Ejemplo n.º 1
0
        public void apply(OpenHeightfield field)
        {
            if (null == field)
            {
                Logger.LogError("[CLeanNullRegionBorders][apply]field null");
                return;
            }

            int nextRegionID = field.regionCount();

            OpenHeightfield.OpenHeightFieldIterator iter = field.GetEnumerator();
            while (iter.MoveNext())
            {
                OpenHeightSpan span = iter.Current;
                if (span.flags != 0)
                {
                    continue;
                }

                span.flags = 1;

                OpenHeightSpan workingSpan   = null;
                int            edgeDirection = -1;

                if (NULL_REGION == span.regionID())
                {
                    //找到Border Span第一个非空的邻居
                    edgeDirection = getNonNullBorderDrection(span);
                    if (-1 == edgeDirection)
                    {
                        continue;
                    }

                    //起点Span为有所属Region的Span
                    //而行走方向为 null Region所在的方向
                    workingSpan = span.getNeighbor(edgeDirection);
                    //转180度
                    edgeDirection = NMGenUtility.AntiDir(edgeDirection);
                }
                else if (!mUseOnlyNullSpans)
                {
                    //起点Span为 null Region的Span
                    //而行走方向即为有所属 Region 的 Span

                    edgeDirection = getNullBorderDrection(span);
                    if (-1 == edgeDirection)
                    {
                        continue;
                    }
                    workingSpan = span;
                }
                else
                {
                    continue;
                }

                //上面两个分支都会保证workingSpan是有所属Region的
                //而Dir 即是 Region 为 Null Region的Dir
                bool isEncompassedNullRegion = processNullRegion(workingSpan, edgeDirection);
                if (isEncompassedNullRegion)   //确定以这个Span为起点的Region,是一个单一Region,并且内含了一个Null Region
                {
                    //如果是完全包含了不可走的NullRegion ,就将这个Region分割成两个Region
                    partialFloodRegion(workingSpan, edgeDirection, nextRegionID);
                    nextRegionID++;
                }
            }

            field.setRegionCount(nextRegionID);

            iter.Reset();
            while (iter.MoveNext())
            {
                iter.Current.flags = 0;
            }
        }
        public void generateRegions( OpenHeightfield field )
        {
            if (null == field)
            {
                return;
            }

            //这个距离,控制生成的网络有多贴近实际的模型
            int minDist = mTraversableAreaBorderSize + field.minBorderDistance();
            int expandIterations = 4 + (mTraversableAreaBorderSize * 2); //TODO emmm

            //排除奇数
            int dist = (field.maxBorderDistance() - 1) & ~1 ;

            List<OpenHeightSpan> floodedSpans = new List<OpenHeightSpan>(1024);
            Stack<OpenHeightSpan> workingStack = new Stack<OpenHeightSpan>(1024);

            OpenHeightfield.OpenHeightFieldIterator iter = field.GetEnumerator();

            int nextRegionID = 1;
            //高于这个距离的体素都得生成Regions,那剩下的体素怎么办呢?
            while ( dist > minDist )  
            {
                iter.Reset();
                floodedSpans.Clear(); 

                while( iter.MoveNext() )
                {
                    OpenHeightSpan span = iter.Current; 
                    if( span.regionID() == NULL_REGION
                        && span.distanceToBorder() >= dist )
                    {
                        floodedSpans.Add(span); 
                    }
                }

                if( nextRegionID > 1 )
                {
                    //大于1表示已经至少存在1个region,先去尝试一下合并
                    if( dist > 0 )
                    {
                        expandRegions(floodedSpans, expandIterations);     
                    }
                    else  //这里不太可能会走到吧?除非minDist == 0
                    {
                        expandRegions(floodedSpans, -1); 
                    }
                }

                //剩下的可能要生成新的Region
                foreach( OpenHeightSpan span in floodedSpans )
                {
                    if( null == span 
                        || span.regionID() != NULL_REGION )
                    {
                        continue; 
                    }

                    //TODO ????
                    int fillTo = Math.Max(dist - 2, minDist); 
                    if( floodNewRegion(span,fillTo,nextRegionID,workingStack ))
                    {
                        nextRegionID++; 
                    }
                }

                //更新深度
                dist = Math.Max(dist - 2, 0); 
            }  //while dist > minDist

            //最后一篇循环
            iter.Reset();
            floodedSpans.Clear(); 
            while( iter.MoveNext() )
            {
                OpenHeightSpan span = iter.Current; 
                if( span.distanceToBorder() >= minDist
                    && span.regionID() == NULL_REGION )
                {
                    floodedSpans.Add(span); 
                }
            }

            if( minDist > 0 )
            {
                expandRegions(floodedSpans, expandIterations * 8); 
            }
            else
            {
                expandRegions(floodedSpans, -1); 
            }
            field.setRegionCount(nextRegionID);

            //后处理
            foreach( IOpenHeightFieldAlgorithm algorithm in mRegionAlgorithms )
            {
                algorithm.apply(field);  
            }
        }
