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