public static int[] calcTileCount(float[] bmin, float[] bmax, float cs, int tileSize) { int[] gwh = Recast.calcGridSize(bmin, bmax, cs); int gw = gwh[0]; int gh = gwh[1]; int ts = tileSize; int tw = (gw + ts - 1) / ts; int th = (gh + ts - 1) / ts; return(new int[] { tw, th }); }
private CompactHeightfield buildCompactHeightfield(InputGeom geom, RecastBuilderConfig bcfg, Context ctx) { RecastConfig cfg = bcfg.cfg; // // Step 2. Rasterize input polygon soup. // // Allocate voxel heightfield where we rasterize our input data to. Heightfield solid = new Heightfield(bcfg.width, bcfg.height, bcfg.bmin, bcfg.bmax, cfg.cs, cfg.ch); // Allocate array that can hold triangle area types. // If you have multiple meshes you need to process, allocate // and array which can hold the max number of triangles you need to // process. // Find triangles which are walkable based on their slope and rasterize // them. // If your input data is multiple meshes, you can transform them here, // calculate // the are type for each of the meshes and rasterize them. float[] verts = geom.Verts; bool tiled = cfg.tileSize > 0; int totaltris = 0; if (tiled) { ChunkyTriMesh chunkyMesh = geom.ChunkyMesh; float[] tbmin = new float[2]; float[] tbmax = new float[2]; tbmin[0] = bcfg.bmin[0]; tbmin[1] = bcfg.bmin[2]; tbmax[0] = bcfg.bmax[0]; tbmax[1] = bcfg.bmax[2]; List <ChunkyTriMeshNode> nodes = chunkyMesh.getChunksOverlappingRect(tbmin, tbmax); foreach (ChunkyTriMeshNode node in nodes) { int[] tris = node.tris; int ntris = tris.Length / 3; totaltris += ntris; int[] m_triareas = Recast.markWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris); RecastRasterization.rasterizeTriangles(ctx, verts, tris, m_triareas, ntris, solid, cfg.walkableClimb); } } else { int[] tris = geom.Tris; int ntris = tris.Length / 3; int[] m_triareas = Recast.markWalkableTriangles(ctx, cfg.walkableSlopeAngle, verts, tris, ntris); totaltris = ntris; RecastRasterization.rasterizeTriangles(ctx, verts, tris, m_triareas, ntris, solid, cfg.walkableClimb); } // // Step 3. Filter walkables surfaces. // // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. RecastFilter.filterLowHangingWalkableObstacles(ctx, cfg.walkableClimb, solid); RecastFilter.filterLedgeSpans(ctx, cfg.walkableHeight, cfg.walkableClimb, solid); RecastFilter.filterWalkableLowHeightSpans(ctx, cfg.walkableHeight, solid); // // Step 4. Partition walkable surface to simple regions. // // Compact the heightfield so that it is faster to handle from now on. // This will result more cache coherent data as well as the neighbours // between walkable cells will be calculated. CompactHeightfield chf = Recast.buildCompactHeightfield(ctx, cfg.walkableHeight, cfg.walkableClimb, solid); // Erode the walkable area by agent radius. RecastArea.erodeWalkableArea(ctx, cfg.walkableRadius, chf); // (Optional) Mark areas. foreach (ConvexVolume vol in geom.ConvexVolumes) { RecastArea.markConvexPolyArea(ctx, vol.verts, vol.hmin, vol.hmax, vol.area, chf); } return(chf); }