public InputGeom(List <float> vertexPositions, List <int> meshFaces) { vertices = new float[vertexPositions.Count]; for (int i = 0; i < vertices.Length; i++) { vertices[i] = vertexPositions[i]; } faces = new int[meshFaces.Count]; for (int i = 0; i < faces.Length; i++) { faces[i] = meshFaces[i]; } bmin = new float[3]; bmax = new float[3]; RecastVectors.copy(bmin, vertices, 0); RecastVectors.copy(bmax, vertices, 0); for (int i = 1; i < vertices.Length / 3; i++) { RecastVectors.min(bmin, vertices, i * 3); RecastVectors.max(bmax, vertices, i * 3); } }
/// @par /// /// The value of spacial parameters are in world units. /// /// The y-values of the polygon vertices are ignored. So the polygon is effectively /// projected onto the xz-plane at @p hmin, then extruded to @p hmax. /// /// @see rcCompactHeightfield, rcMedianFilterWalkableArea public static void markConvexPolyArea(Context ctx, float[] verts, float hmin, float hmax, int areaId, CompactHeightfield chf) { ctx.startTimer("MARK_CONVEXPOLY_AREA"); float[] bmin = new float[3]; float[] bmax = new float[3]; RecastVectors.copy(bmin, verts, 0); RecastVectors.copy(bmax, verts, 0); for (int i = 1; i < verts.Length; ++i) { RecastVectors.min(bmin, verts, i * 3); RecastVectors.max(bmax, verts, i * 3); } bmin[1] = hmin; bmax[1] = hmax; int minx = (int)((bmin[0] - chf.bmin[0]) / chf.cs); int miny = (int)((bmin[1] - chf.bmin[1]) / chf.ch); int minz = (int)((bmin[2] - chf.bmin[2]) / chf.cs); int maxx = (int)((bmax[0] - chf.bmin[0]) / chf.cs); int maxy = (int)((bmax[1] - chf.bmin[1]) / chf.ch); int maxz = (int)((bmax[2] - chf.bmin[2]) / chf.cs); if (maxx < 0) { return; } if (minx >= chf.width) { return; } if (maxz < 0) { return; } if (minz >= chf.height) { return; } if (minx < 0) { minx = 0; } if (maxx >= chf.width) { maxx = chf.width - 1; } if (minz < 0) { minz = 0; } if (maxz >= chf.height) { maxz = chf.height - 1; } // TODO: Optimize. for (int z = minz; z <= maxz; ++z) { for (int x = minx; x <= maxx; ++x) { CompactCell c = chf.cells[x + z * chf.width]; for (int i = c.index, ni = c.index + c.count; i < ni; ++i) { CompactSpan s = chf.spans[i]; if (chf.areas[i] == RecastConstants.RC_NULL_AREA) { continue; } if (s.y >= miny && s.y <= maxy) { float[] p = new float[3]; p[0] = chf.bmin[0] + (x + 0.5f) * chf.cs; p[1] = 0; p[2] = chf.bmin[2] + (z + 0.5f) * chf.cs; if (pointInPoly(verts, p)) { chf.areas[i] = areaId; } } } } } ctx.stopTimer("MARK_CONVEXPOLY_AREA"); }
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); } } }