public void BuildRegions_Success() { //Build a 3x3 heightfield Heightfield hf = new Heightfield(new BBox3(Vector3.Zero, Vector3.One), (float)(1.0f / 3.0f), 0.02f); for (int i = 0; i < 9; 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, 2, 3); //Most spans do not have a region id because those spans are part of the border //Most region ids won't be assigned to any span //Total number of regions right now Assert.AreEqual(chf.MaxRegions, 7); //Center spans should have region id Assert.AreEqual((int)chf.Spans[4 * 2 + 0].Region, 5); Assert.AreEqual((int)chf.Spans[4 * 2 + 1].Region, 6); //Check that the rest of the region ids are not assigned to a span for (int i = 0; i < chf.Spans.Length; i++) { for (int j = 0; j <= 4; j++) { Assert.AreNotEqual((int)chf.Spans[i].Region, j); } } }
/// <summary> /// Generates a <see cref="NavMesh"/> given a collection of triangles and some settings. /// </summary> /// <param name="triangles">The triangles that form the level.</param> /// <param name="settings">The settings to generate with.</param> /// <returns>A <see cref="NavMesh"/>.</returns> public static NavMesh Generate(IEnumerable<Triangle3> triangles, NavMeshGenerationSettings settings) { BBox3 bounds = triangles.GetBoundingBox(settings.CellSize); var hf = new Heightfield(bounds, settings); hf.RasterizeTriangles(triangles); hf.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); hf.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); hf.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); var chf = new CompactHeightfield(hf, settings); chf.Erode(settings.VoxelAgentRadius); chf.BuildDistanceField(); chf.BuildRegions(2, settings.MinRegionSize, settings.MergedRegionSize); var cont = chf.BuildContourSet(settings); var polyMesh = new PolyMesh(cont, settings); var polyMeshDetail = new PolyMeshDetail(polyMesh, chf, settings); var buildData = new NavMeshBuilder(polyMesh, polyMeshDetail, new Pathfinding.OffMeshConnection[0], settings); var navMesh = new NavMesh(buildData); return navMesh; }
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."); } }
public void DistanceField_Simple_Success() { //Build a 3x3 heightfield Heightfield hf = new Heightfield(new BBox3(Vector3.Zero, Vector3.One), (float)(1.0f/3.0f), 0.02f); for (int i = 0; i < 9; 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); //make sure connections are set Assert.AreEqual(chf.Spans[0 * 2].ConnectionCount, 2); //corner Assert.AreEqual(chf.Spans[1 * 2].ConnectionCount, 3); //edge Assert.AreEqual(chf.Spans[2 * 2].ConnectionCount, 2); //corner Assert.AreEqual(chf.Spans[3 * 2].ConnectionCount, 3); //edge Assert.AreEqual(chf.Spans[4 * 2].ConnectionCount, 4); //center chf.BuildDistanceField(); //check distance field values Assert.AreEqual(chf.MaxDistance, 2); //1st row Assert.AreEqual(chf.Distances[0 * 2], 0); //boundary Assert.AreEqual(chf.Distances[1 * 2], 0); //boundary Assert.AreEqual(chf.Distances[2 * 2], 0); //boundary //2nd row Assert.AreEqual(chf.Distances[3 * 2], 0); //boundary Assert.AreEqual(chf.Distances[4 * 2], 2); //center span Assert.AreEqual(chf.Distances[5 * 2], 0); //boundary }
public void DistanceField_Medium_Success() { //Build a 5x5 heightfield Heightfield hf = new Heightfield(new BBox3(Vector3.Zero, Vector3.One), 0.2f, 0.02f); for (int i = 0; i < 25; 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(); //Before box blur, MaxDistance is 4 //After box blur, MaxDistance is 2 Assert.AreEqual(chf.MaxDistance, 2); //1st row Assert.AreEqual(chf.Distances[0 * 2], 0); //boundary Assert.AreEqual(chf.Distances[4 * 2], 0); //boundary //2nd row Assert.AreEqual(chf.Distances[5 * 2], 0); //boundary Assert.AreEqual(chf.Distances[6 * 2], 2); //near boundary Assert.AreEqual(chf.Distances[7 * 2], 2); //near boundary Assert.AreEqual(chf.Distances[8 * 2], 2); //near boundary Assert.AreEqual(chf.Distances[9 * 2], 0); //boundary //3rd row Assert.AreEqual(chf.Distances[10 * 2], 0); //boundary Assert.AreEqual(chf.Distances[11 * 2], 2); //near boundary Assert.AreEqual(chf.Distances[12 * 2], 2); //center (box blurred distance is (2*8 + 5)/9) Assert.AreEqual(chf.Distances[13 * 2], 2); //near boundary Assert.AreEqual(chf.Distances[14 * 2], 0); //boundary }