Пример #1
0
		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);
		}
Пример #2
0
        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.");
            }
        }
Пример #3
0
 public static extern bool rcpdBuildPolyMeshDetail(IntPtr context
                                                   , ref PolyMeshEx polyMesh
                                                   , [In] CompactHeightfield chf
                                                   , float sampleDist
                                                   , float sampleMaxError
                                                   , [In, Out] PolyMeshDetail detailMesh);
Пример #4
0
    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);
    }
Пример #5
0
    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));
    }
Пример #6
0
 public static extern bool nmcsBuildSet(IntPtr context
                                        , [In] CompactHeightfield chf
                                        , float maxError
                                        , int maxEdgeLen
                                        , [In, Out] ContourSetEx cset
                                        , ContourBuildFlags flags);
Пример #7
0
		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;
		}
Пример #8
0
        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));
        }
Пример #9
0
        public PolyMesh CreatePolyMesh(RcConfig config, CompactHeightfield chf)
        {
            var handle = RecastLibrary.polymesh_create(_context.DangerousGetHandle(), ref config, chf.DangerousGetHandle());

            return(new PolyMesh(handle));
        }