コード例 #1
0
        /// @par
        ///
        /// This is just the beginning of the process of fully building a compact heightfield.
        /// Various filters may be applied, then the distance field and regions built.
        /// E.g: #rcBuildDistanceField and #rcBuildRegions
        ///
        /// See the #rcConfig documentation for more information on the configuration parameters.
        ///
        /// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig

        public static CompactHeightfield buildCompactHeightfield(Context ctx, int walkableHeight, int walkableClimb, Heightfield hf)
        {
            ctx.startTimer("BUILD_COMPACTHEIGHTFIELD");

            CompactHeightfield chf = new CompactHeightfield();
            int w         = hf.width;
            int h         = hf.height;
            int spanCount = getHeightFieldSpanCount(ctx, hf);

            // Fill in header.
            chf.width          = w;
            chf.height         = h;
            chf.spanCount      = spanCount;
            chf.walkableHeight = walkableHeight;
            chf.walkableClimb  = walkableClimb;
            chf.maxRegions     = 0;
            RecastVectors.copy(chf.bmin, hf.bmin);
            RecastVectors.copy(chf.bmax, hf.bmax);
            chf.bmax[1] += walkableHeight * hf.ch;
            chf.cs       = hf.cs;
            chf.ch       = hf.ch;
            chf.cells    = new CompactCell[w * h];
            chf.spans    = new CompactSpan[spanCount];
            chf.areas    = new int[spanCount];
            int MAX_HEIGHT = 0xffff;

            for (int i = 0; i < chf.cells.Length; i++)
            {
                chf.cells[i] = new CompactCell();
            }
            for (int i = 0; i < chf.spans.Length; i++)
            {
                chf.spans[i] = new CompactSpan();
            }
            // Fill in cells and spans.
            int idx = 0;

            for (int y = 0; y < h; ++y)
            {
                for (int x = 0; x < w; ++x)
                {
                    Span s = hf.spans[x + y * w];
                    // If there are no spans at this cell, just leave the data to index=0, count=0.
                    if (s == null)
                    {
                        continue;
                    }
                    CompactCell c = chf.cells[x + y * w];
                    c.index = idx;
                    c.count = 0;
                    while (s != null)
                    {
                        if (s.area != RecastConstants.RC_NULL_AREA)
                        {
                            int bot = s.smax;
                            int top = s.next != null ? (int)s.next.smin : MAX_HEIGHT;
                            chf.spans[idx].y = RecastCommon.clamp(bot, 0, 0xffff);
                            chf.spans[idx].h = RecastCommon.clamp(top - bot, 0, 0xff);
                            chf.areas[idx]   = s.area;
                            idx++;
                            c.count++;
                        }
                        s = s.next;
                    }
                }
            }

            // Find neighbour connections.
            int MAX_LAYERS       = RecastConstants.RC_NOT_CONNECTED - 1;
            int tooHighNeighbour = 0;

            for (int y = 0; y < h; ++y)
            {
                for (int x = 0; x < w; ++x)
                {
                    CompactCell c = chf.cells[x + y * w];
                    for (int i = c.index, ni = c.index + c.count; i < ni; ++i)
                    {
                        CompactSpan s = chf.spans[i];

                        for (int dir = 0; dir < 4; ++dir)
                        {
                            RecastCommon.SetCon(s, dir, RecastConstants.RC_NOT_CONNECTED);
                            int nx = x + RecastCommon.GetDirOffsetX(dir);
                            int ny = y + RecastCommon.GetDirOffsetY(dir);
                            // First check that the neighbour cell is in bounds.
                            if (nx < 0 || ny < 0 || nx >= w || ny >= h)
                            {
                                continue;
                            }

                            // Iterate over all neighbour spans and check if any of the is
                            // accessible from current cell.
                            CompactCell nc = chf.cells[nx + ny * w];
                            for (int k = nc.index, nk = nc.index + nc.count; k < nk; ++k)
                            {
                                CompactSpan ns  = chf.spans[k];
                                int         bot = Math.Max(s.y, ns.y);
                                int         top = Math.Min(s.y + s.h, ns.y + ns.h);

                                // Check that the gap between the spans is walkable,
                                // and that the climb height between the gaps is not too high.
                                if ((top - bot) >= walkableHeight && Math.Abs(ns.y - s.y) <= walkableClimb)
                                {
                                    // Mark direction as walkable.
                                    int lidx = k - nc.index;
                                    if (lidx < 0 || lidx > MAX_LAYERS)
                                    {
                                        tooHighNeighbour = Math.Max(tooHighNeighbour, lidx);
                                        continue;
                                    }
                                    RecastCommon.SetCon(s, dir, lidx);
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            if (tooHighNeighbour > MAX_LAYERS)
            {
                throw new Exception("rcBuildCompactHeightfield: Heightfield has too many layers " + tooHighNeighbour + " (max: " + MAX_LAYERS + ")");
            }
            ctx.stopTimer("BUILD_COMPACTHEIGHTFIELD");
            return(chf);
        }
コード例 #2
0
        private static void rasterizeTri(float[] verts, int v0, int v1, int v2, int area, Heightfield hf, float[] bmin, float[] bmax, float cs, float ics, float ich, int flagMergeThr)
        {
            int w = hf.width;
            int h = hf.height;

            float[] tmin = new float[3]; float[] tmax = new float[3];
            float   by = bmax[1] - bmin[1];

            // Calculate the bounding box of the triangle.
            RecastVectors.copy(tmin, verts, v0 * 3);
            RecastVectors.copy(tmax, verts, v0 * 3);
            RecastVectors.min(tmin, verts, v1 * 3);
            RecastVectors.min(tmin, verts, v2 * 3);
            RecastVectors.max(tmax, verts, v1 * 3);
            RecastVectors.max(tmax, verts, v2 * 3);

            // If the triangle does not touch the bbox of the heightfield, skip the triagle.
            if (!overlapBounds(bmin, bmax, tmin, tmax))
            {
                return;
            }

            // Calculate the footprint of the triangle on the grid's y-axis
            int y0 = (int)((tmin[2] - bmin[2]) * ics);
            int y1 = (int)((tmax[2] - bmin[2]) * ics);

            y0 = RecastCommon.clamp(y0, 0, h - 1);
            y1 = RecastCommon.clamp(y1, 0, h - 1);

            // Clip the triangle into all grid cells it touches.
            float[] buf   = new float[7 * 3 * 4];
            int     @in   = 0;
            int     inrow = 7 * 3;
            int     p1    = inrow + 7 * 3;
            int     p2    = p1 + 7 * 3;

            RecastVectors.copy(buf, 0, verts, v0 * 3);
            RecastVectors.copy(buf, 3, verts, v1 * 3);
            RecastVectors.copy(buf, 6, verts, v2 * 3);
            int nvrow, nvIn = 3;

            for (int y = y0; y <= y1; ++y)
            {
                // Clip polygon to row. Store the remaining polygon as well
                float cz      = bmin[2] + y * cs;
                int[] nvrowin = dividePoly(buf, @in, nvIn, inrow, p1, cz + cs, 2);
                nvrow = nvrowin[0];
                nvIn  = nvrowin[1];
                {
                    int temp = @in;
                    @in = p1;
                    p1  = temp;
                }
                if (nvrow < 3)
                {
                    continue;
                }

                // find the horizontal bounds in the row
                float minX = buf[inrow], maxX = buf[inrow];
                for (int i = 1; i < nvrow; ++i)
                {
                    if (minX > buf[inrow + i * 3])
                    {
                        minX = buf[inrow + i * 3];
                    }
                    if (maxX < buf[inrow + i * 3])
                    {
                        maxX = buf[inrow + i * 3];
                    }
                }
                int x0 = (int)((minX - bmin[0]) * ics);
                int x1 = (int)((maxX - bmin[0]) * ics);
                x0 = RecastCommon.clamp(x0, 0, w - 1);
                x1 = RecastCommon.clamp(x1, 0, w - 1);

                int nv, nv2 = nvrow;
                for (int x = x0; x <= x1; ++x)
                {
                    // Clip polygon to column. store the remaining polygon as well
                    float cx    = bmin[0] + x * cs;
                    int[] nvnv2 = dividePoly(buf, inrow, nv2, p1, p2, cx + cs, 0);
                    nv  = nvnv2[0];
                    nv2 = nvnv2[1];
                    {
                        int temp = inrow;
                        inrow = p2;
                        p2    = temp;
                    }
                    if (nv < 3)
                    {
                        continue;
                    }

                    // Calculate min and max of the span.
                    float smin = buf[p1 + 1], smax = buf[p1 + 1];
                    for (int i = 1; i < nv; ++i)
                    {
                        smin = Math.Min(smin, buf[p1 + i * 3 + 1]);
                        smax = Math.Max(smax, buf[p1 + i * 3 + 1]);
                    }
                    smin -= bmin[1];
                    smax -= bmin[1];
                    // Skip the span if it is outside the heightfield bbox
                    if (smax < 0.0f)
                    {
                        continue;
                    }
                    if (smin > by)
                    {
                        continue;
                    }
                    // Clamp the span to the heightfield bbox.
                    if (smin < 0.0f)
                    {
                        smin = 0;
                    }
                    if (smax > by)
                    {
                        smax = by;
                    }

                    // Snap the span to the heightfield height grid.
                    int ismin = RecastCommon.clamp((int)Math.Floor(smin * ich), 0, RecastConstants.RC_SPAN_MAX_HEIGHT);
                    int ismax = RecastCommon.clamp((int)Math.Ceiling(smax * ich), ismin + 1, RecastConstants.RC_SPAN_MAX_HEIGHT);

                    addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
                }
            }
        }