}// 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; }
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