public void generateNeighborLinks(OpenHeightfield field) { if( field == null ) { Logger.LogError("[OpenHeightfieldBuilder][generateNeighborLinks]field Empty"); return; } OpenHeightfield.OpenHeightFieldIterator iter = field.GetEnumerator(); while( iter.MoveNext() ) { OpenHeightSpan span = iter.Current; for(int dir = 0; dir < 4; ++dir) { //邻居的GirdIndex int nWidthIndex = (iter.widthIndex() + BoundeField.getDirOffsetWidth(dir)); int nDepthIndex = (iter.depthIndex() + BoundeField.getDirOffsetDepth(dir)); for(OpenHeightSpan nSpan = field.getData(nWidthIndex,nDepthIndex); nSpan != null; nSpan = nSpan.next()) { int maxFloor = Math.Max(span.floor(), nSpan.floor()); int minCeling = Math.Min(span.ceiling(), nSpan.ceiling()); if( (minCeling - maxFloor) >= mMinTraversableHeight //邻居之间的通道足够高,可以通过 && Math.Abs(nSpan.floor() - span.floor()) <= mMaxTraversableStep ) //两邻居之间的落差足够小 { span.setNeighbor(dir, nSpan); break; } } } } }
public ContourSet build(OpenHeightfield sourceField) { if (null == sourceField || 0 == sourceField.regionCount()) { Logger.LogError("[ContourSetBuilder][build]sourceField Invalid"); return(null); } ContourSet result = new ContourSet(sourceField.boundsMin(), sourceField.boundsMax(), sourceField.cellSize(), sourceField.cellHeight(), sourceField.regionCount()); int discardedContours = 0; /* * If a span has no connections to external regions or is * completely surrounded by other regions (a single span island), * its flag will be zero. * * If a span is connected to one or more external regions then the * flag will be a 4 bit value where connections are recorded as * follows: * bit1 = neighbor0 * bit2 = neighbor1 * bit3 = neighbor2 * bit4 = neighbor3 * With the meaning of the bits as follows: * 0 = neighbor in same region. * 1 = neighbor not in same region. (Neighbor may be the null * region or a real region.) */ OpenHeightfield.OpenHeightFieldIterator iter = sourceField.GetEnumerator(); while (iter.MoveNext()) { OpenHeightSpan span = iter.Current; span.flags = 0; //默认没有与任何外部Region相连 if (NULL_REGION == span.regionID()) { continue; } for (int dir = 0; dir < 4; ++dir) { int nRegionID = NULL_REGION; OpenHeightSpan nSpan = span.getNeighbor(dir); if (nSpan != null) { nRegionID = nSpan.regionID(); } //这里是反常操作,先将相同的当作是1,然后统一位反 if (nRegionID == span.regionID()) { span.flags |= 1 << dir; } } // for //1111111 span.flags ^= 0xf; if (span.flags == 0xf) //证明四个邻居都不在同一个Region或者是一个孤岛Span { //重置这个位置 span.flags = 0; discardedContours++; Logger.LogWarning("[ContourSetBuilder][apply]Island Span|{0}|{1}", span.regionID(), discardedContours); } } //while iter List <int> workingRawVerts = new List <int>(256); List <int> workingSimplifiedVerts = new List <int>(64); iter.Reset(); while (iter.MoveNext()) { OpenHeightSpan span = iter.Current; if (NULL_REGION == span.regionID() || 0 == span.flags) //flag等于0的话,是前面那些孤岛Span { continue; } workingRawVerts.Clear(); workingSimplifiedVerts.Clear(); //找到第一个不是同一个Region的Span int startDir = 0; while (isSameRegion(span, startDir)) { startDir++; } buildRawContours(span, iter.widthIndex(), iter.depthIndex(), startDir, ref workingRawVerts ); generateSimplifiedContour(span.regionID(), workingRawVerts, ref workingSimplifiedVerts); //TODO 为什么小于12个顶点就不行呢? if (workingSimplifiedVerts.Count < 12) { Logger.LogWarning("[ContourSetBuilder][build]Discarded Contour|{0}|{1}|", span.regionID(), discardedContours); discardedContours++; } else { result.add(new Contour(span.regionID(), workingRawVerts, workingSimplifiedVerts)); } } // while iter if (discardedContours > 0) { Logger.LogWarning("[ContourSetBuilder][build]Contours not generated|{0}|", discardedContours); } if (result.size() + discardedContours != sourceField.regionCount() - 1) { for (int regionID = 1; regionID < sourceField.regionCount(); ++regionID) { int regionMatches = 0; for (int iContour = 0; iContour < result.size(); ++iContour) { if (regionID == result.get(iContour).regionID) { regionMatches++; } } if (regionMatches > 1) { Logger.LogError("[ContourSetBuilder][build]More than |{0}|{1}", regionID, regionMatches); } } // for for (int iContour = 0; iContour < result.size(); ++iContour) { Contour contour = result.get(iContour); if (contour.regionID <= 0) { Logger.LogError("[ContourSetBuilder][build]null region contour"); } else if (contour.regionID >= sourceField.regionCount()) { Logger.LogError("[ContourSetBuilder][build]contour out of range|{0}", contour.regionID); } } // for Logger.LogError("[ContourSetBuilder][build]Error{0}|{1}|{2}|{3}", sourceField.regionCount() - 1, result.size() + discardedContours, result.size(), discardedContours ); return(null); } return(result); } // build