Пример #1
0
 public void AddObject(MannulDraw obj)
 {
     if (!DrawObjects.ContainsKey(obj.GetInstanceID()))
     {
         // object
         OOModel oobj = new OOModel(obj);
         oobj.SetObjectId(obj.GetInstanceID());
         // culler
         Culler.Add(oobj);
         DrawObjects.Add(oobj.GetObjectId(), oobj);
     }
 }
Пример #2
0
 /// <summary>
 /// 将全部落入 distance 的AABB对应的 Item 物体 绘制到缓冲区
 /// </summary>
 /// <param name="distance">刷新距离值</param>
 private void FlushOccluders(float distance)
 {
     while (mMaxQueue.Size > 0 && ((OOModel)mMaxQueue.Peek()).Box.Zmax <= distance)
     {
         OOModel obj = (OOModel)mMaxQueue.Dequeue();
         if (obj.CanOcclude == 0)
         {
             continue;
         }
         DrawOccluder(obj);
     }
 }
Пример #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);
        }
Пример #4
0
        /// <summary>
        /// 根据指定的算法运行
        /// </summary>
        /// <param name="mode">运行模式</param>
        public void FindVisible(int mode)
        {
            mVisible = mTail = null;
            Tree.TouchCounter++;
            switch (mode)
            {
            case OOCE_FRUSTUM_CULLING:
                FrustumCull();
                break;

            case OOCE_OCCLUSION_CULLING:
                OcclusionCull();
                break;

            case OOCE_OCCLUSION_CULLING_OLD:
                OcclusionCullOld();
                break;
            }
        }
Пример #5
0
        public void Refresh(OOModel obj)
        {
            OONode nd;

            nd = obj.Head.CNext.Node;
            Vector3 absV  = (obj.Box.Mid - nd.Box.Mid).Abs();
            Vector3 sizeV = nd.Box.Size - obj.Box.Size;

            if (absV.Less(sizeV))
            {
                return;
            }
            while (nd.Parent != null && absV.AnyGreater(sizeV))
            {
                nd = nd.Parent;
            }
            obj.Detach();
            nd.AddObject(obj);
        }
Пример #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);
             }
         }
     }
 }
Пример #7
0
        /// <summary>
        /// 绘制一个物体到缓冲区
        /// </summary>
        /// <param name="obj">待绘制物体</param>
        private void DrawOccluder(OOModel obj)
        {
            // 获取物体的模型
            OOMesh mdl = obj.Model;
            // 计算 ModelView 矩阵.注意:这里需要相机的变换矩阵的逆矩阵
            // 另一问题:左手系和右手系问题。
            Matrix4x4 modelViewMatrix = mView * obj.ModelWorldMatrix;

            // 变换mesh的顶点到 相机空间 和 裁剪空间
            for (int i = 0; i < mdl.NumVert; i++)
            {
                // Vector3 p = obj.ModelWorldMatrix.MultiplyPoint3x4(mdl.Vertices[i]);
                Vector4 tmp = modelViewMatrix.MultiplyPoint3x4(mdl.Vertices[i]);
                mdl.CameraSpaceVertices[i] = tmp;
                tmp.w = 1;
                mdl.ClipSpaceVertices[i] = mProject * tmp;
            }
            int xmin = 100000;
            int xmax = 0;
            int ymin = 100000;
            int ymax = 0;

            // 遍历所有面
            for (int i = 0; i < mdl.NumFace; i++)
            {
                // 面索引
                int p1 = mdl.Faces[i][0];
                int p2 = mdl.Faces[i][1];
                int p3 = mdl.Faces[i][2];
                // 计算法向量。此处可以优化成:初始化时计算,而后变换一下法向量即可。
                // 构建右手坐标系 逆时针为正方向
                Vector3 a = mdl.CameraSpaceVertices[p2] - mdl.CameraSpaceVertices[p1];
                Vector3 b = mdl.CameraSpaceVertices[p3] - mdl.CameraSpaceVertices[p1];
                Vector3 n = Vector3.Cross(a, b);
                // 背面剔除。可计算相机的朝向,然后与三角面的法线计算即可。
                // 此处实际上计算 Camera 空间 原点到平面的距离是否小于0
                if (Vector3.Dot(n, mdl.CameraSpaceVertices[p1]) < 0)
                {
                    mClip.mClipSpaceVertices[0] = mdl.ClipSpaceVertices[p1];
                    mClip.mClipSpaceVertices[1] = mdl.ClipSpaceVertices[p2];
                    mClip.mClipSpaceVertices[2] = mdl.ClipSpaceVertices[p3];
                    // 裁剪计算
                    int nv = mClip.ClipAndProject(3);
#if TEST_DRAW_ONE
                    DebugUtils.Info("ClipAndProject", string.Format("world1({0}, {1})", mClip.mScreenSpaceVertices[0][0], mClip.mScreenSpaceVertices[0][1]));
                    DebugUtils.Info("ClipAndProject", string.Format("world2({0}, {1})", mClip.mScreenSpaceVertices[1][0], mClip.mScreenSpaceVertices[1][1]));
                    DebugUtils.Info("ClipAndProject", string.Format("world3({0}, {1})", mClip.mScreenSpaceVertices[2][0], mClip.mScreenSpaceVertices[2][1]));
#endif
                    // 裁剪判断
                    if (nv > 2)
                    {
                        // 裁剪后,计算屏幕区域的AABB
                        for (int j = 0; j < nv; j++)
                        {
                            if (mClip.mScreenSpaceVertices[j][0] < xmin)
                            {
                                xmin = mClip.mScreenSpaceVertices[j][0];
                            }
                            else
                            {
                                if (mClip.mScreenSpaceVertices[j][0] > xmax)
                                {
                                    xmax = mClip.mScreenSpaceVertices[j][0];
                                }
                            }
                            if (mClip.mScreenSpaceVertices[j][1] < ymin)
                            {
                                ymin = mClip.mScreenSpaceVertices[j][1];
                            }
                            else if (mClip.mScreenSpaceVertices[j][1] > ymax)
                            {
                                ymax = mClip.mScreenSpaceVertices[j][1];
                            }
                        }
                        // 绘制多边形到缓冲
                        Map.DrawPolygon(mClip.mScreenSpaceVertices, nv);
                    }
                }
            }
            // 设置该区域内有被覆盖
            Map.SetDirtyRectangle(xmin, ymin, xmax, ymax);
        }
Пример #8
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;
                    }
                }
            }
        }
Пример #9
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
        }
Пример #10
0
 /// <summary>
 /// 重置下一个可见物体为当前物体
 /// </summary>
 /// <returns></returns>
 public int GetNextObject()
 {
     mTemp = mTemp.Next;
     return(mTemp != null ? 1 : 0);
 }
Пример #11
0
 /// <summary>
 /// 获得当前第一个可见物体
 /// </summary>
 /// <returns></returns>
 public int GetFirstObject()
 {
     mTemp = mVisible;
     return(mTemp != null ? 1 : 0);
 }
Пример #12
0
 /// <summary>
 /// 删除KDTree中指定的Object
 /// </summary>
 /// <param name="obj">待删除物体</param>
 public void Remove(OOModel obj)
 {
     Tree.Delete(obj);
 }
Пример #13
0
 /// <summary>
 /// 添加物体到KDTree
 /// </summary>
 /// <param name="obj">待添加物体</param>
 public void Add(OOModel obj)
 {
     Tree.Add(obj);
 }
Пример #14
0
 public void Delete(OOModel obj)
 {
     obj.Detach();
 }
Пример #15
0
 public void Add(OOModel obj)
 {
     Root.AddObject(obj);
 }