Ejemplo n.º 1
0
        /// <summary>
        /// Find all the polygons within a certain bounding box.
        /// </summary>
        /// <param name="tile">Current tile</param>
        /// <param name="qbounds">The bounds</param>
        /// <param name="polys">List of polygons</param>
        /// <returns>Number of polygons found</returns>
        public int QueryPolygonsInTile(MeshTile tile, BBox3 qbounds, List <PolyId> polys)
        {
            if (tile.BVTree.Count != 0)
            {
                int     node  = 0;
                int     end   = tile.Header.BvNodeCount;
                Vector3 tbmin = tile.Header.Bounds.Min;
                Vector3 tbmax = tile.Header.Bounds.Max;

                //Clamp query box to world box
                Vector3    qbmin = qbounds.Min;
                Vector3    qbmax = qbounds.Max;
                PolyBounds b;
                float      bminx = MathHelper.Clamp(qbmin.X, tbmin.X, tbmax.X) - tbmin.X;
                float      bminy = MathHelper.Clamp(qbmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
                float      bminz = MathHelper.Clamp(qbmin.Z, tbmin.Z, tbmax.Z) - tbmin.Z;
                float      bmaxx = MathHelper.Clamp(qbmax.X, tbmin.X, tbmax.X) - tbmin.X;
                float      bmaxy = MathHelper.Clamp(qbmax.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
                float      bmaxz = MathHelper.Clamp(qbmax.Z, tbmin.Z, tbmax.Z) - tbmin.Z;

                const int MinMask = unchecked ((int)0xfffffffe);

                b.Min.X = (int)(bminx * tile.Header.BvQuantFactor) & MinMask;
                b.Min.Y = (int)(bminy * tile.Header.BvQuantFactor) & MinMask;
                b.Min.Z = (int)(bminz * tile.Header.BvQuantFactor) & MinMask;
                b.Max.X = (int)(bmaxx * tile.Header.BvQuantFactor + 1) | 1;
                b.Max.Y = (int)(bmaxy * tile.Header.BvQuantFactor + 1) | 1;
                b.Max.Z = (int)(bmaxz * tile.Header.BvQuantFactor + 1) | 1;

                //traverse tree
                PolyId polyBase = GetPolyRefBase(tile);

                while (node < end)
                {
                    BVTree.Node bvNode     = tile.BVTree[node];
                    bool        overlap    = PolyBounds.Overlapping(ref b, ref bvNode.Bounds);
                    bool        isLeafNode = bvNode.Index >= 0;

                    if (isLeafNode && overlap)
                    {
                        if (polys.Count < polys.Capacity)
                        {
                            PolyId polyRef;
                            PolyId.SetPolyIndex(ref polyBase, bvNode.Index, out polyRef);
                            polys.Add(polyRef);
                        }
                    }

                    if (overlap || isLeafNode)
                    {
                        node++;
                    }
                    else
                    {
                        int escapeIndex = -bvNode.Index;
                        node += escapeIndex;
                    }
                }

                return(polys.Count);
            }
            else
            {
                BBox3  b;
                PolyId polyBase = GetPolyRefBase(tile);

                for (int i = 0; i < tile.Header.PolyCount; i++)
                {
                    var poly = tile.Polys[i];

                    //don't return off-mesh connection polygons
                    if (poly.PolyType == PolygonType.OffMeshConnection)
                    {
                        continue;
                    }

                    //calculate polygon bounds
                    b.Max = b.Min = tile.Verts[poly.Verts[0]];
                    for (int j = 1; j < poly.VertCount; j++)
                    {
                        Vector3 v = tile.Verts[poly.Verts[j]];
                        Vector3Extensions.ComponentMin(ref b.Min, ref v, out b.Min);
                        Vector3Extensions.ComponentMax(ref b.Max, ref v, out b.Max);
                    }

                    if (BBox3.Overlapping(ref qbounds, ref b))
                    {
                        if (polys.Count < polys.Capacity)
                        {
                            PolyId polyRef;
                            PolyId.SetPolyIndex(ref polyBase, i, out polyRef);
                            polys.Add(polyRef);
                        }
                    }
                }

                return(polys.Count);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Rasterizes a triangle using conservative voxelization.
        /// </summary>
        /// <param name="a">The first vertex of the triangle.</param>
        /// <param name="b">The second vertex of the triangle.</param>
        /// <param name="c">The third vertex of the triangle.</param>
        /// <param name="area">The area flags for the triangle.</param>
        public void RasterizeTriangle(ref Vector3 a, ref Vector3 b, ref Vector3 c, Area area)
        {
            //distances buffer for ClipPolygonToBounds
            float[] distances = new float[12];

            float invCellSize   = 1f / cellSize;
            float invCellHeight = 1f / cellHeight;
            float boundHeight   = bounds.Max.Y - bounds.Min.Y;

            //calculate the triangle's bounding box
            BBox3 bbox;

            Triangle3.GetBoundingBox(ref a, ref b, ref c, out bbox);

            //make sure that the triangle is at least in one cell.
            if (!BBox3.Overlapping(ref bbox, ref bounds))
            {
                return;
            }

            //figure out which rows.
            int z0 = (int)((bbox.Min.Z - bounds.Min.Z) * invCellSize);
            int z1 = (int)((bbox.Max.Z - bounds.Min.Z) * invCellSize);

            //clamp to the field boundaries.
            MathHelper.Clamp(ref z0, 0, length - 1);
            MathHelper.Clamp(ref z1, 0, length - 1);

            Vector3[] inVerts = new Vector3[7], outVerts = new Vector3[7], inRowVerts = new Vector3[7];

            for (int z = z0; z <= z1; z++)
            {
                //copy the original vertices to the array.
                inVerts[0] = a;
                inVerts[1] = b;
                inVerts[2] = c;

                //clip the triangle to the row
                int   nvrow = 3;
                float cz    = bounds.Min.Z + z * cellSize;
                nvrow = MathHelper.ClipPolygonToPlane(inVerts, outVerts, distances, nvrow, 0, 1, -cz);
                if (nvrow < 3)
                {
                    continue;
                }
                nvrow = MathHelper.ClipPolygonToPlane(outVerts, inRowVerts, distances, nvrow, 0, -1, cz + cellSize);
                if (nvrow < 3)
                {
                    continue;
                }

                float minX = inRowVerts[0].X, maxX = minX;
                for (int i = 1; i < nvrow; i++)
                {
                    float vx = inRowVerts[i].X;
                    if (minX > vx)
                    {
                        minX = vx;
                    }
                    if (maxX < vx)
                    {
                        maxX = vx;
                    }
                }

                int x0 = (int)((minX - bounds.Min.X) * invCellSize);
                int x1 = (int)((maxX - bounds.Min.X) * invCellSize);

                MathHelper.Clamp(ref x0, 0, width - 1);
                MathHelper.Clamp(ref x1, 0, width - 1);

                for (int x = x0; x <= x1; x++)
                {
                    //clip the triangle to the column
                    int   nv = nvrow;
                    float cx = bounds.Min.X + x * cellSize;
                    nv = MathHelper.ClipPolygonToPlane(inRowVerts, outVerts, distances, nv, 1, 0, -cx);
                    if (nv < 3)
                    {
                        continue;
                    }
                    nv = MathHelper.ClipPolygonToPlane(outVerts, inVerts, distances, nv, -1, 0, cx + cellSize);
                    if (nv < 3)
                    {
                        continue;
                    }

                    //calculate the min/max of the polygon
                    float polyMin = inVerts[0].Y, polyMax = polyMin;
                    for (int i = 1; i < nv; i++)
                    {
                        float y = inVerts[i].Y;
                        polyMin = Math.Min(polyMin, y);
                        polyMax = Math.Max(polyMax, y);
                    }

                    //normalize span bounds to bottom of heightfield
                    float boundMinY = bounds.Min.Y;
                    polyMin -= boundMinY;
                    polyMax -= boundMinY;

                    //if the spans are outside the heightfield, skip.
                    if (polyMax < 0f || polyMin > boundHeight)
                    {
                        continue;
                    }

                    //clamp the span to the heightfield.
                    if (polyMin < 0)
                    {
                        polyMin = 0;
                    }
                    if (polyMax > boundHeight)
                    {
                        polyMax = boundHeight;
                    }

                    //snap to grid
                    int spanMin = (int)(polyMin * invCellHeight);
                    int spanMax = (int)Math.Ceiling(polyMax * invCellHeight);

                    //add the span
                    cells[z * width + x].AddSpan(new Span(spanMin, spanMax, area));
                }
            }
        }