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 GenerateNavMesh() { Console.WriteLine("Generating NavMesh"); Stopwatch sw = new Stopwatch(); sw.Start(); long prevMs = 0; try { //level.SetBoundingBoxOffset(new Vector3(settings.CellSize * 0.5f, settings.CellHeight * 0.5f, settings.CellSize * 0.5f)); var levelTris = _level.Triangles().ToArray(); 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()); } 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.TriangleCount + " 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."); } }
public static extern bool rcpdBuildPolyMeshDetail(IntPtr context , ref PolyMeshEx polyMesh , [In] CompactHeightfield chf , float sampleDist , float sampleMaxError , [In, Out] PolyMeshDetail detailMesh);
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 Detour.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 Detour.NavMeshBuilder(param)); }
public static extern bool nmcsBuildSet(IntPtr context , [In] CompactHeightfield chf , float maxError , int maxEdgeLen , [In, Out] ContourSetEx cset , ContourBuildFlags flags);
public bool BuildNavMesh( out string error ) { DestroyNavMesh(); if( !EnabledInHierarchy ) { error = "Is not enabled."; return false; } //get geometry data var collector = GetAllGeometriesForNavigationMesh(); Vector3[] vertices = collector.resultVertices; int[] indices = collector.resultIndices; int vertexCount = collector.resultVertexCount; int indexCount = collector.resultIndexCount; if( vertexCount == 0 ) { error = "No vertices were gathered from collision objects."; return false; } //get settings var settings = new NavMeshGenerationSettings(); settings.CellSize = (float)CellSize; settings.CellHeight = (float)CellHeight; settings.MaxClimb = (float)AgentMaxClimb; settings.AgentHeight = (float)AgentHeight; settings.AgentRadius = (float)AgentRadius; settings.MinRegionSize = MinRegionSize; settings.MergedRegionSize = MergedRegionSize; settings.MaxEdgeLength = MaxEdgeLength; settings.MaxEdgeError = (float)MaxEdgeError; settings.VertsPerPoly = MaxVerticesPerPolygon; settings.SampleDistance = DetailSampleDistance; settings.MaxSampleError = DetailMaxSampleError; settings.BuildBoundingVolumeTree = true; TiledNavMesh newTiledNavMesh; try { //level.SetBoundingBoxOffset(new SVector3(settings.CellSize * 0.5f, settings.CellHeight * 0.5f, settings.CellSize * 0.5f)); var bounds = Bounds.Cleared; bounds.Add( vertices ); var heightfield = new Heightfield( ToSharpNav( bounds ), settings ); var vertices2 = new SharpNav.Geometry.Vector3[ indexCount ]; for( int index = 0; index < indexCount; index++ ) vertices2[ index ] = ToSharpNav( vertices[ indices[ index ] ] ); //Area[] areas = AreaGenerator.From( vertices2, Area.Default ) // .MarkBelowSlope( (float)AgentMaxSlope.Value.InRadians(), Area.Null ) // .ToArray(); //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( vertices2, areas ); heightfield.RasterizeTriangles( vertices2, Area.Default ); heightfield.FilterLedgeSpans( settings.VoxelAgentHeight, settings.VoxelMaxClimb ); heightfield.FilterLowHangingWalkableObstacles( settings.VoxelMaxClimb ); heightfield.FilterWalkableLowHeightSpans( settings.VoxelAgentHeight ); var compactHeightfield = new CompactHeightfield( heightfield, settings ); compactHeightfield.Erode( settings.VoxelAgentRadius ); compactHeightfield.BuildDistanceField(); compactHeightfield.BuildRegions( 0, settings.MinRegionSize, settings.MergedRegionSize ); //!!!! System.Random r = new System.Random(); var regionColors = new ColorByte[ compactHeightfield.MaxRegions ]; regionColors[ 0 ] = new ColorByte( 0, 0, 0 ); for( int i = 1; i < regionColors.Length; i++ ) regionColors[ i ] = new ColorByte( (byte)r.Next( 0, 255 ), (byte)r.Next( 0, 255 ), (byte)r.Next( 0, 255 ), (byte)255 ); var contourSet = compactHeightfield.BuildContourSet( settings ); var polyMesh = new PolyMesh( contourSet, settings ); var polyMeshDetail = new PolyMeshDetail( polyMesh, compactHeightfield, settings ); var buildData = new NavMeshBuilder( polyMesh, polyMeshDetail, new OffMeshConnection[ 0 ], settings ); newTiledNavMesh = new TiledNavMesh( buildData ); //!!!! ////Pathfinding with multiple units //GenerateCrowd(); } catch( Exception e ) { DestroyNavMesh(); error = e.Message; return false; } int dataLength; byte[] data; using( var memoryStream = new MemoryStream() ) { var serializer = new NavMeshBinarySerializer(); serializer.Serialize( memoryStream, newTiledNavMesh ); dataLength = (int)memoryStream.Length; data = memoryStream.GetBuffer(); } //generate nav mesh data var writer = new ArrayDataWriter(); writer.Write( navMeshDataVersion ); writer.Write( dataLength ); writer.Write( data, 0, dataLength ); //set NavMeshData and init var newNavMeshData = new byte[ writer.BitLength / 8 ]; Buffer.BlockCopy( writer.Data, 0, newNavMeshData, 0, newNavMeshData.Length ); NavMeshData = newNavMeshData; error = ""; return true; }
public PolyMeshDetail CreatePolyMeshDetail(RcConfig config, PolyMesh polyMesh, CompactHeightfield chf) { var handle = RecastLibrary.polymesh_detail_create(_context.DangerousGetHandle(), ref config, polyMesh.DangerousGetHandle(), chf.DangerousGetHandle()); return(new PolyMeshDetail(handle)); }
public PolyMesh CreatePolyMesh(RcConfig config, CompactHeightfield chf) { var handle = RecastLibrary.polymesh_create(_context.DangerousGetHandle(), ref config, chf.DangerousGetHandle()); return(new PolyMesh(handle)); }