Example #1
0
 public void reset()
 {
     voxelizationTime  = UNDEFINED;
     regionGenTime     = UNDEFINED;
     contourGenTime    = UNDEFINED;
     polyGenTime       = UNDEFINED;
     finalMeshGenTime  = UNDEFINED;
     mSolidHeightfield = null;
     mOpenHeightfield  = null;
     mContours         = null;
     mPolyMesh         = null;
 }
Example #2
0
 public void setPolyMesh(PolyMeshField mesh)
 {
     mPolyMesh = mesh;
 }
        }// func

        private static void getPolyMergeInfo(int polyAPointer, int polyBPointer,
                                             int[] polys, int[] verts,
                                             int maxVertsPerPoly, out int[] outResult)
        {
            outResult = new int[3];

            outResult[0] = -1;
            outResult[1] = -1;
            outResult[2] = -1;

            int vertCountA = PolyMeshField.getPolyVertCount(polyAPointer, polys, maxVertsPerPoly);
            int vertCountB = PolyMeshField.getPolyVertCount(polyBPointer, polys, maxVertsPerPoly);

            //减2 是因为合并了一条边,少了两个顶点
            if (vertCountA + vertCountB - 2 > maxVertsPerPoly)
            {
                return;
            }

            for (int iPolyVertA = 0; iPolyVertA < vertCountA; ++iPolyVertA)
            {
                int iVertA     = polys[polyAPointer + iPolyVertA];
                int iVertANext = polys[polyAPointer + getNextIndex(iPolyVertA, vertCountA)];

                for (int iPolyVertB = 0; iPolyVertB < vertCountB; ++iPolyVertB)
                {
                    int iVertB     = polys[polyBPointer + iPolyVertB];
                    int iVertBNext = polys[polyBPointer + getNextIndex(iPolyVertB, vertCountB)];

                    /*
                     *    同一种顶点顺序,两个点是重合的话, 就是共享边了。
                     *    A/B+1
                     *     \
                     *      \
                     *      A+1/B
                     */

                    if (iVertA == iVertBNext &&
                        iVertANext == iVertB)
                    {
                        outResult[1] = iPolyVertA;
                        outResult[2] = iPolyVertB;
                    }
                } //iPolyB
            }     // iPolyA


            if (-1 == outResult[1])
            {
                return;
            }

            //对顺时针包含的多边形有效
            int pSharedVertMinus;
            int pSharedVert;
            int pSharedVertPlus;

            //为什么是3呢?是因为xyz为一组
            //A-1
            pSharedVertMinus = polys[polyAPointer + getPreviousIndex(outResult[1], vertCountA)] * 3;
            //A
            pSharedVert = polys[polyAPointer + outResult[1]] * 3;
            //????TODO,用B的,还是B+2了卧槽。。。
            //我艹,B+2 对应的就是图上的A+1,这个并不是真是意义是A点的下一个点
            pSharedVertPlus = polys[polyBPointer + ((outResult[2] + 2) % vertCountB)] * 3;

            if (!isLeft(verts[pSharedVert], verts[pSharedVert + 2],
                        verts[pSharedVertMinus], verts[pSharedVertMinus + 2],
                        verts[pSharedVertPlus], verts[pSharedVertPlus + 2]
                        ))
            {
                return;
            }

            pSharedVertMinus = polys[polyBPointer + getPreviousIndex(outResult[2], vertCountB)] * 3;
            pSharedVert      = polys[polyBPointer + outResult[2]] * 3;
            pSharedVertPlus  = polys[polyAPointer + ((outResult[1] + 2) % vertCountA)] * 3;

            if (!isLeft(verts[pSharedVert], verts[pSharedVert + 2],
                        verts[pSharedVertMinus], verts[pSharedVertMinus + 2],
                        verts[pSharedVertPlus], verts[pSharedVertPlus + 2]))
            {
                return;
            }

            //共享边
            pSharedVertMinus = polys[polyAPointer + outResult[1]] * 3;
            pSharedVert      = polys[polyAPointer + getNextIndex(outResult[1], vertCountA)] * 3;

            int deltaX = verts[pSharedVertMinus + 0] - verts[pSharedVert + 0];
            int deltaZ = verts[pSharedVertMinus + 2] - verts[pSharedVert + 2];

            outResult[0] = deltaX * deltaX + deltaZ * deltaZ;
        }
        } // build

        private static void buildAdjacencyData(PolyMeshField mesh)
        {
            int vertCount    = mesh.verts.Length / 3;
            int polyCount    = mesh.polyRegions.Length;
            int maxEdgeCount = polyCount * mesh.maxVertsPerPoly();  // 多边形的个数乘以顶点数?

            int[] edges     = new int[maxEdgeCount * 6];
            int   edgeCount = 0;

            int[] startEdge = new int[vertCount];
            for (int i = 0; i < startEdge.Length; ++i)
            {
                startEdge[i] = PolyMeshField.NULL_INDEX;
            }

            //数组链表
            int[] nextEdge = new int[maxEdgeCount];
            for (int iPoly = 0; iPoly < polyCount; ++iPoly)
            {
                int pPoly = iPoly * mesh.maxVertsPerPoly() * 2; //两组maxVertPerPoly为步长
                for (int vertOffset = 0; vertOffset < mesh.maxVertsPerPoly(); ++vertOffset)
                {
                    int iVert = mesh.polys[pPoly + vertOffset];  //第一组maxVertsPerPoly的数据
                    if (PolyMeshField.NULL_INDEX == iVert)
                    {
                        break;
                    }

                    //如果 maxVertsPerPoly = 6 ,那当vertOffset = 5 的时候会发生什么?
                    //那iNextVert就会回到起点
                    int iNextVert;
                    if (vertOffset + 1 >= mesh.maxVertsPerPoly() ||
                        mesh.polys[pPoly + vertOffset + 1] == PolyMeshField.NULL_INDEX)
                    {
                        iNextVert = mesh.polys[pPoly];
                    }
                    else
                    {
                        iNextVert = mesh.polys[pPoly + vertOffset + 1];
                    }

                    if (iVert < iNextVert)
                    {
                        int edgeBaseIdx = edgeCount * 6;
                        //一条边的两个端点
                        edges[edgeBaseIdx]     = iVert;
                        edges[edgeBaseIdx + 1] = iNextVert;

                        //这条边在多边形里面的信息
                        edges[edgeBaseIdx + 2] = iPoly;
                        edges[edgeBaseIdx + 3] = vertOffset;

                        //默认是边界边
                        edges[edgeBaseIdx + 4] = PolyMeshField.NULL_INDEX;
                        edges[edgeBaseIdx + 5] = PolyMeshField.NULL_INDEX;


                        //倒插链表? iVert顶点 -> edgeCount 边 -> 然后edgeCount 就是链表尾了
                        //TODO  源码这里也是这样,不知道为毛
                        nextEdge[edgeCount] = startEdge[iVert];  //???这个东西不是NULL_INDEX么?
                        startEdge[iVert]    = edgeCount;

                        edgeCount++;
                    }
                } // for vertOffset
            }     // for Poly

            for (int iPoly = 0; iPoly < polyCount; ++iPoly)
            {
                int pPoly = iPoly * mesh.maxVertsPerPoly() * 2;
                for (int vertOffset = 0; vertOffset < mesh.maxVertsPerPoly(); ++vertOffset)
                {
                    int iVert = mesh.polys[pPoly + vertOffset];
                    if (PolyMeshField.NULL_INDEX == iVert)
                    {
                        break;
                    }

                    int iNextVert;
                    if (vertOffset + 1 >= mesh.maxVertsPerPoly() ||
                        mesh.polys[pPoly + vertOffset] == PolyMeshField.NULL_INDEX)
                    {
                        iNextVert = mesh.polys[pPoly];
                    }
                    else
                    {
                        iNextVert = mesh.polys[pPoly + vertOffset];
                    }

                    //这里是反向查找共享边的信息
                    if (iVert > iNextVert)
                    {
                        for (int edgeIndex = startEdge[iNextVert]; edgeIndex != PolyMeshField.NULL_INDEX; edgeIndex = nextEdge[edgeIndex])
                        {
                            if (iVert == edges[edgeIndex * 6 + 1])
                            {
                                edges[edgeIndex * 6 + 4] = iPoly;
                                edges[edgeIndex * 6 + 5] = vertOffset;
                                break;
                            }
                        } // for
                    }     //if ivert > iNextVert
                }         // for vertOffset
            }             // for Poly

            for (int pEdge = 0; pEdge < edgeCount; pEdge += 6)
            {
                //是否共享边 ?
                if (edges[pEdge + 4] != PolyMeshField.NULL_INDEX)
                {
                    int pPolyA = edges[pEdge + 2] * mesh.maxVertsPerPoly() * 2;
                    int pPolyB = edges[pEdge + 4] * mesh.maxVertsPerPoly() * 2;
                    //参考 poly和edges数组的定义。描述的就是polyA的哪些边与哪个poly共享
                    mesh.polys[pPolyA + mesh.maxVertsPerPoly() + edges[pEdge + 3]] = edges[pEdge + 4];
                    mesh.polys[pPolyB + mesh.maxVertsPerPoly() + edges[pEdge + 5]] = edges[pEdge + 2];
                }
            }
        }// func
        public PolyMeshField build(ContourSet contours)
        {
            if (null == contours ||
                0 == contours.size())
            {
                Logger.LogError("[PolyMeshFieldBuild][build]Param Error");
                return(null);
            }

            PolyMeshField result = new PolyMeshField(contours.boundsMin(),
                                                     contours.boundsMax(),
                                                     contours.cellSize(),
                                                     contours.cellHeight(),
                                                     mMaxVertsPerPoly);

            int sourceVertCount     = 0;
            int maxPossiblePolygons = 0;
            int maxVertsPerContour  = 0;

            for (int contourIndex = 0; contourIndex < contours.size(); ++contourIndex)
            {
                int count = contours.get(contourIndex).vertCount;
                sourceVertCount += count;
                //过 n 边形的一个顶点,能把n边形最多分成 n - 2 三角形
                maxPossiblePolygons += count - 2;
                maxVertsPerContour   = Math.Max(maxVertsPerContour, count);
            }

            if (sourceVertCount - 1 > DEFLAG)
            {
                Logger.LogError("[PolyMeshFieldBuilder][build]sourceVertCount out of Range|{0}|{1}", DEFLAG, sourceVertCount);
                return(null);
            }

            int[] globalVerts     = new int[sourceVertCount * 3]; //存的是索引,存的是整个轮廓的
            int   globalVertCount = 0;

            int[] globalPolys = new int[maxPossiblePolygons * mMaxVertsPerPoly];  //存的也是索引
            for (int i = 0; i < globalPolys.Length; ++i)
            {
                globalPolys[i] = PolyMeshField.NULL_INDEX;
            }

            int[] globalRegions   = new int[maxPossiblePolygons];
            int   globalPolyCount = 0;

            int[] contourToGlobalIndicesMap   = new int[maxVertsPerContour]; //存的也是索引
            Dictionary <int, int> vertIndices = new Dictionary <int, int>();

            List <int> workingIndices   = new List <int>(maxVertsPerContour);
            List <int> workingTriangles = new List <int>(maxVertsPerContour);

            //TODO 为什么要+1?
            int[] workingPolys     = new int[(maxVertsPerContour + 1) * mMaxVertsPerPoly];
            int   workingPolyCount = 0;

            int[] mergeInfo  = new int[3];
            int[] mergedPoly = new int[mMaxVertsPerPoly];

            for (int contourIndex = 0; contourIndex < contours.size(); ++contourIndex)
            {
                Contour contour = contours.get(contourIndex);
                //4个数据一组,(x,y,z,regionID),最少需要三个顶点
                if (contour.verts.Length < 3 * 4)
                {
                    Logger.LogError("[PolyMeshFieldBuilder][build]Bad Contour|{0}", contour.regionID);
                    continue;
                }

                //初始情况下,顶点索引对应的就是对应的顶点

                /*
                 *   Indices : 0 1 2 3 4 5 6  ....
                 *             0 1 2 3 4 5 6  ....
                 */
                workingIndices.Clear();
                for (int i = 0; i < contour.vertCount; ++i)  //这个顶点数是按四个一组的
                {
                    workingIndices.Add(i);
                } // for contour.vert

                //三角剖分
                int triangleCount = triangulate(contour.verts, ref workingIndices, ref workingTriangles);
                if (triangleCount <= 0)
                {
                    Logger.LogError("[PolyMeshField][build]Triangulate Contour|{0}", contour.regionID);
                    continue;
                }


                for (int iContourVert = 0; iContourVert < contour.vertCount; ++iContourVert)
                {
                    int pContourVert = iContourVert * 4;
                    int vertHash     = getHashCode(contour.verts[pContourVert],
                                                   contour.verts[pContourVert + 1],
                                                   contour.verts[pContourVert + 2]);

                    //vertIndices 里面储存的是根据顶点xyz hash出来的key,对应的在全局顶点表中的索引
                    //全局顶点表 以 xyz 3个为一组,储存轮廓的顶点
                    int iGlobalVert = 0;
                    if (!vertIndices.TryGetValue(vertHash, out iGlobalVert))
                    {
                        iGlobalVert = globalVertCount;
                        globalVertCount++;
                        vertIndices.Add(vertHash, iGlobalVert);

                        int newVertsBase = iGlobalVert * 3;
                        globalVerts[newVertsBase]     = contour.verts[pContourVert];
                        globalVerts[newVertsBase + 1] = contour.verts[pContourVert + 1];
                        globalVerts[newVertsBase + 2] = contour.verts[pContourVert + 2];
                    }

                    //这个东东是临时用的,就是记录 轮廓中某个顶点的索引,对应的是在全局顶点表中索引
                    //Contour Vertex index  -> global vertex index
                    contourToGlobalIndicesMap[iContourVert] = iGlobalVert;
                } // for iContourVert


                for (int i = 0; i < workingPolys.Length; ++i)
                {
                    workingPolys[i] = PolyMeshField.NULL_INDEX;
                } // for workingPolys

                //只有这个阶段是三角形
                workingPolyCount = 0;
                for (int i = 0; i < triangleCount; ++i)
                {
                    /*
                     *  workingTraingles 储存的是上一步三角剖分的三角形的顶点索引
                     *                     ||
                     *                      V
                     *  contourToGlobalIndicesMap 储存的是轮廓顶点索引,对应在全局顶点表的索引关系
                     *                     ||
                     *                     V
                     *  workingPolys 中 储存的则是全局的顶点索引
                     *
                     *
                     */


                    int polyIdxBase     = workingPolyCount * mMaxVertsPerPoly;
                    int triangleIdxBase = i * 3;
                    workingPolys[polyIdxBase] =
                        contourToGlobalIndicesMap[workingTriangles[triangleIdxBase]];
                    workingPolys[polyIdxBase + 1] =
                        contourToGlobalIndicesMap[workingTriangles[triangleIdxBase + 1]];
                    workingPolys[polyIdxBase + 2] =
                        contourToGlobalIndicesMap[workingTriangles[triangleIdxBase] + 2];

                    workingPolyCount++;
                }  //triangleCount

                //合并三角形
                if (mMaxVertsPerPoly > 3)
                {
                    while (true)
                    {
                        int longestMergeEdge = -1;
                        int pBestPolyA       = -1;
                        int iPolyAVert       = -1;
                        int pBestPolyB       = -1;
                        int iPolyBVert       = -1;


                        for (int iPolyA = 0; iPolyA < workingPolyCount - 1; ++iPolyA)
                        {
                            for (int iPolyB = iPolyA + 1; iPolyB < workingPolyCount; ++iPolyB)
                            {
                                //因为一个多边形最多有mMaxVertsPerPoly的点,所以
                                //多边形的真正起点为就是用多边形的索引乘以顶点数
                                //Can polyB merge with polyA?
                                getPolyMergeInfo(iPolyA * mMaxVertsPerPoly,
                                                 iPolyB * mMaxVertsPerPoly,
                                                 workingPolys,
                                                 globalVerts,
                                                 result.maxVertsPerPoly(),
                                                 out mergeInfo);

                                if (mergeInfo[0] > longestMergeEdge)
                                {
                                    longestMergeEdge = mergeInfo[0];
                                    pBestPolyA       = iPolyA * mMaxVertsPerPoly;
                                    iPolyAVert       = mergeInfo[1];
                                    pBestPolyB       = iPolyB * mMaxVertsPerPoly;
                                    iPolyBVert       = mergeInfo[2];
                                }
                            } // for iPolyB
                        }     // for iPolyA

                        if (longestMergeEdge <= 0)
                        {
                            break;
                        }

                        for (int i = 0; i < mergedPoly.Length; ++i)
                        {
                            mergedPoly[i] = PolyMeshField.NULL_INDEX;
                        }

                        int vertCountA = PolyMeshField.getPolyVertCount(pBestPolyA, workingPolys, result.maxVertsPerPoly());
                        int vertCountB = PolyMeshField.getPolyVertCount(pBestPolyB, workingPolys, result.maxVertsPerPoly());
                        int position   = 0;


                        for (int i = 0; i < vertCountA - 1; ++i)
                        {
                            //pBestPolyA 为多边形对应的基索引
                            //iPolyAVert 为共享的一个端点
                            //+1 指的是共享点下一个顶点开始
                            int polyIdx = pBestPolyA + ((iPolyAVert + 1 + i) % vertCountA);
                            mergedPoly[position++] = workingPolys[polyIdx];
                        } // for vertCountA

                        for (int i = 0; i < vertCountB - 1; ++i)
                        {
                            int polyIdx = pBestPolyB + ((iPolyBVert + 1 + i) % vertCountB);
                            mergedPoly[position++] = workingPolys[polyIdx];
                        }

                        //将合并之后的顶点拷到A指定的多边形
                        Array.Copy(mergedPoly, 0, workingPolys, pBestPolyA, mMaxVertsPerPoly);
                        //将多边形B删除
                        Array.Copy(workingPolys, pBestPolyB + mMaxVertsPerPoly, workingPolys, pBestPolyB, workingPolys.Length - pBestPolyB - mMaxVertsPerPoly);

                        workingPolyCount--;
                    } // while true
                }     // if MaxVertsPerPoly

                for (int i = 0; i < workingPolyCount; ++i)
                {
                    Array.Copy(workingPolys, i * mMaxVertsPerPoly,
                               globalPolys, globalPolyCount * mMaxVertsPerPoly, mMaxVertsPerPoly);
                    globalRegions[globalPolyCount] = contour.regionID;
                    globalPolyCount++;
                }
            } // for contours

            //xyz为一组
            result.verts = new int[globalVertCount * 3];
            Array.Copy(globalVerts, 0, result.verts, 0, globalVertCount * 3);

            result.polys = new int[globalPolyCount * mMaxVertsPerPoly * 2];
            for (int iPoly = 0; iPoly < globalPolyCount; ++iPoly)
            {
                int pPoly = iPoly * mMaxVertsPerPoly;  //第几个Poly的索引
                for (int offset = 0; offset < mMaxVertsPerPoly; ++offset)
                {
                    //result里的多边形是以 2 * mMaxVertsPerPoly为一组的
                    //第一组 mMaxVertsPerPoly 是多边形自身的数据
                    //第二组 mMaxVertsPertPol 是邻接多边形的数据
                    //而globalPolys就是以一组 mMaxVertsPerPoly
                    result.polys[pPoly * 2 + offset] = globalPolys[pPoly + offset];
                    result.polys[pPoly * 2 + mMaxVertsPerPoly + offset] = PolyMeshField.NULL_INDEX;
                }
            } // for

            result.polyRegions = new int[globalPolyCount];
            Array.Copy(globalRegions, 0, result.polyRegions, 0, globalPolyCount);

            buildAdjacencyData(result);

            return(result);
        } // build
