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

                }
            }
        }
Exemplo n.º 2
0
        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