private void BuildContours() { ContourSet cset = ContourSet.Build(mBuildContext , mBuildContext.CompactField , mConfig.EdgeMaxDeviation , mConfig.MaxEdgeLength , mConfig.ContourOptions); if (cset == null) { FinalizeAbort("Aborted at contour set build."); return; } if (cset.Count < 1) { FinalizeNoResult("Completed after contour build. No useable contours generated."); return; } mBuildContext.Contours = cset; if (PostProcess() && PostContoursCheck() && PostCompactFieldCheck()) { mBuildContext.Log("Built contour set. Contour count: " + cset.Count, this); mState = NMGenState.PolyMeshBuild; } }
/// <summary> /// Constructor /// </summary> /// <remarks> /// <para> /// A 'no result' object will be created if the <paramref name="polyMesh"/> parameter /// is null or has a polygon count of zero. /// </para> /// </remarks> /// <param name="tx">The x-index of the tile within the tile grid. (tx, tz)</param> /// <param name="tz">The z-index of the tile within the tile grid. (tx, tz)</param> /// <param name="polyMesh">The polymesh.</param> /// <param name="detailMesh">The detail mesh.</param> /// <param name="heightfield">The heightfield.</param> /// <param name="compactField">The compact field.</param> /// <param name="contours">The contour set.</param> public NMGenAssets(int tx, int tz , PolyMesh polyMesh , PolyMeshDetail detailMesh , Heightfield heightfield , CompactHeightfield compactField , ContourSet contours) { mTileX = tx; mTileZ = tz; if (polyMesh == null || polyMesh.PolyCount == 0) { mPolyMesh = null; mDetailMesh = null; mHeightfield = null; mCompactField = null; mContours = null; } else { mPolyMesh = polyMesh; mDetailMesh = detailMesh; // OK to be null. mHeightfield = heightfield; mCompactField = compactField; mContours = contours; } }
public NavMeshBuilder GenerateNavmesh(BBox3 bbox) { float[] vertices; int[] indices; AreaId[] areas; GetRawData(out vertices, out indices, out areas); var settings = WoWSettings; var hf = new Heightfield(bbox, settings); hf.RasterizeTrianglesWithAreas(vertices, areas); hf.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); hf.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); hf.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); var chf = new CompactHeightfield(hf, settings); chf.Erode(settings.VoxelAgentWidth); chf.BuildDistanceField(); chf.BuildRegions((int)(settings.AgentWidth / settings.CellSize) + 8, settings.MinRegionSize, settings.MergedRegionSize); var cset = new ContourSet(chf, settings); var pmesh = new PolyMesh(cset, settings); var dmesh = new PolyMeshDetail(pmesh, chf, settings); var buildData = new NavMeshBuilder(pmesh, dmesh, new SharpNav.Pathfinding.OffMeshConnection[0], settings); return(buildData); }
/// <summary> /// Sets the context as having produced no result. /// </summary> public void SetAsNoResult() { mHeightfield = null; mCompactField = null; mContours = null; mPolyMesh = null; mDetailMesh = null; mNoResult = true; }
//private void GenerateNavMesh() //{ // Console.WriteLine("Generating NavMesh"); // long prevMs = 0; // try // { // var levelTris = level.GetTriangles(); // var triEnumerable = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length); // BBox3 bounds = triEnumerable.GetBoundingBox(); // settings = NavMeshGenerationSettings.Default; // heightfield = new Heightfield(bounds, settings); // heightfield.RasterizeTriangles(levelTris, Area.Default); // heightfield.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); // heightfield.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); // heightfield.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); // compactHeightfield = new CompactHeightfield(heightfield, settings); // compactHeightfield.Erode(settings.VoxelAgentRadius); // compactHeightfield.BuildDistanceField(); // compactHeightfield.BuildRegions(0, settings.MinRegionSize, settings.MergedRegionSize); // contourSet = compactHeightfield.BuildContourSet(settings); // polyMesh = new PolyMesh(contourSet, settings); // polyMeshDetail = new PolyMeshDetail(polyMesh, compactHeightfield, settings); // buildData = new NavMeshBuilder(polyMesh, polyMeshDetail, new SharpNav.Pathfinding.OffMeshConnection[0], settings); // tiledNavMesh = new TiledNavMesh(buildData); // navMeshQuery = new NavMeshQuery(tiledNavMesh, 2048); // } // catch (Exception e) // { // //if (!interceptExceptions) // // throw; // //else // // Console.WriteLine("Navmesh generation failed with exception:" + Environment.NewLine + e.ToString()); // } // finally // { // //sw.Stop(); // } //} private void GenerateNavMesh() { Console.WriteLine("Generating NavMesh"); long prevMs = 0; //try //{ var levelTris = level.GetTriangles(); var triEnumerable = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length); BBox3 bounds = triEnumerable.GetBoundingBox(); settings = NavMeshGenerationSettings.Default; heightfield = new Heightfield(bounds, settings); heightfield.RasterizeTriangles(levelTris, Area.Default); heightfield.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); heightfield.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); heightfield.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); compactHeightfield = new CompactHeightfield(heightfield, settings); compactHeightfield.Erode(settings.VoxelAgentRadius); compactHeightfield.BuildDistanceField(); compactHeightfield.BuildRegions(0, settings.MinRegionSize, settings.MergedRegionSize); contourSet = compactHeightfield.BuildContourSet(settings); polyMesh = new PolyMesh(contourSet, settings); polyMeshDetail = new PolyMeshDetail(polyMesh, compactHeightfield, settings); buildData = new NavMeshBuilder(polyMesh, polyMeshDetail, new SharpNav.Pathfinding.OffMeshConnection[0], settings); tiledNavMesh = new TiledNavMesh(buildData); navMeshQuery = new NavMeshQuery(tiledNavMesh, 2048); OutMesh(); //} //catch (Exception e) //{ // //if (!interceptExceptions) // // throw; // //else // // Console.WriteLine("Navmesh generation failed with exception:" + Environment.NewLine + e.ToString()); //} //finally //{ // //sw.Stop(); //} }
private bool PostContoursCheck() { ContourSet contours = mBuildContext.Contours; if (contours == null || contours.IsDisposed) { FinalizeAbort("Custom processors destroyed the contour set. (" + mState + " Post)"); return(false); } else if (contours.Count < 1) { FinalizeNoResult( "Aborted after contour set build. No contours generated. (" + mState + " Post)"); return(false); } return(true); }
public void ContourConstructor() { //TODO directly build contours now that ContourSet allows it. //Build a 5x5 heightfield Heightfield hf = new Heightfield(new BBox3(Vector3.Zero, Vector3.One), (float)(1.0f / 5.0f), 0.02f); for (int i = 0; i < 5 * 5; i++) { hf[i].AddSpan(new Span(10, 20, Area.Default)); hf[i].AddSpan(new Span(25, 30, Area.Default)); } CompactHeightfield chf = new CompactHeightfield(hf, 2, 1); chf.BuildDistanceField(); chf.BuildRegions(1, 1, 1); ContourSet contourSet = chf.BuildContourSet(1, 5, ContourBuildFlags.None); Assert.AreEqual(contourSet.Count, 2); }
private void BuildPolyMesh() { ContourSet cset = mBuildContext.Contours; PolyMesh polyMesh = PolyMesh.Build(mBuildContext , cset , mConfig.MaxVertsPerPoly , mConfig.WalkableHeight , mConfig.WalkableRadius , mConfig.WalkableStep); if (CanDispose(NMGenAssetFlag.ContourSet)) { cset.RequestDisposal(); mBuildContext.Contours = null; } if (polyMesh == null) { FinalizeAbort("Aborted at poly mesh build."); return; } if (polyMesh.PolyCount < 1) { FinalizeNoResult("Aborted after poly mesh build. No polygons generated."); return; } mBuildContext.PolyMesh = polyMesh; if (PostProcess() & PostPolyMeshCheck() & PostCompactFieldCheck()) { mBuildContext.Log("Built poly mesh. PolyCount: " + polyMesh.PolyCount, this); mState = NMGenState.DetailMeshBuild; } }
private void GenerateNavMesh() { Console.WriteLine("Generating NavMesh"); Stopwatch sw = new Stopwatch(); sw.Start(); long prevMs = 0; try { //level.SetBoundingBoxOffset(new SVector3(settings.CellSize * 0.5f, settings.CellHeight * 0.5f, settings.CellSize * 0.5f)); var levelTris = level.GetTriangles(); var triEnumerable = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length); BBox3 bounds = triEnumerable.GetBoundingBox(); heightfield = new Heightfield(bounds, settings); Console.WriteLine("Heightfield"); Console.WriteLine(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; /*Area[] areas = AreaGenerator.From(triEnumerable, Area.Default) .MarkAboveHeight(areaSettings.MaxLevelHeight, Area.Null) .MarkBelowHeight(areaSettings.MinLevelHeight, Area.Null) .MarkBelowSlope(areaSettings.MaxTriSlope, Area.Null) .ToArray(); heightfield.RasterizeTrianglesWithAreas(levelTris, areas);*/ heightfield.RasterizeTriangles(levelTris, Area.Default); Console.WriteLine(" + Rasterization\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); Console.WriteLine(" + Filtering"); prevMs = sw.ElapsedMilliseconds; heightfield.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); Console.WriteLine(" + Ledge Spans\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; heightfield.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); Console.WriteLine(" + Low Hanging Obstacles\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; heightfield.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); Console.WriteLine(" + Low Height Spans\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield = new CompactHeightfield(heightfield, settings); Console.WriteLine("CompactHeightfield"); Console.WriteLine(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield.Erode(settings.VoxelAgentRadius); Console.WriteLine(" + Erosion\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield.BuildDistanceField(); Console.WriteLine(" + Distance Field\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield.BuildRegions(0, settings.MinRegionSize, settings.MergedRegionSize); Console.WriteLine(" + Regions\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; Random r = new Random(); regionColors = new Color4[compactHeightfield.MaxRegions]; regionColors[0] = Color4.Black; for (int i = 1; i < regionColors.Length; i++) regionColors[i] = new Color4((byte)r.Next(0, 255), (byte)r.Next(0, 255), (byte)r.Next(0, 255), 255); Console.WriteLine(" + Colors\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; contourSet = compactHeightfield.BuildContourSet(settings); Console.WriteLine("ContourSet"); Console.WriteLine(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; polyMesh = new PolyMesh(contourSet, settings); Console.WriteLine("PolyMesh"); Console.WriteLine(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; polyMeshDetail = new PolyMeshDetail(polyMesh, compactHeightfield, settings); Console.WriteLine("PolyMeshDetail"); Console.WriteLine(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; hasGenerated = true; } catch (Exception e) { if (!interceptExceptions) throw; else Console.WriteLine("Navmesh generation failed with exception:" + Environment.NewLine + e.ToString()); } finally { sw.Stop(); } if (hasGenerated) { try { GeneratePathfinding(); //Pathfinding with multiple units GenerateCrowd(); } catch (Exception e) { Console.WriteLine("Pathfinding generation failed with exception" + Environment.NewLine + e.ToString()); hasGenerated = false; } Label l = (Label)statusBar.FindChildByName("GenTime"); l.Text = "Generation Time: " + sw.ElapsedMilliseconds + "ms"; Console.WriteLine("Navmesh generated successfully in " + sw.ElapsedMilliseconds + "ms."); Console.WriteLine("Rasterized " + level.GetTriangles().Length + " triangles."); Console.WriteLine("Generated " + contourSet.Count + " regions."); Console.WriteLine("PolyMesh contains " + polyMesh.VertCount + " vertices in " + polyMesh.PolyCount + " polys."); Console.WriteLine("PolyMeshDetail contains " + polyMeshDetail.VertCount + " vertices and " + polyMeshDetail.TrisCount + " tris in " + polyMeshDetail.MeshCount + " meshes."); } }
private void GenerateNavMesh() { //Debug.Log("Generating NavMesh"); Stopwatch sw = new Stopwatch(); sw.Start(); long prevMs = 0; try { //level.SetBoundingBoxOffset(new SVector3(settings.CellSize * 0.5f, settings.CellHeight * 0.5f, settings.CellSize * 0.5f)); var levelTris = level.GetTriangles(); var triEnumerable = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length); BBox3 bounds = triEnumerable.GetBoundingBox(); heightfield = new Heightfield(bounds, settings); //Debug.Log("Heightfield"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; /*Area[] areas = AreaGenerator.From(triEnumerable, Area.Default) * .MarkAboveHeight(areaSettings.MaxLevelHeight, Area.Null) * .MarkBelowHeight(areaSettings.MinLevelHeight, Area.Null) * .MarkBelowSlope(areaSettings.MaxTriSlope, Area.Null) * .ToArray(); * heightfield.RasterizeTrianglesWithAreas(levelTris, areas);*/ heightfield.RasterizeTriangles(levelTris, Area.Default); //Debug.Log(" + Rasterization\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); //Debug.Log(" + Filtering"); prevMs = sw.ElapsedMilliseconds; heightfield.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); //Debug.Log(" + Ledge Spans\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; heightfield.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); //Debug.Log(" + Low Hanging Obstacles\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; heightfield.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); //Debug.Log(" + Low Height Spans\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield = new CompactHeightfield(heightfield, settings); //Debug.Log("CompactHeightfield"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield.Erode(settings.VoxelAgentRadius); //Debug.Log(" + Erosion\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield.BuildDistanceField(); //Debug.Log(" + Distance Field\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield.BuildRegions(0, settings.MinRegionSize, settings.MergedRegionSize); //Debug.Log(" + Regions\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; contourSet = compactHeightfield.BuildContourSet(settings); //Debug.Log("ContourSet"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; polyMesh = new PolyMesh(contourSet, settings); //Debug.Log("PolyMesh"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; polyMeshDetail = new PolyMeshDetail(polyMesh, compactHeightfield, settings); //Debug.Log("PolyMeshDetail"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; hasGenerated = true; } catch (Exception e) { if (!interceptExceptions) { throw; } else { //Debug.Log("Navmesh generation failed with exception:" + Environment.NewLine + e.ToString()); } } finally { sw.Stop(); } if (hasGenerated) { try { GeneratePathfinding(); //Pathfinding with multiple units //GenerateCrowd(); } catch (Exception e) { //Debug.Log("Pathfinding generation failed with exception" + Environment.NewLine + e.ToString()); hasGenerated = false; } //Label l = (Label)statusBar.FindChildByName("GenTime"); //l.Text = "Generation Time: " + sw.ElapsedMilliseconds + "ms"; //Debug.Log("Navmesh generated successfully in " + sw.ElapsedMilliseconds + "ms."); //Debug.Log("Rasterized " + level.GetTriangles().Length + " triangles."); //Debug.Log("Generated " + contourSet.Count + " regions."); //Debug.Log("PolyMesh contains " + polyMesh.VertCount + " vertices in " + polyMesh.PolyCount + " polys."); //Debug.Log("PolyMeshDetail contains " + polyMeshDetail.VertCount + " vertices and " + polyMeshDetail.TrisCount + " tris in " + polyMeshDetail.MeshCount + " meshes."); } }
public void GenNavMesh() { // MeshCollider List <Triangle3> colliderTringles = new List <Triangle3>(); Collider[] colliders = GameObject.FindObjectsOfType <Collider>(); List <GameObject> destroyGos = new List <GameObject>(); foreach (Collider collider in colliders) { Mesh mesh = null; Matrix4x4 localToWorldMatrix = Matrix4x4.identity; if (collider is MeshCollider) { MeshCollider mc = collider as MeshCollider; mesh = mc.sharedMesh; localToWorldMatrix = mc.transform.localToWorldMatrix; } if (collider is BoxCollider) { BoxCollider bc = collider as BoxCollider; GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); mesh = go.GetComponent <MeshFilter>().sharedMesh; go.transform.parent = collider.transform; go.transform.localRotation = Quaternion.identity; go.transform.localPosition = bc.center; go.transform.localScale = bc.size; localToWorldMatrix = go.transform.localToWorldMatrix; destroyGos.Add(go); } if (null != mesh) { UnityEngine.Vector3[] vertices = mesh.vertices; for (int i = 0; i < mesh.subMeshCount; ++i) { var subMesh = mesh.GetIndices(i); for (int j = 0; j < subMesh.Length; j += 3) { UnityEngine.Vector3 a = localToWorldMatrix.MultiplyPoint(vertices[subMesh[j]]); UnityEngine.Vector3 b = localToWorldMatrix.MultiplyPoint(vertices[subMesh[j + 1]]); UnityEngine.Vector3 c = localToWorldMatrix.MultiplyPoint(vertices[subMesh[j + 2]]); colliderTringles.Add(new Triangle3(ConvertVector3(a), ConvertVector3(b), ConvertVector3(c))); } } } } foreach (var go in destroyGos) { GameObject.DestroyImmediate(go); } destroyGos.Clear(); Triangle3[] levelTris = colliderTringles.ToArray(); var triEnumerable = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length); BBox3 bounds = triEnumerable.GetBoundingBox(); heightfield = new Heightfield(bounds, settings); heightfield.RasterizeTriangles(levelTris, Area.Default); heightfield.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); heightfield.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); heightfield.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); compactHeightfield = new CompactHeightfield(heightfield, settings); compactHeightfield.Erode(settings.VoxelAgentRadius); compactHeightfield.BuildDistanceField(); compactHeightfield.BuildRegions(0, settings.MinRegionSize, settings.MergedRegionSize); contourSet = compactHeightfield.BuildContourSet(settings); polyMesh = new PolyMesh(contourSet, settings); polyMeshDetail = new PolyMeshDetail(polyMesh, compactHeightfield, settings); buildData = new NavMeshBuilder(polyMesh, polyMeshDetail, new SharpNav.Pathfinding.OffMeshConnection[0], settings); tiledNavMesh = new TiledNavMesh(buildData); navMeshQuery = new NavMeshQuery(tiledNavMesh, 2048); { System.Random r = new System.Random(); regionColors = new Color[compactHeightfield.MaxRegions]; regionColors[0] = Color.black; for (int i = 1; i < regionColors.Length; i++) { regionColors[i] = new Color((byte)r.Next(0, 255), (byte)r.Next(0, 255), (byte)r.Next(0, 255), 255); } } this.GenDrawMesh(); Debug.Log("GenNavMesh Done!"); }
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)); }
/// <summary> /// Initializes a new instance of the <see cref="PolyMesh"/> class by creating polygons from contours. /// </summary> /// <param name="contSet">The <see cref="ContourSet"/> to generate polygons from.</param> /// <param name="cellSize">The size of one voxel/cell.</param> /// <param name="cellHeight">The height of one voxel/cell.</param> /// <param name="borderSize">The size of the border around the mesh.</param> /// <param name="numVertsPerPoly">The maximum number of vertices per polygon.</param> public PolyMesh(ContourSet contSet, float cellSize, float cellHeight, int borderSize, int numVertsPerPoly) { //copy contour data this.bounds = contSet.Bounds; this.cellSize = cellSize; this.cellHeight = cellHeight; this.borderSize = borderSize; //get maximum limits //TODO move to ContourSet? int maxVertices = 0; int maxTris = 0; int maxVertsPerCont = 0; foreach (var cont in contSet) { int vertCount = cont.Vertices.Length; //skip null contours if (vertCount < 3) continue; maxVertices += vertCount; maxTris += vertCount - 2; maxVertsPerCont = Math.Max(maxVertsPerCont, vertCount); } //initialize the mesh members var verts = new List<PolyVertex>(maxVertices); var polys = new List<Polygon>(maxTris); Queue<int> vertRemoveQueue = new Queue<int>(maxVertices); this.numVertsPerPoly = numVertsPerPoly; var vertDict = new Dictionary<PolyVertex, int>(new PolyVertex.RoughYEqualityComparer(2)); int[] indices = new int[maxVertsPerCont]; //keep track of vertex hash codes Triangle[] tris = new Triangle[maxVertsPerCont]; List<Polygon> contPolys = new List<Polygon>(maxVertsPerCont + 1); //extract contour data foreach (Contour cont in contSet) { //skip null contours if (cont.IsNull) continue; PolyVertex[] vertices = new PolyVertex[cont.Vertices.Length]; //triangulate contours for (int i = 0; i < cont.Vertices.Length; i++) { var cv = cont.Vertices[i]; vertices[i] = new PolyVertex(cv.X, cv.Y, cv.Z); indices[i] = i; } //Form triangles inside the area bounded by the contours int ntris = Triangulate(vertices, indices, tris); if (ntris <= 0) //TODO notify user when this happens. Logging? ntris = -ntris; //add and merge vertices for (int i = 0; i < cont.Vertices.Length; i++) { var cv = cont.Vertices[i]; var pv = vertices[i]; //save the hash code for each vertex indices[i] = AddVertex(vertDict, pv, verts); if (RegionId.HasFlags(cv.RegionId, RegionFlags.VertexBorder)) { //the vertex should be removed vertRemoveQueue.Enqueue(indices[i]); } } contPolys.Clear(); //iterate through all the triangles for (int i = 0; i < ntris; i++) { Triangle ti = tris[i]; //make sure there are three distinct vertices. anything less can't be a polygon. if (ti.Index0 == ti.Index1 || ti.Index0 == ti.Index2 || ti.Index1 == ti.Index2) continue; //each polygon has numVertsPerPoly //index 0, 1, 2 store triangle vertices //other polygon indexes (3 to numVertsPerPoly - 1) should be used for storing extra vertices when two polygons merge together Polygon p = new Polygon(numVertsPerPoly, Area.Null, RegionId.Null, 0); p.Vertices[0] = RemoveDiagonalFlag(indices[ti.Index0]); p.Vertices[1] = RemoveDiagonalFlag(indices[ti.Index1]); p.Vertices[2] = RemoveDiagonalFlag(indices[ti.Index2]); contPolys.Add(p); } //no polygons generated, so skip if (contPolys.Count == 0) continue; //merge polygons if (numVertsPerPoly > 3) { while (true) { //find best polygons int bestMergeVal = 0; int bestPolyA = 0, bestPolyB = 0, bestEdgeA = 0, bestEdgeB = 0; for (int i = 0; i < contPolys.Count - 1; i++) { int pj = i; for (int j = i + 1; j < contPolys.Count; j++) { int pk = j; int ea = 0, eb = 0; int v = GetPolyMergeValue(contPolys, pj, pk, verts, out ea, out eb); if (v > bestMergeVal) { bestMergeVal = v; bestPolyA = i; bestPolyB = j; bestEdgeA = ea; bestEdgeB = eb; } } } if (bestMergeVal > 0) { int pa = bestPolyA; int pb = bestPolyB; MergePolys(contPolys, pa, pb, bestEdgeA, bestEdgeB); contPolys[pb] = contPolys[contPolys.Count - 1]; contPolys.RemoveAt(contPolys.Count - 1); } else { //no more merging break; } } } //store polygons for (int i = 0; i < contPolys.Count; i++) { Polygon p = contPolys[i]; Polygon p2 = new Polygon(numVertsPerPoly, cont.Area, cont.RegionId, 0); Buffer.BlockCopy(p.Vertices, 0, p2.Vertices, 0, numVertsPerPoly * sizeof(int)); polys.Add(p2); } } //remove edge vertices while (vertRemoveQueue.Count > 0) { int i = vertRemoveQueue.Dequeue(); if (CanRemoveVertex(polys, i)) RemoveVertex(verts, polys, i); } //calculate adjacency (edges) BuildMeshAdjacency(verts, polys, numVertsPerPoly); //find portal edges if (this.borderSize > 0) { //iterate through all the polygons for (int i = 0; i < polys.Count; i++) { Polygon p = polys[i]; //iterate through all the vertices for (int j = 0; j < numVertsPerPoly; j++) { if (p.Vertices[j] == NullId) break; //skip connected edges if (p.NeighborEdges[j] != NullId) continue; int nj = j + 1; if (nj >= numVertsPerPoly || p.Vertices[nj] == NullId) nj = 0; //grab two consecutive vertices int va = p.Vertices[j]; int vb = p.Vertices[nj]; //set some flags if (verts[va].X == 0 && verts[vb].X == 0) p.NeighborEdges[j] = NeighborEdgeFlag | 0; else if (verts[va].Z == contSet.Height && verts[vb].Z == contSet.Height) p.NeighborEdges[j] = NeighborEdgeFlag | 1; else if (verts[va].X == contSet.Width && verts[vb].X == contSet.Width) p.NeighborEdges[j] = NeighborEdgeFlag | 2; else if (verts[va].Z == 0 && verts[vb].Z == 0) p.NeighborEdges[j] = NeighborEdgeFlag | 3; } } } this.vertices = verts.ToArray(); this.polygons = polys.ToArray(); }
//HACK borderSize is 0 here. Fix with borderSize. /// <summary> /// Initializes a new instance of the <see cref="PolyMesh"/> class. /// </summary> /// <param name="contSet">The <see cref="ContourSet"/> to generate polygons from.</param> /// <param name="settings">The settings to build with.</param> public PolyMesh(ContourSet contSet, NavMeshGenerationSettings settings) : this(contSet, settings.CellSize, settings.CellHeight, 0, settings.VertsPerPoly) { }
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); }