Esempio n. 1
0
        /// <summary>
        /// 此 Node 分割
        /// </summary>
        private void Split()
        {
            // 左右孩子创建
            Left  = new OONode();
            Right = new OONode();
            // 记录孩子Node的深度值
            Right.Level = Left.Level = Level + 1;
            // 记录孩子Node的父节点
            Left.Parent = Right.Parent = this;
            // 获取分割轴
            SplitAxis = GetSplitAxis(ref Box.Size);
            // 获取分割轴的分割值
            mSplitValue = Box.Mid[SplitAxis];
            // 计算孩子结点的包围盒 size.
            Left.Box = Right.Box = Box;
            float half = 0.5f * Box.Size[SplitAxis];

            // 孩子包围盒的此寸为父节点的一半
            Left.Box.Size[SplitAxis] = Right.Box.Size[SplitAxis] = half;
            // 在分割轴上, 加减 size,得到新的 中心点
            Left.Box.Mid[SplitAxis]  = Box.Mid[SplitAxis] - half;
            Right.Box.Mid[SplitAxis] = Box.Mid[SplitAxis] + half;
            Right.Box.ToMinMax();
            Left.Box.ToMinMax();
        }
Esempio n. 2
0
 /// <summary>
 /// 删除指定结点
 /// </summary>
 /// <param name="nd">待删除结点</param>
 private void DeleteNodes(OONode nd)
 {
     if (nd == null)
     {
         return;
     }
     nd.DeleteItems();
     DeleteNodes(nd.Left);
     DeleteNodes(nd.Right);
 }
Esempio n. 3
0
 private void VisualKDTree(OONode node)
 {
     node.DrawAABB();
     if (node.Left != null)
     {
         VisualKDTree(node.Left);
     }
     if (node.Right != null)
     {
         VisualKDTree(node.Right);
     }
 }
Esempio n. 4
0
        public OONode()
        {
            Head      = new OOItem();
            Tail      = new OOItem();
            Box       = new OOBox(Vector3.one * float.MaxValue, Vector3.one * float.MinValue);
            SplitAxis = LEAF;
            Visible   = 0;
            ItemCount = 0;

            Left      = null;
            Right     = null;
            Parent    = null;
            Head.Prev = null;
            Head.Next = Tail;
            Tail.Next = null;
            Tail.Prev = Head;
        }
Esempio n. 5
0
 /// <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);
             }
         }
     }
 }
Esempio n. 6
0
        /// <summary>
        /// 合并孩子节点
        /// </summary>
        /// <param name="maxItems"></param>
        private void Merge(int maxItems)
        {
            if (SplitAxis == LEAF)
            {
                return;
            }
            if (Left.SplitAxis != LEAF || Right.SplitAxis != LEAF)
            {
                return;
            }
            if (Left.ItemCount + Right.ItemCount >= maxItems)
            {
                return;
            }
            DoubleCounter++;
            OOItem i1;

            while (Left.Head.Next != Left.Tail)
            {
                i1 = Left.Head.Next;
                i1.Detach();
                i1.Attach(this);
                i1.Obj.DoubleId = DoubleCounter;
            }
            while (Right.Head.Next != Right.Tail)
            {
                i1 = Right.Head.Next;
                i1.Detach();
                if (i1.Obj.DoubleId != DoubleCounter)
                {
                    i1.Attach(this);
                }
                else
                {
                    i1.Unlink();
                }
            }
            Left      = Right = null;
            SplitAxis = LEAF;
        }
Esempio n. 7
0
        /// <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;
                    }
                }
            }
        }
Esempio n. 8
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
        }
Esempio n. 9
0
 public OOKDTree()
 {
     Root       = new OONode();
     Root.Level = 0;
 }