Ejemplo n.º 1
0
        /// <summary>
        /// 相机位置到物体Box的最大最小值距离( 无穷范数 )
        /// </summary>
        /// <param name="box">AABB数据</param>
        /// <param name="min">AABB距相机距离最近值</param>
        /// <param name="max">AABB距相机距离最远值</param>
        private void MinMax(ref OOBox box, ref float min, ref float max)
        {
            min = 0;
            max = float.MinValue;
            // 相机到Box中心的向量三维度的距离表示
            Vector3 diff = (mPosition - box.Mid).Abs();

            // 三维度距离与Box此寸比较,计算最大和最小距离值
            for (int i = 0; i < 3; i++)
            {
                float d1 = diff[i] - box.Size[i];
                if (d1 > min)
                {
                    min = d1;
                }
                float d2 = diff[i] + box.Size[i];
                if (d2 > max)
                {
                    max = d2;
                }
            }
            // 不能小于0, 比如在内部
            if (min < 0)
            {
                min = 0;
            }
        }
Ejemplo n.º 2
0
 /// <summary>
 /// 将物体保存到 小根堆
 /// </summary>
 /// <param name="obj">待添加物体</param>
 /// <param name="box">添加物体的Box的大小</param>
 private void PushBox2(object obj, ref OOBox box)
 {
     // 最近和最远平面距离计算
     MinMax(ref box, ref box.Zmin, ref box.Zmax);
     // 以最近距离为权重值,添加到优先队列
     mMinQueue.Enqueue(box.Zmin, obj, box.Zmin);
 }
Ejemplo n.º 3
0
        /// <summary>
        /// 判断 Box 的可见性
        /// </summary>
        /// <param name="flush">Node结点的Box 为 1, 需要将缓存的遮挡物先绘制再查询; Node中的Item为0.</param>
        /// <param name="box">AABB数据</param>
        /// <param name="dist">最近距离( 负无穷范数 )</param>
        /// <returns></returns>
        private int IsVisible(int flush, ref OOBox box, float dist)
        {
            // Box放大一点点
            OOBox q = box;

            q.Size = box.Size + Vector3.one * mSafeDistance;
            // 截头体测试
            int visible = mFrustum.Test(ref q);

            if (visible == 0)
            {
                return(0);
            }
            // 相机在Box内部
            if (visible == 2)
            {
                return(1);
            }
            if (flush != 0)
            {
                // 绘制Box最远距离 小于 dist的物体
                FlushOccluders(dist);
            }
            return(QueryBox(ref box));
        }
Ejemplo n.º 4
0
        public int Test(ref OOBox b)
        {
            int     i;
            float   m, n;
            Vector3 diff = (b.Mid - mPosition).Abs();

            // 相机位置在 b 内部, 返回2
            if (diff.Less(b.Size))
            {
                return(2);
            }
            // 检测Box与6个平面的相交
            for (i = 0; i < 6; i++)
            {
                // box 中心点 到 面的有符号距离计算
                m = Vector3.Dot(b.Mid, mPlanes[i]) + mPlanes[i][3];
                // b 的 size 在 面法向 最大投影距离.必定为一个正值
                Vector3 plane = mPlanes[i].Abs();
                n = Vector3.Dot(b.Size, plane);
                // 如果 存在一个面,使得 m 值大于 最大投影值,可以肯定 box 不相较于 截头体
                if (m > n)
                {
                    return(0);
                }
            }
            // 这种情况存在: box 与 截头体相交; box在截头体内部.
            // 这两种情况,都需要保留 box 对应的 物体
            return(1);
        }
