public OpenHeightfield build(SolidHeightfield sourceField ,
            bool performFullGeneration )
        {
            if( sourceField == null )
            {
                Logger.LogError("[OpenHeightfieldBuilder][build] sourceField null "); 
                return null; 
            }

            OpenHeightfield result = new OpenHeightfield(
                sourceField.boundsMin(),
                sourceField.boundsMax(),
                sourceField.cellSize(),
                sourceField.cellHeight()
                );
            
            for(int depthIndex = 0; depthIndex < sourceField.depth(); depthIndex++)
            {
                for(int widthIndex = 0; widthIndex < sourceField.width(); widthIndex++)
                {
                    OpenHeightSpan baseSpan = null;
                    OpenHeightSpan previousSpan = null;

                    for (HeightSpan span = sourceField.getData(widthIndex, depthIndex);
                         span != null;
                         span = span.next()
                        )
                    {
                        if ( span.flags() != mFilterFlags )
                        {
                            continue; 
                        }

                        //当前Solid Span的max对应的是对应OpenSpan的floor
                        int floor = span.max();  
                        //下一个Next Solid Span的min对应当前OpenSpan的Ceil。
                        int ceiling = (span.next() != null
                            ? span.next().min()
                            : int.MaxValue) ;

                        //对应的Open Span
                        OpenHeightSpan oSpan = new OpenHeightSpan(floor,
                            (ceiling - floor )
                            ); 
                        if( baseSpan == null  )
                        {
                            baseSpan = oSpan; 
                        }
                        if( previousSpan != null )
                        {
                            previousSpan.setNext(oSpan); 
                        }
                        previousSpan = oSpan;
                        result.incrementSpanCount(); 
                    } //for 
                    if( baseSpan != null )
                    {
                        result.addData(widthIndex, depthIndex, baseSpan); 
                    }
                }//for
            } //for

            if( performFullGeneration )
            {
                generateNeighborLinks(result);
                generateDistanceField(result);
                blurDistanceField(result);
                generateRegions(result);  
            }

            return result; 
        }
        //vertices是以(x,y,z)(x,y,z)三组三组为一个顶点
        public SolidHeightfield build(float[] vertices, int[] indices)
        {
            if (vertices == null ||
                indices == null ||
                vertices.Length % 3 != 0 ||
                indices.Length % 3 != 0)
            {
                Logger.LogError("[SolidHeightfieldBuilder][build]invalid");
                return(null);
            }

            SolidHeightfield result = new SolidHeightfield(mCellSize, mCellHeight);

            //用作分母,方便后面计算的
            float inverseCellSize   = 1 / result.cellSize();
            float inverseCellHeight = 1 / result.cellHeight();


            float xmin = vertices[0];
            float ymin = vertices[1];
            float zmin = vertices[2];
            float xmax = vertices[0];
            float ymax = vertices[1];
            float zmax = vertices[2];

            //遍历所有顶点,找出最大的Bounds
            for (int i = 3; i < vertices.Length; i += 3)
            {
                xmax = Math.Max(vertices[i], xmax);
                ymax = Math.Max(vertices[i + 1], ymax);
                zmax = Math.Max(vertices[i + 2], zmax);

                xmin = Math.Min(vertices[i], xmin);
                ymin = Math.Min(vertices[i + 1], ymin);
                zmin = Math.Min(vertices[i + 2], zmin);
            }

            result.setBounds(xmin, ymin, zmin, xmax, ymax, zmax);

            //判断哪些多边形的表面是可以行走的,坡度不能太大
            int[] polyFlags = markInputMeshWalkableFlags(vertices, indices);

            //开始对每个面进行体素化
            int polyCount = indices.Length / 3;

            for (int iPoly = 0; iPoly < polyCount; iPoly++)
            {
                voxelizeTriangle(iPoly,
                                 vertices,
                                 indices,
                                 polyFlags[iPoly],
                                 inverseCellSize,
                                 inverseCellHeight,
                                 result);
            }

            markLowHeightSpans(result);

            if (mClipLedges)
            {
                markLedgeSpans(result);
            }

            return(result);
        }