Example #6
0
        public TriangleMesh build(float[] vertices, int[] indices, IntermediateData outIntermediateData)
        {
            if (outIntermediateData != null)
            {
                outIntermediateData.reset();
            }

            long timerStart = 0;

            if (outIntermediateData != null)
            {
                timerStart = System.DateTime.Now.Ticks;
            }

            SolidHeightfield solidField = mSolidHeightFieldBuilder.build(vertices, indices);

            if (solidField == null ||
                !solidField.hasSpans())
            {
                return(null);
            }

            if (outIntermediateData != null)
            {
                outIntermediateData.voxelizationTime = System.DateTime.Now.Ticks - timerStart;
            }

            if (outIntermediateData != null)
            {
                outIntermediateData.setSolidHeightfield(solidField);
            }

            if (outIntermediateData != null)
            {
                timerStart = System.DateTime.Now.Ticks;
            }

            OpenHeightfield openField = mOpenHeightFieldBuilder.build(solidField, false);

            if (null == openField)
            {
                return(null);
            }

            if (outIntermediateData != null)
            {
                outIntermediateData.setOpenHeightfield(openField);
            }

            mOpenHeightFieldBuilder.generateNeighborLinks(openField);
            mOpenHeightFieldBuilder.generateDistanceField(openField);
            mOpenHeightFieldBuilder.blurDistanceField(openField);
            mOpenHeightFieldBuilder.generateRegions(openField);

            if (outIntermediateData != null)
            {
                outIntermediateData.regionGenTime = System.DateTime.Now.Ticks - timerStart;
            }

            if (outIntermediateData != null)
            {
                timerStart = System.DateTime.Now.Ticks;
            }

            ContourSet contours = mContourSetBuilder.build(openField);

            if (null == contours)
            {
                return(null);
            }

            if (outIntermediateData != null)
            {
                outIntermediateData.contourGenTime = System.DateTime.Now.Ticks - timerStart;
            }

            if (outIntermediateData != null)
            {
                outIntermediateData.setContours(contours);
            }

            if (outIntermediateData != null)
            {
                timerStart = System.DateTime.Now.Ticks;
            }

            PolyMeshField polMesh = mPolyMeshBuilder.build(contours);

            if (null == polMesh)
            {
                return(null);
            }

            if (null != outIntermediateData)
            {
                outIntermediateData.polyGenTime = System.DateTime.Now.Ticks - timerStart;
            }

            if (outIntermediateData != null)
            {
                outIntermediateData.setPolyMesh(polMesh);
            }

            if (outIntermediateData != null)
            {
                timerStart = System.DateTime.Now.Ticks;
            }

            TriangleMesh mesh = mTriangleMeshBuilder.build(polMesh, openField);

            if (outIntermediateData != null &&
                mesh != null)
            {
                outIntermediateData.finalMeshGenTime = System.DateTime.Now.Ticks - timerStart;
            }

            return(mesh);
        }