Beispiel #1
0
 /// <summary>
 /// Node 分割
 /// </summary>
 /// <param name="maxLevel">限制Node最大的深度</param>
 /// <param name="maxItems">限制Node包含的最大数量</param>
 public void Distribute(int maxLevel, int maxItems)
 {
     if (Level < maxLevel && (SplitAxis != LEAF || ItemCount > maxItems))
     {
         if (SplitAxis == LEAF)
         {
             Split();
         }
         while (Head.Next != Tail)
         {
             OOItem i1 = Head.Next;
             i1.Detach();
             float mid  = i1.Obj.Box.Mid[SplitAxis];
             float size = i1.Obj.Box.Size[SplitAxis];
             if (mid + size < mSplitValue)
             {
                 i1.Attach(Left);
             }
             else if (mid - size > mSplitValue)
             {
                 i1.Attach(Right);
             }
             else
             {
                 OOItem i2 = i1.Split();
                 i1.Attach(Left);
                 i2.Attach(Right);
             }
         }
     }
     Merge(maxItems);
 }
Beispiel #2
0
 public void DeleteItems()
 {
     while (Head.Next != Tail)
     {
         OOItem i1 = Head.Next;
         i1.Detach();
         i1.Unlink();
     }
 }
Beispiel #3
0
        // 在该Node 添加 一个 Object
        public void AddObject(OOModel obj)
        {
            // Node内存储的数据为 OOItem
            OOItem item = new OOItem();

            // OOItem 与 OOObject 进行 相互 关联
            // OOItem 记录 Obj
            item.Obj = obj;
            // OOObject 链表头 添加 OOItem
            item.Link(obj.Head);
            // 将 item 挂到该 Node
            item.Attach(this);
        }
Beispiel #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;
        }
Beispiel #5
0
        public OOModel(MannulDraw drawer)
        {
            Drawer = drawer;
            MeshFilter mf = drawer.gameObject.GetComponent <MeshFilter>();

            Model = new OOMesh(mf);
            Box   = new OOBox(Vector3.one * float.MaxValue, Vector3.one * float.MinValue);
            UpdateTransform();
            Head       = new OOItem();
            Tail       = new OOItem();
            Tail.CNext = null;
            Head.CPrev = null;
            Head.CNext = Tail;
            Tail.CPrev = Head;
            CanOcclude = 1;
            // GeoDebugDrawUtils.DrawAABB(Box.Min, Box.Max);
        }
Beispiel #6
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);
             }
         }
     }
 }
Beispiel #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;
                    }
                }
            }
        }
Beispiel #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
        }