Ejemplo n.º 3
0
        public void apply(OpenHeightfield field)
        {
            if (null == field)
            {
                Logger.LogError("[FilterOutSmallRegions][apply]field null");
                return;
            }

            if (field.regionCount() < 2)
            {
                Logger.LogError("[FilterOutSmallRegions][apply]RegionCnt|{0}", field.regionCount());
                return;
            }

            //PS:索引即是对应的ID
            Region[] regions = new Region[field.regionCount()];
            for (int i = 0; i < field.regionCount(); ++i)
            {
                regions[i] = new Region(i);
            }

            #region 收集邻接信息
            OpenHeightfield.OpenHeightFieldIterator iter = field.GetEnumerator();
            while (iter.MoveNext())
            {
                OpenHeightSpan span = iter.Current;
                if (span.regionID() <= NULL_REGION)
                {
                    continue;
                }

                //索引即RegionID
                Region region = regions[span.regionID()];
                region.spanCount++;

                for (OpenHeightSpan nextHigherSpan = span.next();
                     nextHigherSpan != null;
                     nextHigherSpan = nextHigherSpan.next()
                     )
                {
                    int nextHigherSpanRegionID = nextHigherSpan.regionID();
                    if (nextHigherSpanRegionID <= NULL_REGION)
                    {
                        continue;
                    }
                    //因为是同属一个Grid的,所以肯定是重叠的
                    if (!region.overlappingRegions.Contains(nextHigherSpanRegionID))
                    {
                        region.overlappingRegions.Add(nextHigherSpanRegionID);
                    }
                } //for

                if (region.connections.Count > 0)
                {
                    continue;
                }

                int edgeDirection = getRegionEdgeDirection(span);
                if (edgeDirection != -1)
                {
                    findRegionConnections(span, edgeDirection, ref region.connections);
                }
            } // while

            #endregion

            #region 清理孤岛Region
            for (int regionID = 1; regionID < field.regionCount(); ++regionID)
            {
                Region region = regions[regionID];
                if (0 == region.spanCount)
                {
                    continue;
                }

                // 有且仅有一个 Null Region 邻居
                if (region.connections.Count == 1 &&
                    region.connections[0] == NULL_REGION)
                {
                    if (region.spanCount < mMinUnconnectedRegionSize)
                    {
                        region.resetWithID(0);
                    }
                }
            }  //for

            #endregion

            #region 合并小的Region
            int mergeCount;
            do
            {
                mergeCount = 0;

                foreach (Region region in regions)
                {
                    if (region.id <= NULL_REGION ||
                        region.spanCount == 0)
                    {
                        continue;
                    }

                    if (region.spanCount > mMergeRegionSize)
                    {
                        continue;
                    }

                    Region targetMergeRegion = null;
                    int    smallestSizeFound = int.MaxValue;

                    foreach (int nRegionID in region.connections)
                    {
                        if (nRegionID <= 0)
                        {
                            continue;
                        }

                        Region nRegion = regions[nRegionID];
                        if (nRegion.spanCount < smallestSizeFound &&
                            canMerge(region, nRegion))
                        {
                            targetMergeRegion = nRegion;
                            smallestSizeFound = nRegion.spanCount;
                        }
                    } // foreach nRegionID

                    if (targetMergeRegion != null &&
                        mergeRegions(targetMergeRegion, region))     //为啥是反过来Merge。。。
                    {
                        int oldRegionID = region.id;
                        region.resetWithID(targetMergeRegion.id);

                        foreach (Region r in regions)
                        {
                            if (r.id <= NULL_REGION)
                            {
                                continue;
                            }
                            if (r.id == oldRegionID)
                            {
                                r.id = targetMergeRegion.id;
                            }
                            else
                            {
                                replaceNeighborRegionID(r, oldRegionID, targetMergeRegion.id);
                            }
                        } // foreach regions

                        mergeCount++;
                    } // if mergerRegion
                }     // foreach region
            } while (mergeCount > 0);

            #endregion

            #region  re-map 区域ID,保持ID连接
            foreach (Region region in regions)
            {
                if (region.id >= NULL_REGION)
                {
                    region.remap = true;
                }
            }

            int currRegionID = NULL_REGION;
            foreach (Region region in regions)
            {
                if (!region.remap)
                {
                    continue;
                }
                currRegionID++;
                int oldID = region.id;

                foreach (Region r in regions)
                {
                    if (r.id == oldID)
                    {
                        r.id    = currRegionID;
                        r.remap = false;
                    }
                } //foreach
            }     //foreach

            field.setRegionCount(currRegionID + 1);

            iter.Reset();
            while (iter.MoveNext())
            {
                OpenHeightSpan span = iter.Current;
                if (NULL_REGION == span.regionID())
                {
                    continue;
                }
                else
                {
                    //真正re-map一下
                    span.setRegionID(regions[span.regionID()].id);
                }
            }

            #endregion
        }  //apply