public void BuildTile(int x, int y) { RecastVertex bmin = Geometry.MinBounds; RecastVertex bmax = Geometry.MaxBounds; float tcs = Config.TileSize * Config.CellSize; RecastVertex tileBMin = new RecastVertex(); RecastVertex tileBMax = new RecastVertex(); tileBMin.X = bmin.X + x * tcs; tileBMin.Y = bmin.Y; tileBMin.Z = bmin.Z + y * tcs; tileBMax.X = bmin.X + (x + 1) * tcs; tileBMax.Y = bmax.Y; tileBMax.Z = bmin.Z + (y + 1) * tcs; var builder = BuildTileMesh(x, y, tileBMin, tileBMax); // remove/add new tile? if (builder != null) { LunaNav.NavMeshBuilder outBuilder; // nav mesh remove tile NavMesh.RemoveTile(NavMesh.GetTileRefAt(x, y, 0), out outBuilder); // nav mesh add tile long result = 0; NavMesh.AddTile(builder, NavMesh.TileFreeData, 0, ref result); } }
private void Xloop(int y, int x, float tcs, RecastVertex bmin, RecastVertex bmax) { RecastVertex tileBMin = new RecastVertex(); RecastVertex tileBMax = new RecastVertex(); tileBMin.X = bmin.X + x * tcs; tileBMin.Y = bmin.Y; tileBMin.Z = bmin.Z + y * tcs; tileBMax.X = bmin.X + (x + 1) * tcs; tileBMax.Y = bmax.Y; tileBMax.Z = bmin.Z + (y + 1) * tcs; bool canceled = EditorUtility.DisplayCancelableProgressBar("Generating...", "Generating Tile " + Progress + " of " + Total, Progress / (float)Total); if (canceled) { //tokenSource.Cancel(); } //var t = Task.Factory.StartNew(() => BuildTile(x, y, tileBMin, tileBMax), tokenSource.Token, TaskCreationOptions.LongRunning, scheduler); //tasks.Add(t); BuildTile(x, y, tileBMin, tileBMax); }
public void BuildTileSizeData() { RecastVertex bmin = _geom.MinBounds; RecastVertex bmax = _geom.MaxBounds; int gw = 0, gh = 0; CalcGridSize(bmin, bmax, _config.CellSize, out gw, out gh); int ts = TileSize; int tw = (gw + ts - 1) / ts; int th = (gh + ts - 1) / ts; TileWidth = tw; TileHeight = th; int tileBits = Math.Min(ilog2(nextPow2(th * tw)), 14); if (tileBits > 14) { tileBits = 14; } int polyBits = 22 - tileBits; MaxTiles = 1 << tileBits; MaxPolysPerTile = 1 << polyBits; }
/// <summary> /// Builds the entire NavMesh from the Data gathered by BuildGeometry through the Detail Mesh /// Then it creates a GameObject that has the RecastNavMesh. /// </summary> /// <returns></returns> public long BuildAllTiles(Config config, Geometry geom, int tileWidth, int tileHeight, int maxPolysPerTile, int maxTiles) { NavMesh = new Detour.NavMesh(); NavMeshParams param = new NavMeshParams() { Orig = geom.MinBounds.ToArray(), MaxPolys = maxPolysPerTile, MaxTiles = maxTiles, TileWidth = config.TileSize * config.CellSize, TileHeight = config.TileSize * config.CellSize }; NavMesh.Init(param); TileWidth = tileWidth; TileHeight = tileHeight; Config = config; Geometry = geom; Progress = 0; IsBuilding = true; Stopwatch timer = new Stopwatch(); timer.Start(); RecastVertex bmin = geom.MinBounds; RecastVertex bmax = geom.MaxBounds; float tcs = config.TileSize * config.CellSize; Total = TileWidth * TileHeight; bool canceled = false; for (int y = 0; y < TileHeight; y++) { YLoop(y, tcs, bmin, bmax); } if (!canceled) { while (Progress != Total) { canceled = EditorUtility.DisplayCancelableProgressBar("Generating...", "Generating Tile " + Progress + " of " + Total, Progress / (float)Total); if (canceled) { tokenSource.Cancel(); break; } } } Task.WaitAll(tasks.ToArray()); timer.Stop(); EditorUtility.ClearProgressBar(); IsBuilding = false; BuildGeometry(); return(timer.ElapsedMilliseconds); }
private void CalcGridSize(RecastVertex bmin, RecastVertex bmax, float cellSize, out int w, out int h) { if (bmin != null && bmax != null) { w = (int)((bmax.X - bmin.X) / cellSize + 0.5f); h = (int)((bmax.Z - bmin.Z) / cellSize + 0.5f); } else { w = 0; h = 0; } }
private void YLoop(int y, float tcs, RecastVertex bmin, RecastVertex bmax) { bool canceled = false; for (int x = 0; x < TileWidth; x++) { canceled = EditorUtility.DisplayCancelableProgressBar("Generating...", "Generating Tile " + Progress + " of " + Total, Progress / (float)Total); if (canceled) { //tokenSource.Cancel(); break; } Xloop(y, x, tcs, bmin, bmax); } }
public void RebuildTiles() { Progress = 0; IsBuilding = true; RecastVertex bmin = Geometry.MinBounds; RecastVertex bmax = Geometry.MaxBounds; RecastVertex tileBMin = new RecastVertex(); RecastVertex tileBMax = new RecastVertex(); float tcs = Config.TileSize * Config.CellSize; Total = TileWidth * TileHeight; for (int y = 0; y < TileHeight; y++) { for (int x = 0; x < TileWidth; x++) { Progress = y * TileWidth + x; tileBMin.X = bmin.X + x * tcs; tileBMin.Y = bmin.Y; tileBMin.Z = bmin.Z + y * tcs; tileBMax.X = bmin.X + (x + 1) * tcs; tileBMax.Y = bmax.Y; tileBMax.Z = bmin.Z + (y + 1) * tcs; EditorUtility.DisplayProgressBar("Generating...", "Generating Tile " + Progress + " of " + Total, Progress / (float)Total); var builder = BuildTileMesh(x, y, tileBMin, tileBMax); // remove/add new tile? if (builder != null) { LunaNav.NavMeshBuilder outBuilder; // nav mesh remove tile NavMesh.RemoveTile(NavMesh.GetTileRefAt(x, y, 0), out outBuilder); // nav mesh add tile long result = 0; NavMesh.AddTile(builder, NavMesh.TileFreeData, 0, ref result); } } } EditorUtility.ClearProgressBar(); IsBuilding = false; BuildGeometry(); }
public void BuildTile(int x, int y, RecastVertex tileBMin, RecastVertex tileBMax) { var builder = BuildTileMesh(x, y, tileBMin, tileBMax); // remove/add new tile? if (builder != null) { lock (this) { LunaNav.NavMeshBuilder outBuilder; // nav mesh remove tile NavMesh.RemoveTile(NavMesh.GetTileRefAt(x, y, 0), out outBuilder); // nav mesh add tile long result = 0; NavMesh.AddTile(builder, NavMesh.TileFreeData, 0, ref result); } } Progress++; }
public void BuildTile(int x, int y, RecastVertex tileBMin, RecastVertex tileBMax) { var builder = BuildTileMesh(x, y, tileBMin, tileBMax); // remove/add new tile? if (builder != null) { lock (this) { Detour.AtavismNavTile outBuilder; // nav mesh remove tile NavMesh.RemoveTile(NavMesh.GetTileRefAt(x, y, 0), out outBuilder); // nav mesh add tile long result = 0; NavMesh.AddTile(builder, NavMesh.TileFreeData, 0, ref result); } } Progress++; }
private static void CalcGridSize(RecastVertex bmin, RecastVertex bmax, float cellSize, out int w, out int h) { if (bmin != null && bmax != null) { w = (int) ((bmax.X - bmin.X)/cellSize + 0.5f); h = (int) ((bmax.Z - bmin.Z)/cellSize + 0.5f); } else { w = 0; h = 0; } }
/// <summary> /// This takes the current geometry and builds the data to go into Recast /// It needs to be updated to take into account scale, position, and rotation /// It needs to be updated to look for specific tags /// </summary> /// <param name="geom"></param> private void BuildGeometry(Config config, Geometry geom) { for (int i = 0; i < UnityEditorInternal.InternalEditorUtility.tags.Length; i++) { if ((Tags & (1 << i)) != 0) { foreach (var gameObject in GameObject.FindGameObjectsWithTag(UnityEditorInternal.InternalEditorUtility.tags[i])) { foreach (var terrainObj in gameObject.GetComponentsInChildren <Terrain>()) { var terrain = terrainObj.terrainData; var w = terrain.heightmapWidth; var h = terrain.heightmapHeight; var meshScale = terrain.size; var tRes = 1; meshScale = new Vector3(meshScale.x / (w - 1) * tRes, meshScale.y, meshScale.z / (h - 1) * tRes); var tData = terrain.GetHeights(0, 0, w, h); w = (w - 1) / tRes + 1; h = (h - 1) / tRes + 1; var tVertices = new Vector3[w * h]; var tPolys = new int[(w - 1) * (h - 1) * 6]; // Build vertices and UVs for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { tVertices[y * w + x] = Vector3.Scale(meshScale, new Vector3(x, tData[y * tRes, x * tRes], y)) + terrainObj.transform.position; } } var index = 0; // Build triangle indices: 3 indices into vertex array for each triangle for (int y = 0; y < h - 1; y++) { for (int x = 0; x < w - 1; x++) { // For each grid cell output two triangles tPolys[index++] = (y * w) + x; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = (y * w) + x + 1; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = ((y + 1) * w) + x + 1; tPolys[index++] = (y * w) + x + 1; } } int subTotalVerts = geom.NumVertexes; foreach (var tVertex in tVertices) { geom.Vertexes.Add(new RecastVertex(tVertex.x, tVertex.y, tVertex.z)); geom.NumVertexes++; } for (int j = 0; j < tPolys.Length; j += 3) { geom.Triangles.Add(tPolys[j] + subTotalVerts); geom.Triangles.Add(tPolys[j + 1] + subTotalVerts); geom.Triangles.Add(tPolys[j + 2] + subTotalVerts); geom.NumTriangles++; } } foreach (var componentsInChild in gameObject.GetComponentsInChildren <MeshFilter>()) { int subTotalVerts = geom.NumVertexes; foreach (Vector3 vector3 in componentsInChild.sharedMesh.vertices) { Vector3 vec = gameObject.transform.TransformPoint(vector3); geom.Vertexes.Add(new RecastVertex(vec.x, vec.y, vec.z)); geom.NumVertexes++; } for (int j = 0; j < componentsInChild.sharedMesh.triangles.Length; j += 3) { geom.Triangles.Add(componentsInChild.sharedMesh.triangles[j] + subTotalVerts); geom.Triangles.Add(componentsInChild.sharedMesh.triangles[j + 1] + subTotalVerts); geom.Triangles.Add(componentsInChild.sharedMesh.triangles[j + 2] + subTotalVerts); geom.NumTriangles++; } } foreach (var offMeshConnector in gameObject.GetComponentsInChildren <OffMeshConnector>()) { RecastVertex start = new RecastVertex(offMeshConnector.StartPosition.x, offMeshConnector.StartPosition.y, offMeshConnector.StartPosition.z); RecastVertex end = new RecastVertex(offMeshConnector.EndPosition.x, offMeshConnector.EndPosition.y, offMeshConnector.EndPosition.z); geom.AddOffMeshConnection(start, end, offMeshConnector.Radius, offMeshConnector.Bidirectional, 5, 8); } } } } Verts = geom.NumVertexes; Tris = geom.NumTriangles; if (Verts != 0) { geom.CalculateBounds(); config.CalculateGridSize(geom); geom.CreateChunkyTriMesh(); } }
/// <summary> /// This takes the current geometry and builds the data to go into Recast /// It needs to be updated to take into account scale, position, and rotation /// It needs to be updated to look for specific tags /// </summary> /// <param name="geom"></param> private static void BuildGeometry(NavMeshSettings settings, Config config, Geometry geom) { for (int i = 0; i < UnityEditorInternal.InternalEditorUtility.tags.Length; i++) { if ((settings.Tags & (1 << i)) != 0) { foreach (var gameObject in GameObject.FindGameObjectsWithTag(UnityEditorInternal.InternalEditorUtility.tags[i])) { foreach (var terrainObj in gameObject.GetComponentsInChildren<Terrain>()) { var terrain = terrainObj.terrainData; var w = terrain.heightmapWidth; var h = terrain.heightmapHeight; var meshScale = terrain.size; var tRes = 1; meshScale = new Vector3(meshScale.x / (w - 1) * tRes, meshScale.y, meshScale.z / (h - 1) * tRes); var tData = terrain.GetHeights(0, 0, w, h); w = (w - 1) / tRes + 1; h = (h - 1) / tRes + 1; var tVertices = new Vector3[w * h]; var tPolys = new int[(w - 1) * (h - 1) * 6]; // Build vertices and UVs for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { tVertices[y * w + x] = Vector3.Scale(meshScale, new Vector3(x, tData[y * tRes, x * tRes], y)) + terrainObj.transform.position; } } var index = 0; // Build triangle indices: 3 indices into vertex array for each triangle for (int y = 0; y < h - 1; y++) { for (int x = 0; x < w - 1; x++) { // For each grid cell output two triangles tPolys[index++] = (y * w) + x; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = (y * w) + x + 1; tPolys[index++] = ((y + 1) * w) + x; tPolys[index++] = ((y + 1) * w) + x + 1; tPolys[index++] = (y * w) + x + 1; } } int subTotalVerts = geom.NumVertexes; foreach (var tVertex in tVertices) { geom.Vertexes.Add(new RecastVertex(tVertex.x, tVertex.y, tVertex.z)); geom.NumVertexes++; } for (int j = 0; j < tPolys.Length; j += 3) { geom.Triangles.Add(tPolys[j] + subTotalVerts); geom.Triangles.Add(tPolys[j + 1] + subTotalVerts); geom.Triangles.Add(tPolys[j + 2] + subTotalVerts); geom.NumTriangles++; } } foreach (var componentsInChild in gameObject.GetComponentsInChildren<MeshFilter>()) { int subTotalVerts = geom.NumVertexes; foreach (Vector3 vector3 in componentsInChild.sharedMesh.vertices) { Vector3 vec = gameObject.transform.TransformPoint(vector3); geom.Vertexes.Add(new RecastVertex(vec.x, vec.y, vec.z)); geom.NumVertexes++; } for (int j = 0; j < componentsInChild.sharedMesh.triangles.Length; j += 3) { geom.Triangles.Add(componentsInChild.sharedMesh.triangles[j] + subTotalVerts); geom.Triangles.Add(componentsInChild.sharedMesh.triangles[j + 1] + subTotalVerts); geom.Triangles.Add(componentsInChild.sharedMesh.triangles[j + 2] + subTotalVerts); geom.NumTriangles++; } } foreach (var offMeshConnector in gameObject.GetComponentsInChildren<OffMeshConnector>()) { RecastVertex start = new RecastVertex(offMeshConnector.StartPosition.x, offMeshConnector.StartPosition.y, offMeshConnector.StartPosition.z); RecastVertex end = new RecastVertex(offMeshConnector.EndPosition.x, offMeshConnector.EndPosition.y, offMeshConnector.EndPosition.z); geom.AddOffMeshConnection(start, end, offMeshConnector.Radius, offMeshConnector.Bidirectional, 5, 8); } } } } if (geom.NumVertexes != 0) { geom.CalculateBounds(); config.CalculateGridSize(geom); geom.CreateChunkyTriMesh(); } }
public void BuildTile(int x, int y) { RecastVertex bmin = Geometry.MinBounds; RecastVertex bmax = Geometry.MaxBounds; float tcs = Config.TileSize * Config.CellSize; RecastVertex tileBMin = new RecastVertex(); RecastVertex tileBMax = new RecastVertex(); tileBMin.X = bmin.X + x * tcs; tileBMin.Y = bmin.Y; tileBMin.Z = bmin.Z + y * tcs; tileBMax.X = bmin.X + (x + 1) * tcs; tileBMax.Y = bmax.Y; tileBMax.Z = bmin.Z + (y + 1) * tcs; var builder = BuildTileMesh(x, y, tileBMin, tileBMax); // remove/add new tile? if (builder != null) { Detour.AtavismNavTile outBuilder; // nav mesh remove tile NavMesh.RemoveTile(NavMesh.GetTileRefAt(x, y, 0), out outBuilder); // nav mesh add tile long result = 0; NavMesh.AddTile(builder, NavMesh.TileFreeData, 0, ref result); } }
public void RebuildTiles() { Progress = 0; IsBuilding = true; RecastVertex bmin = Geometry.MinBounds; RecastVertex bmax = Geometry.MaxBounds; RecastVertex tileBMin = new RecastVertex(); RecastVertex tileBMax = new RecastVertex(); float tcs = Config.TileSize * Config.CellSize; Total = TileWidth * TileHeight; for (int y = 0; y < TileHeight; y++) { for (int x = 0; x < TileWidth; x++) { Progress = y * TileWidth + x; tileBMin.X = bmin.X + x * tcs; tileBMin.Y = bmin.Y; tileBMin.Z = bmin.Z + y * tcs; tileBMax.X = bmin.X + (x + 1) * tcs; tileBMax.Y = bmax.Y; tileBMax.Z = bmin.Z + (y + 1) * tcs; #if UNITY_EDITOR EditorUtility.DisplayProgressBar("Generating...", "Generating Tile " + Progress + " of " + Total, Progress / (float)Total); #endif var builder = BuildTileMesh(x, y, tileBMin, tileBMax); // remove/add new tile? if (builder != null) { Detour.AtavismNavTile outBuilder; // nav mesh remove tile NavMesh.RemoveTile(NavMesh.GetTileRefAt(x, y, 0), out outBuilder); // nav mesh add tile long result = 0; NavMesh.AddTile(builder, NavMesh.TileFreeData, 0, ref result); } } } #if UNITY_EDITOR EditorUtility.ClearProgressBar(); #endif IsBuilding = false; BuildGeometry(); }
private void YLoop(int y, float tcs, RecastVertex bmin, RecastVertex bmax) { bool canceled = false; #if UNITY_EDITOR for (int x = 0; x < TileWidth; x++) { canceled = EditorUtility.DisplayCancelableProgressBar("Generating...", "Generating Tile " + Progress + " of " + Total, Progress / (float)Total); if (canceled) { tokenSource.Cancel(); break; } Xloop(y, x, tcs, bmin, bmax); } #endif }
private void Xloop(int y, int x, float tcs, RecastVertex bmin, RecastVertex bmax) { RecastVertex tileBMin = new RecastVertex(); RecastVertex tileBMax = new RecastVertex(); tileBMin.X = bmin.X + x*tcs; tileBMin.Y = bmin.Y; tileBMin.Z = bmin.Z + y*tcs; tileBMax.X = bmin.X + (x + 1)*tcs; tileBMax.Y = bmax.Y; tileBMax.Z = bmin.Z + (y + 1)*tcs; #if UNITY_EDITOR bool canceled = EditorUtility.DisplayCancelableProgressBar("Generating...", "Generating Tile " + Progress + " of " + Total, Progress / (float)Total); if (canceled) { tokenSource.Cancel(); } #endif var t = Task.Factory.StartNew(() => BuildTile(x, y, tileBMin, tileBMax), tokenSource.Token, TaskCreationOptions.LongRunning, scheduler); tasks.Add(t); }
private Detour.AtavismNavTile BuildTileMesh(int tx, int ty, RecastVertex min, RecastVertex max) { Config.Width = Config.TileSize + Config.BorderSize * 2; Config.Height = Config.TileSize + Config.BorderSize * 2; Config.MinBounds = min; Config.MaxBounds = max; Config.MinBounds.X -= Config.BorderSize * Config.CellSize; Config.MinBounds.Z -= Config.BorderSize * Config.CellSize; Config.MaxBounds.X += Config.BorderSize * Config.CellSize; Config.MaxBounds.Z += Config.BorderSize * Config.CellSize; HeightField heightfield = new HeightField(Config.Width, Config.Height, Config.MinBounds.ToArray(), Config.MaxBounds.ToArray(), Config.CellSize, Config.CellHeight); short[] triAreas = new short[Geometry.ChunkyTriMesh.MaxTrisPerChunk]; float[] tbmin = new float[2], tbmax = new float[2]; tbmin[0] = Config.MinBounds.X; tbmin[1] = Config.MinBounds.Z; tbmax[0] = Config.MaxBounds.X; tbmax[1] = Config.MaxBounds.Z; int[] cid = new int[512]; int ncid = Geometry.ChunkyTriMesh.GetChunksOverlappingRect(tbmin, tbmax, ref cid, 512); if (ncid == 0) return null; for (int i = 0; i < ncid; i++) { ChunkyTriMeshNode node = Geometry.ChunkyTriMesh.Nodes[cid[i]]; int[] tris = new int[node.n * 3]; Array.Copy(Geometry.ChunkyTriMesh.Tris, node.i * 3, tris, 0, node.n * 3); List<int> ctris = new List<int>(tris); int nctris = node.n; Array.Clear(triAreas, 0, triAreas.Length); Geometry.MarkWalkableTriangles(Config.WalkableSlopeAngle, ctris, nctris, ref triAreas); heightfield.RasterizeTriangles(Geometry, ctris, nctris, triAreas, Config.WalkableClimb); } heightfield.FilterLowHangingWalkableObstacles(Config.WalkableClimb); heightfield.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb); heightfield.FilterWalkableLowHeightSpans(Config.WalkableHeight); CompactHeightfield compactHeightfield = new CompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, heightfield); compactHeightfield.ErodeWalkableArea(Config.WalkableRadius); // optional convex volumes compactHeightfield.BuildDistanceField(); compactHeightfield.BuildRegions(Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea); ContourSet contourSet = new ContourSet(compactHeightfield, Config.MaxSimplificationError, Config.MaxEdgeLength); if (contourSet.NConts == 0) return null; PolyMesh polyMesh = new PolyMesh(contourSet, Config.MaxVertexesPerPoly); DetailPolyMesh detailPolyMesh = new DetailPolyMesh(polyMesh, compactHeightfield, Config.DetailSampleDistance, Config.DetailSampleMaxError); // Convert the Areas and Flags for path weighting for (int i = 0; i < polyMesh.NPolys; i++) { if (polyMesh.Areas[i] == Geometry.WalkableArea) { polyMesh.Areas[i] = 0; // Sample_polyarea_ground polyMesh.Flags[i] = 1; // Samply_polyflags_walk } } NavMeshCreateParams param = new NavMeshCreateParams { Verts = polyMesh.Verts, VertCount = polyMesh.NVerts, Polys = polyMesh.Polys, PolyAreas = polyMesh.Areas, PolyFlags = polyMesh.Flags, PolyCount = polyMesh.NPolys, Nvp = polyMesh.Nvp, DetailMeshes = detailPolyMesh.Meshes, DetailVerts = detailPolyMesh.Verts, DetailVertsCount = detailPolyMesh.NVerts, DetailTris = detailPolyMesh.Tris, DetailTriCount = detailPolyMesh.NTris, // Off Mesh data OffMeshConVerts = Geometry.OffMeshConnectionVerts.ToArray(), OffMeshConRad = Geometry.OffMeshConnectionRadii.ToArray(), OffMeshConDir = Geometry.OffMeshConnectionDirections.ToArray(), OffMeshConAreas = Geometry.OffMeshConnectionAreas.ToArray(), OffMeshConFlags = Geometry.OffMeshConnectionFlags.ToArray(), OffMeshConUserId = Geometry.OffMeshConnectionIds.ToArray(), OffMeshConCount = (int)Geometry.OffMeshConnectionCount, // end off mesh data WalkableHeight = Config.WalkableHeight, WalkableRadius = Config.WalkableRadius, WalkableClimb = Config.WalkableClimb, BMin = new float[] { polyMesh.BMin[0], polyMesh.BMin[1], polyMesh.BMin[2] }, BMax = new float[] { polyMesh.BMax[0], polyMesh.BMax[1], polyMesh.BMax[2] }, Cs = polyMesh.Cs, Ch = polyMesh.Ch, BuildBvTree = true, TileX = tx, TileY = ty, TileLayer = 0 }; return new Detour.AtavismNavTile(param); }
private LunaNav.NavMeshBuilder BuildTileMesh(int tx, int ty, RecastVertex min, RecastVertex max) { Config.Width = Config.TileSize + Config.BorderSize * 2; Config.Height = Config.TileSize + Config.BorderSize * 2; Config.MinBounds = min; Config.MaxBounds = max; Config.MinBounds.X -= Config.BorderSize * Config.CellSize; Config.MinBounds.Z -= Config.BorderSize * Config.CellSize; Config.MaxBounds.X += Config.BorderSize * Config.CellSize; Config.MaxBounds.Z += Config.BorderSize * Config.CellSize; HeightField heightfield = new HeightField(Config.Width, Config.Height, Config.MinBounds.ToArray(), Config.MaxBounds.ToArray(), Config.CellSize, Config.CellHeight); short[] triAreas = new short[Geometry.ChunkyTriMesh.MaxTrisPerChunk]; float[] tbmin = new float[2], tbmax = new float[2]; tbmin[0] = Config.MinBounds.X; tbmin[1] = Config.MinBounds.Z; tbmax[0] = Config.MaxBounds.X; tbmax[1] = Config.MaxBounds.Z; int[] cid = new int[512]; int ncid = Geometry.ChunkyTriMesh.GetChunksOverlappingRect(tbmin, tbmax, ref cid, 512); if (ncid == 0) { return(null); } for (int i = 0; i < ncid; i++) { ChunkyTriMeshNode node = Geometry.ChunkyTriMesh.Nodes[cid[i]]; int[] tris = new int[node.n * 3]; Array.Copy(Geometry.ChunkyTriMesh.Tris, node.i * 3, tris, 0, node.n * 3); List <int> ctris = new List <int>(tris); int nctris = node.n; Array.Clear(triAreas, 0, triAreas.Length); Geometry.MarkWalkableTriangles(Config.WalkableSlopeAngle, ctris, nctris, ref triAreas); heightfield.RasterizeTriangles(Geometry, ctris, nctris, triAreas, Config.WalkableClimb); } heightfield.FilterLowHangingWalkableObstacles(Config.WalkableClimb); heightfield.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb); heightfield.FilterWalkableLowHeightSpans(Config.WalkableHeight); CompactHeightfield compactHeightfield = new CompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, heightfield); compactHeightfield.ErodeWalkableArea(Config.WalkableRadius); // optional convex volumes compactHeightfield.BuildDistanceField(); compactHeightfield.BuildRegions(Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea); ContourSet contourSet = new ContourSet(compactHeightfield, Config.MaxSimplificationError, Config.MaxEdgeLength); if (contourSet.NConts == 0) { return(null); } PolyMesh polyMesh = new PolyMesh(contourSet, Config.MaxVertexesPerPoly); DetailPolyMesh detailPolyMesh = new DetailPolyMesh(polyMesh, compactHeightfield, Config.DetailSampleDistance, Config.DetailSampleMaxError); // Convert the Areas and Flags for path weighting for (int i = 0; i < polyMesh.NPolys; i++) { if (polyMesh.Areas[i] == Geometry.WalkableArea) { polyMesh.Areas[i] = 0; // Sample_polyarea_ground polyMesh.Flags[i] = 1; // Samply_polyflags_walk } } NavMeshCreateParams param = new NavMeshCreateParams { Verts = polyMesh.Verts, VertCount = polyMesh.NVerts, Polys = polyMesh.Polys, PolyAreas = polyMesh.Areas, PolyFlags = polyMesh.Flags, PolyCount = polyMesh.NPolys, Nvp = polyMesh.Nvp, DetailMeshes = detailPolyMesh.Meshes, DetailVerts = detailPolyMesh.Verts, DetailVertsCount = detailPolyMesh.NVerts, DetailTris = detailPolyMesh.Tris, DetailTriCount = detailPolyMesh.NTris, // Off Mesh data OffMeshConVerts = Geometry.OffMeshConnectionVerts.ToArray(), OffMeshConRad = Geometry.OffMeshConnectionRadii.ToArray(), OffMeshConDir = Geometry.OffMeshConnectionDirections.ToArray(), OffMeshConAreas = Geometry.OffMeshConnectionAreas.ToArray(), OffMeshConFlags = Geometry.OffMeshConnectionFlags.ToArray(), OffMeshConUserId = Geometry.OffMeshConnectionIds.ToArray(), OffMeshConCount = (int)Geometry.OffMeshConnectionCount, // end off mesh data WalkableHeight = Config.WalkableHeight, WalkableRadius = Config.WalkableRadius, WalkableClimb = Config.WalkableClimb, BMin = new float[] { polyMesh.BMin[0], polyMesh.BMin[1], polyMesh.BMin[2] }, BMax = new float[] { polyMesh.BMax[0], polyMesh.BMax[1], polyMesh.BMax[2] }, Cs = polyMesh.Cs, Ch = polyMesh.Ch, BuildBvTree = true, TileX = tx, TileY = ty, TileLayer = 0 }; return(new LunaNav.NavMeshBuilder(param)); }
private void RasterizeTriangle(List <RecastVertex> vertexes, int v0, int v1, int v2, short area, float ics, float ich, int flagMergeThr) { int w = Width; int h = Height; RecastVertex tempMin, tempMax; float by = Bmax[1] - Bmin[1]; tempMin = new RecastVertex(vertexes[v0]); tempMax = new RecastVertex(vertexes[v0]); tempMin = RecastVertex.Min(tempMin, vertexes[v1]); tempMin = RecastVertex.Min(tempMin, vertexes[v2]); tempMax = RecastVertex.Max(tempMax, vertexes[v1]); tempMax = RecastVertex.Max(tempMax, vertexes[v2]); if (!OverlapBounds(Bmin, Bmax, tempMin.ToArray(), tempMax.ToArray())) { return; } int x0 = (int)((tempMin[0] - Bmin[0]) * ics); int y0 = (int)((tempMin[2] - Bmin[2]) * ics); int x1 = (int)((tempMax[0] - Bmin[0]) * ics); int y1 = (int)((tempMax[2] - Bmin[2]) * ics); x0 = Math.Max(0, Math.Min(x0, w - 1)); y0 = Math.Max(0, Math.Min(y0, h - 1)); x1 = Math.Max(0, Math.Min(x1, w - 1)); y1 = Math.Max(0, Math.Min(y1, h - 1)); float[] inArray = new float[7 * 3], outArray = new float[7 * 3], inrowArray = new float[7 * 3]; for (int y = y0; y <= y1; y++) { Array.Copy(vertexes[v0].ToArray(), 0, inArray, 0, 3); Array.Copy(vertexes[v1].ToArray(), 0, inArray, 1 * 3, 3); Array.Copy(vertexes[v2].ToArray(), 0, inArray, 2 * 3, 3); int nvrow = 3; float cz = Bmin[2] + y * Cs; nvrow = ClipPoly(inArray, nvrow, ref outArray, 0, 1, -cz); if (nvrow < 3) { continue; } nvrow = ClipPoly(outArray, nvrow, ref inrowArray, 0, -1, cz + Cs); if (nvrow < 3) { continue; } for (int x = x0; x <= x1; x++) { int nv = nvrow; float cx = Bmin[0] + x * Cs; nv = ClipPoly(inrowArray, nv, ref outArray, 1, 0, -cx); if (nv < 3) { continue; } nv = ClipPoly(outArray, nv, ref inArray, -1, 0, cx + Cs); if (nv < 3) { continue; } float smin = inArray[1], smax = inArray[1]; for (int i = 1; i < nv; i++) { smin = Math.Min(smin, inArray[i * 3 + 1]); smax = Math.Max(smax, inArray[i * 3 + 1]); } smin -= Bmin[1]; smax -= Bmin[1]; if (smax.CompareTo(0.0f) < 0 || smin.CompareTo(by) > 0) { continue; } if (smin.CompareTo(0.0f) < 0) { smin = 0; } if (smax.CompareTo(by) > 0) { smax = by; } int ismin = Math.Max(0, Math.Min((int)Math.Floor(smin * ich), short.MaxValue)); int ismax = Math.Max(ismin + 1, Math.Min((int)Math.Floor(smax * ich), short.MaxValue)); AddSpan(x, y, ismin, ismax, area, flagMergeThr); } } }