/// <summary> /// 截头体剔除算法入口 /// </summary> private void FrustumCull() { mMinQueue.Clear(); PushBox(Tree.Root, ref Tree.Root.Box); while (mMinQueue.Size > 0) { OONode nd = (OONode)mMinQueue.Dequeue(); if (mFrustum.Test(ref nd.Box) > 0) { nd.Distribute(mMaxLevel, mMaxItems); OOItem itm = nd.Head.Next; while (itm != nd.Tail) { OOModel obj = itm.Obj; if (obj.TouchId != Tree.TouchCounter) { obj.TouchId = Tree.TouchCounter; if (mFrustum.Test(ref obj.Box) > 0) { obj.Next = null; if (mVisible == null) { mVisible = mTail = obj; } else { mTail.Next = obj; mTail = obj; } } } itm = itm.Next; } if (nd.SplitAxis != OONode.LEAF) { PushBox(nd.Left, ref nd.Left.Box); PushBox(nd.Right, ref nd.Right.Box); } } } }
/// <summary> /// 老旧的遮挡剔除算法入口 /// </summary> private void OcclusionCullOld() { Stat[0] = Stat[1] = 0; Map.Clear(); mMinQueue.Clear(); mMaxQueue.Clear(); PushBox(Tree.Root, ref Tree.Root.Box); while (mMinQueue.Size > 0) { OONode nd = (OONode)mMinQueue.Dequeue(); nd.Distribute(mMaxLevel, mMaxItems); MinMax(ref nd.Box, ref nd.Box.Zmin, ref nd.Box.Zmax); if (nd.SplitAxis != OONode.LEAF) { if (nd.Visible != 0 || IsVisible(1, ref nd.Box, nd.Box.Zmin) != 0) { nd.Visible = 1; PushBox(nd.Left, ref nd.Left.Box); PushBox(nd.Right, ref nd.Right.Box); } else { nd.Visible = 0; if (nd.Parent != null) { nd.Parent.Visible = 0; } } } else { if (IsVisible(1, ref nd.Box, nd.Box.Zmin) != 0) { OOItem itm = nd.Head.Next; while (itm != nd.Tail) { if (itm.Obj.TouchId != Tree.TouchCounter) { itm.Obj.TouchId = Tree.TouchCounter; OOModel obj = itm.Obj; float dis = -Vector3.Dot(obj.Box.Mid, mLook); float d = Vector3.Dot(mAbsLook, obj.Box.Size); obj.Box.Zmin = dis - d; obj.Box.Zmax = dis + d; if (IsVisible(0, ref obj.Box, 0) != 0) { mMaxQueue.Enqueue(obj.Box.Zmax, obj, obj.Box.Zmax); obj.Next = null; if (mVisible == null) { mVisible = mTail = obj; } else { mTail.Next = obj; mTail = obj; } } } itm = itm.Next; } } if (nd.Parent != null) { nd.Parent.Visible = 0; } } } }
/// <summary> /// 遮挡剔除 算法入口 /// </summary> private void OcclusionCull() { Stat[0] = Stat[1] = 0; Map.Clear(); mMinQueue.Clear(); mMaxQueue.Clear(); PushBox2(Tree.Root, ref Tree.Root.Box); // 按 负无穷范数(最小值) 作为优先权中 遍历 while (mMinQueue.Size > 0) { OONode nd = (OONode)mMinQueue.Dequeue(); nd.Distribute(mMaxLevel, mMaxItems); MinMax(ref nd.Box, ref nd.Box.Zmin, ref nd.Box.Zmax); if (nd.SplitAxis != OONode.LEAF) // 非叶节点 { // 该节点存在两个子节点 // 如果 该节点 Visible 为可见 ,则不需要进一步计算 // 如果 该结点 Visible 为不可见,则进一步计算判断可见性 // KDTree的Node不是每次重新分配,带有一定的缓存功能。所以, Visible 可以加速计算 // 存在一个问题:如果所有的物体都分到了一个Node中,可能会不停的划分到最大深度。后期需要优化 if ((nd.Visible != 0) || IsVisible(1, ref nd.Box, nd.Box.Zmin) != 0) { // 标记为可见 nd.Visible = 1; // 父节点可见,接下来判断左右孩子结点的可见性 PushBox2(nd.Left, ref nd.Left.Box); PushBox2(nd.Right, ref nd.Right.Box); } else { // 标记为不可见 nd.Visible = 0; if (nd.Parent != null) { nd.Parent.Visible = 0; } } } else // 叶节点 { // 叶节点的Box测试 if (IsVisible(1, ref nd.Box, nd.Box.Zmin) != 0) { OOItem itm = nd.Head.Next; // 保存需要绘制的物体,以 Zmax 为优先级排序 while (itm != nd.Tail) { if (itm.Obj.TouchId != Tree.TouchCounter) { itm.Obj.TouchId = Tree.TouchCounter; OOModel obj = itm.Obj; MinMax(ref obj.Box, ref obj.Box.Zmin, ref obj.Box.Zmax); // 查询物体的Box是否可见 if (IsVisible(0, ref obj.Box, 0) != 0) { // 如果一个物体的Box可见,则为待绘制的物体 mMaxQueue.Enqueue(obj.Box.Zmax, obj, obj.Box.Zmax); obj.Next = null; if (mVisible == null) { mVisible = mTail = obj; } else { mTail.Next = obj; mTail = obj; } } } itm = itm.Next; } } if (nd.Parent != null) { nd.Parent.Visible = 0; } } } #if TEST_DRAW VisualKDTree(Tree.Root); if (mMaxQueue.Size > 0) { DebugUtils.Info("OcclusionCull", "Before Max Left: ", mMaxQueue.Size); FlushOccluders(float.MaxValue); DebugUtils.Info("OcclusionCull", "After Max Left: ", mMaxQueue.Size); } Map.DrawScreenShot(); #endif }