Ejemplo n.º 5
0
        public OOMesh(MeshFilter filter)
        {
            MeshFilter = filter;
            MeshFilter.sharedMesh.RecalculateBounds();

#if TEST_DRAW_ONE
            Vector3 world1 = new Vector3(1.14f, -0.7f, -5.94f);
            Vector3 world2 = new Vector3(1.14f, 1.96f, -7.81f);
            Vector3 world3 = new Vector3(7.28f, -0.7f, -5.94f);
            Vertices = new Vector3[]
            {
                filter.transform.worldToLocalMatrix.MultiplyPoint3x4(world1),
                filter.transform.worldToLocalMatrix.MultiplyPoint3x4(world2),
                filter.transform.worldToLocalMatrix.MultiplyPoint3x4(world3)
            };
            world1 = Camera.main.WorldToScreenPoint(world1) * 32;
            world2 = Camera.main.WorldToScreenPoint(world2) * 32;
            world3 = Camera.main.WorldToScreenPoint(world3) * 32;
            DebugUtils.Info("OOModel", string.Format("world1({0}, {1})", world1.x, world1.y));
            DebugUtils.Info("OOModel", string.Format("world2({0}, {1})", world2.x, world2.y));
            DebugUtils.Info("OOModel", string.Format("world3({0}, {1})", world3.x, world3.y));
            Faces = new Vector3i[] { new Vector3i(0, 1, 2) };
#else
            Vertices = MeshFilter.sharedMesh.vertices;
            Faces    = ArrayToList(MeshFilter.sharedMesh.triangles);
#endif
            NumVert             = Vertices.Length;
            NumFace             = Faces.Length;
            CameraSpaceVertices = new Vector3[NumVert];
            ClipSpaceVertices   = new Vector4[NumVert];
            Bounds b = MeshFilter.sharedMesh.bounds;
            Box = new OOBox(b.min, b.max);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// 按照相机朝向计算距离值
        /// </summary>
        /// <param name="obj">待添加物体</param>
        /// <param name="box">待添加物体的Box数据</param>
        private void PushBox(object obj, ref OOBox box)
        {
            float dis, d;

            dis      = -Vector3.Dot(box.Mid, mLook);
            d        = Vector3.Dot(mAbsLook, box.Size);
            box.Zmin = dis - d;
            box.Zmax = dis + d;
            mMinQueue.Enqueue(box.Zmin, obj, box.Zmin);
        }
Ejemplo n.º 7
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);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// 根据相机位置,获得所在区域,然后获取Box可见面构造的轮廓
        ///                    max
        ///         6 --------- 7
        ///       / |         / |
        ///     2 --------- 3   |
        ///     |   |       |   |
        ///     |   |       |   |
        ///     |   4 --------- 5
        ///     | /         | /
        ///     0 --------- 1
        ///    min
        /// </summary>
        /// <param name="box">查询Box的可见性</param>
        /// <returns></returns>
        private int QueryBox(ref OOBox box)
        {
            Vector3 min = box.Min;
            Vector3 max = box.Max;

            // 8顶点索引和数据对应
            Vector4[] vxt = new Vector4[8];
            vxt[0] = new Vector4(min[0], min[1], min[2], 1);
            vxt[1] = new Vector4(max[0], min[1], min[2], 1);
            vxt[2] = new Vector4(min[0], max[1], min[2], 1);
            vxt[3] = new Vector4(max[0], max[1], min[2], 1);
            vxt[4] = new Vector4(min[0], min[1], max[2], 1);
            vxt[5] = new Vector4(max[0], min[1], max[2], 1);
            vxt[6] = new Vector4(min[0], max[1], max[2], 1);
            vxt[7] = new Vector4(max[0], max[1], max[2], 1);

            // 区域码计算
            int cd = 0;

            if (mPosition[0] < min[0])
            {
                // 左面之左
                cd |= 1;
            }
            if (mPosition[0] > max[0])
            {
                // 右面之右
                cd |= 2;
            }
            if (mPosition[1] < min[1])
            {
                // 下面之下
                cd |= 4;
            }
            if (mPosition[1] > max[1])
            {
                // 上面之上
                cd |= 8;
            }
            if (mPosition[2] < min[2])
            {
                // 进面之近
                cd |= 16;
            }
            if (mPosition[2] > max[2])
            {
                // 远面之远
                cd |= 32;
            }

            // 到这一步,已经过了截头体测试.物体均在相机视角内
            // 索引相机能见到的顶点
            int[] stt = STAB[cd];
            // 数组0索引表示能见到的顶点数量,后面的数组索引记录Box的顶点索引
            int vp = stt[0];

#if TEST_DRAW
            List <Vector3> polygon     = new List <Vector3>();
            List <Vector3> clipPolygon = new List <Vector3>();
#endif
            // 遍历顶点
            for (int i = 0; i < vp; i++)
            {
                // 获得顶点索引
                int j = stt[i + 1];
                // 将顶点变换到裁剪空间
                mClip.mClipSpaceVertices[i] = mPV * vxt[j];
#if TEST_DRAW
                polygon.Add(vxt[j]);
                // 裁剪前
                clipPolygon.Add(mClip.mClipSpaceVertices[i] * (1 / mClip.mClipSpaceVertices[i][3]));
#endif
            }

#if TEST_DRAW
            // 绘制可见多边形
            GeoDebugDrawUtils.DrawPolygon(polygon, Color.red);
            GeoDebugDrawUtils.DrawPolygon(clipPolygon, Color.red);
            DrawNDCBox();
#endif
            // 对Box的轮廓进行裁剪计算,返回裁剪后的顶点数
            vp = mClip.ClipAndProject(vp);
#if TEST_DRAW
            clipPolygon.Clear();
            // z 方向上 偏移 0.01
            Vector4 offset = new Vector4(0, 0, 0.01f, 0);
            for (int i = 0; i < vp; ++i)
            {
                clipPolygon.Add(offset + mClip.mClipSpaceVertices[i]);
            }
            // 裁剪后
            GeoDebugDrawUtils.DrawPolygon(clipPolygon, Color.blue);
#endif
            if (vp < 3)
            {
                return(0);
            }
            int res = Map.QueryPolygon(mClip.mScreenSpaceVertices, vp);
            return(res);
        }