Exemplo n.º 1
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));
                }
            }
        }