コード例 #1
0
ファイル: NavMesh.cs プロジェクト: MaybeMars/SharpNav
		/// <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;
		}
コード例 #2
0
ファイル: NavMesh.cs プロジェクト: catingame/Krocodile
        /// <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);
        }
コード例 #3
0
        public override object EditValue(ITypeDescriptorContext context, System.IServiceProvider provider, object value)
        {
            IWindowsFormsEditorService svc = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;

            NavMeshGenerationSettings config = value as NavMeshGenerationSettings;

            using (NavMeshGenerationSettingsForm form = new NavMeshGenerationSettingsForm())
            {
                form.NavSetting = config;
                if (svc.ShowDialog(form) == DialogResult.OK)
                {
                    config = form.NavSetting;                     // update object
                }
            }

            return(value);            // can also replace the wrapper object here
        }
コード例 #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NavMeshBuilder" /> class.
        /// Add all the PolyMesh and PolyMeshDetail attributes to the Navigation Mesh.
        /// Then, add Off-Mesh connection support.
        /// </summary>
        /// <param name="polyMesh">The PolyMesh</param>
        /// <param name="polyMeshDetail">The PolyMeshDetail</param>
        /// <param name="offMeshCons">Offmesh connection data</param>
        /// <param name="settings">The settings used to build.</param>
        public NavMeshBuilder(PolyMesh polyMesh, PolyMeshDetail polyMeshDetail, OffMeshConnection[] offMeshCons, NavMeshGenerationSettings settings)
        {
            if (settings.VertsPerPoly > PathfindingCommon.VERTS_PER_POLYGON)
            {
                throw new InvalidOperationException("The number of vertices per polygon is above SharpNav's limit");
            }
            if (polyMesh.VertCount == 0)
            {
                throw new InvalidOperationException("The provided PolyMesh has no vertices.");
            }
            if (polyMesh.PolyCount == 0)
            {
                throw new InvalidOperationException("The provided PolyMesh has not polys.");
            }

            int nvp = settings.VertsPerPoly;

            //classify off-mesh connection points
            BoundarySide[] offMeshSides          = new BoundarySide[offMeshCons.Length * 2];
            int            storedOffMeshConCount = 0;
            int            offMeshConLinkCount   = 0;

            if (offMeshCons.Length > 0)
            {
                //find height bounds
                float hmin = float.MaxValue;
                float hmax = -float.MaxValue;

                if (polyMeshDetail != null)
                {
                    for (int i = 0; i < polyMeshDetail.VertCount; i++)
                    {
                        float h = polyMeshDetail.Verts[i].Y;
                        hmin = Math.Min(hmin, h);
                        hmax = Math.Max(hmax, h);
                    }
                }
                else
                {
                    for (int i = 0; i < polyMesh.VertCount; i++)
                    {
                        PolyVertex iv = polyMesh.Verts[i];
                        float      h  = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight;
                        hmin = Math.Min(hmin, h);
                        hmax = Math.Max(hmax, h);
                    }
                }

                hmin -= settings.MaxClimb;
                hmax += settings.MaxClimb;
                BBox3 bounds = polyMesh.Bounds;
                bounds.Min.Y = hmin;
                bounds.Max.Y = hmax;

                for (int i = 0; i < offMeshCons.Length; i++)
                {
                    Vector3 p0 = offMeshCons[i].Pos0;
                    Vector3 p1 = offMeshCons[i].Pos1;

                    offMeshSides[i * 2 + 0] = BoundarySideExtensions.FromPoint(p0, bounds);
                    offMeshSides[i * 2 + 1] = BoundarySideExtensions.FromPoint(p1, bounds);

                    //off-mesh start position isn't touching mesh
                    if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                    {
                        if (p0.Y < bounds.Min.Y || p0.Y > bounds.Max.Y)
                        {
                            offMeshSides[i * 2 + 0] = 0;
                        }
                    }

                    //count number of links to allocate
                    if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                    {
                        offMeshConLinkCount++;
                    }
                    if (offMeshSides[i * 2 + 1] == BoundarySide.Internal)
                    {
                        offMeshConLinkCount++;
                    }

                    if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                    {
                        storedOffMeshConCount++;
                    }
                }
            }

            //off-mesh connections stored as polygons, adjust values
            int totPolyCount = polyMesh.PolyCount + storedOffMeshConCount;
            int totVertCount = polyMesh.VertCount + storedOffMeshConCount * 2;

            //find portal edges
            int edgeCount   = 0;
            int portalCount = 0;

            for (int i = 0; i < polyMesh.PolyCount; i++)
            {
                PolyMesh.Polygon p = polyMesh.Polys[i];
                for (int j = 0; j < nvp; j++)
                {
                    if (p.Vertices[j] == PolyMesh.NullId)
                    {
                        break;
                    }

                    edgeCount++;

                    if (PolyMesh.IsBoundaryEdge(p.NeighborEdges[j]))
                    {
                        int dir = p.NeighborEdges[j] % 16;
                        if (dir != 15)
                        {
                            portalCount++;
                        }
                    }
                }
            }

            int maxLinkCount = edgeCount + portalCount * 2 + offMeshConLinkCount * 2;

            //find unique detail vertices
            int uniqueDetailVertCount = 0;
            int detailTriCount        = 0;

            if (polyMeshDetail != null)
            {
                detailTriCount = polyMeshDetail.TrisCount;
                for (int i = 0; i < polyMesh.PolyCount; i++)
                {
                    int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount;
                    int numPolyVerts   = polyMesh.Polys[i].VertexCount;
                    uniqueDetailVertCount += numDetailVerts - numPolyVerts;
                }
            }
            else
            {
                uniqueDetailVertCount = 0;
                detailTriCount        = 0;
                for (int i = 0; i < polyMesh.PolyCount; i++)
                {
                    int numPolyVerts = polyMesh.Polys[i].VertexCount;
                    uniqueDetailVertCount += numPolyVerts - 2;
                }
            }

            //allocate data
            header             = new PathfindingCommon.NavMeshInfo();
            navVerts           = new Vector3[totVertCount];
            navPolys           = new Poly[totPolyCount];
            navDMeshes         = new PolyMeshDetail.MeshData[polyMesh.PolyCount];
            navDVerts          = new Vector3[uniqueDetailVertCount];
            navDTris           = new PolyMeshDetail.TriangleData[detailTriCount];
            offMeshConnections = new OffMeshConnection[storedOffMeshConCount];

            //store header
            //HACK TiledNavMesh should figure out the X/Y/layer instead of the user maybe?
            header.X               = 0;
            header.Y               = 0;
            header.Layer           = 0;
            header.PolyCount       = totPolyCount;
            header.VertCount       = totVertCount;
            header.MaxLinkCount    = maxLinkCount;
            header.Bounds          = polyMesh.Bounds;
            header.DetailMeshCount = polyMesh.PolyCount;
            header.DetailVertCount = uniqueDetailVertCount;
            header.DetailTriCount  = detailTriCount;
            header.OffMeshBase     = polyMesh.PolyCount;
            header.WalkableHeight  = settings.AgentHeight;
            header.WalkableRadius  = settings.AgentRadius;
            header.WalkableClimb   = settings.MaxClimb;
            header.OffMeshConCount = storedOffMeshConCount;
            header.BvNodeCount     = settings.BuildBoundingVolumeTree ? polyMesh.PolyCount * 2 : 0;
            header.BvQuantFactor   = 1f / settings.CellSize;

            int offMeshVertsBase = polyMesh.VertCount;
            int offMeshPolyBase  = polyMesh.PolyCount;

            //store vertices
            for (int i = 0; i < polyMesh.VertCount; i++)
            {
                PolyVertex iv = polyMesh.Verts[i];
                navVerts[i].X = polyMesh.Bounds.Min.X + iv.X * settings.CellSize;
                navVerts[i].Y = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight;
                navVerts[i].Z = polyMesh.Bounds.Min.Z + iv.Z * settings.CellSize;
            }

            //off-mesh link vertices
            int n = 0;

            for (int i = 0; i < offMeshCons.Length; i++)
            {
                //only store connections which start from this tile
                if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                {
                    navVerts[offMeshVertsBase + (n * 2 + 0)] = offMeshCons[i].Pos0;
                    navVerts[offMeshVertsBase + (n * 2 + 1)] = offMeshCons[i].Pos1;
                    n++;
                }
            }

            //store polygons
            for (int i = 0; i < polyMesh.PolyCount; i++)
            {
                navPolys[i]           = new Poly();
                navPolys[i].VertCount = 0;
                navPolys[i].Tag       = polyMesh.Polys[i].Tag;
                navPolys[i].Area      = polyMesh.Polys[i].Area;
                navPolys[i].PolyType  = PolygonType.Ground;
                navPolys[i].Verts     = new int[nvp];
                navPolys[i].Neis      = new int[nvp];
                for (int j = 0; j < nvp; j++)
                {
                    if (polyMesh.Polys[i].Vertices[j] == PolyMesh.NullId)
                    {
                        break;
                    }

                    navPolys[i].Verts[j] = polyMesh.Polys[i].Vertices[j];
                    if (PolyMesh.IsBoundaryEdge(polyMesh.Polys[i].NeighborEdges[j]))
                    {
                        //border or portal edge
                        int dir = polyMesh.Polys[i].NeighborEdges[j] % 16;
                        if (dir == 0xf)                         //border
                        {
                            navPolys[i].Neis[j] = 0;
                        }
                        else if (dir == 0)                         //portal x-
                        {
                            navPolys[i].Neis[j] = Link.External | 4;
                        }
                        else if (dir == 1)                         //portal z+
                        {
                            navPolys[i].Neis[j] = Link.External | 2;
                        }
                        else if (dir == 2)                         //portal x+
                        {
                            navPolys[i].Neis[j] = Link.External | 0;
                        }
                        else if (dir == 3)                         //portal z-
                        {
                            navPolys[i].Neis[j] = Link.External | 6;
                        }
                    }
                    else
                    {
                        //normal connection
                        navPolys[i].Neis[j] = polyMesh.Polys[i].NeighborEdges[j] + 1;
                    }

                    navPolys[i].VertCount++;
                }
            }

            //off-mesh connection vertices
            n = 0;
            for (int i = 0; i < offMeshCons.Length; i++)
            {
                //only store connections which start from this tile
                if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                {
                    navPolys[offMeshPolyBase + n].VertCount = 2;
                    navPolys[offMeshPolyBase + n].Verts     = new int[nvp];
                    navPolys[offMeshPolyBase + n].Verts[0]  = offMeshVertsBase + (n * 2 + 0);
                    navPolys[offMeshPolyBase + n].Verts[1]  = offMeshVertsBase + (n * 2 + 1);
                    navPolys[offMeshPolyBase + n].Tag       = offMeshCons[i].Flags;
                    navPolys[offMeshPolyBase + n].Area      = polyMesh.Polys[offMeshCons[i].Poly].Area;                //HACK is this correct?
                    navPolys[offMeshPolyBase + n].PolyType  = PolygonType.OffMeshConnection;
                    n++;
                }
            }

            //store detail meshes and vertices
            if (polyMeshDetail != null)
            {
                int            vbase             = 0;
                List <Vector3> storedDetailVerts = new List <Vector3>();
                for (int i = 0; i < polyMesh.PolyCount; i++)
                {
                    int vb             = polyMeshDetail.Meshes[i].VertexIndex;
                    int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount;
                    int numPolyVerts   = navPolys[i].VertCount;
                    navDMeshes[i].VertexIndex   = vbase;
                    navDMeshes[i].VertexCount   = numDetailVerts - numPolyVerts;
                    navDMeshes[i].TriangleIndex = polyMeshDetail.Meshes[i].TriangleIndex;
                    navDMeshes[i].TriangleCount = polyMeshDetail.Meshes[i].TriangleCount;

                    //Copy detail vertices
                    //first 'nv' verts are equal to nav poly verts
                    //the rest are detail verts
                    for (int j = 0; j < navDMeshes[i].VertexCount; j++)
                    {
                        storedDetailVerts.Add(polyMeshDetail.Verts[vb + numPolyVerts + j]);
                    }

                    vbase += numDetailVerts - numPolyVerts;
                }

                navDVerts = storedDetailVerts.ToArray();

                //store triangles
                for (int j = 0; j < polyMeshDetail.TrisCount; j++)
                {
                    navDTris[j] = polyMeshDetail.Tris[j];
                }
            }
            else
            {
                //create dummy detail mesh by triangulating polys
                int tbase = 0;
                for (int i = 0; i < polyMesh.PolyCount; i++)
                {
                    int numPolyVerts = navPolys[i].VertCount;
                    navDMeshes[i].VertexIndex   = 0;
                    navDMeshes[i].VertexCount   = 0;
                    navDMeshes[i].TriangleIndex = tbase;
                    navDMeshes[i].TriangleCount = numPolyVerts - 2;

                    //triangulate polygon
                    for (int j = 2; j < numPolyVerts; j++)
                    {
                        navDTris[tbase].VertexHash0 = 0;
                        navDTris[tbase].VertexHash1 = j - 1;
                        navDTris[tbase].VertexHash2 = j;

                        //bit for each edge that belongs to the poly boundary
                        navDTris[tbase].Flags = 1 << 2;
                        if (j == 2)
                        {
                            navDTris[tbase].Flags |= 1 << 0;
                        }
                        if (j == numPolyVerts - 1)
                        {
                            navDTris[tbase].Flags |= 1 << 4;
                        }

                        tbase++;
                    }
                }
            }

            //store and create BV tree
            if (settings.BuildBoundingVolumeTree)
            {
                //build tree
                navBvTree = new BVTree(polyMesh.Verts, polyMesh.Polys, nvp, settings.CellSize, settings.CellHeight);
            }

            //store off-mesh connections
            n = 0;
            for (int i = 0; i < offMeshConnections.Length; i++)
            {
                //only store connections which start from this tile
                if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                {
                    offMeshConnections[n].Poly = offMeshPolyBase + n;

                    //copy connection end points
                    offMeshConnections[n].Pos0 = offMeshCons[i].Pos0;
                    offMeshConnections[n].Pos1 = offMeshCons[i].Pos1;

                    offMeshConnections[n].Radius = offMeshCons[i].Radius;
                    offMeshConnections[n].Flags  = offMeshCons[i].Flags;
                    offMeshConnections[n].Side   = offMeshSides[i * 2 + 1];
                    offMeshConnections[n].Tag    = offMeshCons[i].Tag;

                    n++;
                }
            }
        }
コード例 #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CompactHeightfield"/> class.
 /// </summary>
 /// <param name="field">A <see cref="Heightfield"/> to build from.</param>
 /// <param name="settings">The settings to build with.</param>
 public CompactHeightfield(Heightfield field, NavMeshGenerationSettings settings)
     : this(field, settings.VoxelAgentHeight, settings.VoxelMaxClimb)
 {
 }
コード例 #6
0
 /// <summary>
 /// Builds a set of <see cref="Contour"/>s around the generated regions. Must be called after regions are generated.
 /// </summary>
 /// <param name="settings">Settings for building the <see cref="ContourSet"/>.</param>
 /// <returns>A <see cref="ContourSet"/> containing one contour per region.</returns>
 public ContourSet BuildContourSet(NavMeshGenerationSettings settings)
 {
     return BuildContourSet(settings.MaxEdgeError, settings.MaxEdgeLength, settings.ContourFlags);
 }
コード例 #7
0
ファイル: NavMeshBuilder.cs プロジェクト: MaybeMars/SharpNav
		/// <summary>
		/// Initializes a new instance of the <see cref="NavMeshBuilder" /> class.
		/// Add all the PolyMesh and PolyMeshDetail attributes to the Navigation Mesh.
		/// Then, add Off-Mesh connection support.
		/// </summary>
		/// <param name="polyMesh">The PolyMesh</param>
		/// <param name="polyMeshDetail">The PolyMeshDetail</param>
		/// <param name="offMeshCons">Offmesh connection data</param>
		/// <param name="settings">The settings used to build.</param>
		public NavMeshBuilder(PolyMesh polyMesh, PolyMeshDetail polyMeshDetail, OffMeshConnection[] offMeshCons, NavMeshGenerationSettings settings)
		{
			if (settings.VertsPerPoly > PathfindingCommon.VERTS_PER_POLYGON)
				throw new InvalidOperationException("The number of vertices per polygon is above SharpNav's limit");
			if (polyMesh.VertCount == 0)
				throw new InvalidOperationException("The provided PolyMesh has no vertices.");
			if (polyMesh.PolyCount == 0)
				throw new InvalidOperationException("The provided PolyMesh has not polys.");

			int nvp = settings.VertsPerPoly;

			//classify off-mesh connection points
			BoundarySide[] offMeshSides = new BoundarySide[offMeshCons.Length * 2];
			int storedOffMeshConCount = 0;
			int offMeshConLinkCount = 0;

			if (offMeshCons.Length > 0)
			{
				//find height bounds
				float hmin = float.MaxValue;
				float hmax = -float.MaxValue;

				if (polyMeshDetail != null)
				{
					for (int i = 0; i < polyMeshDetail.VertCount; i++)
					{
						float h = polyMeshDetail.Verts[i].Y;
						hmin = Math.Min(hmin, h);
						hmax = Math.Max(hmax, h);
					}
				}
				else
				{
					for (int i = 0; i < polyMesh.VertCount; i++)
					{
						PolyVertex iv = polyMesh.Verts[i];
						float h = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight;
						hmin = Math.Min(hmin, h);
						hmax = Math.Max(hmax, h);
					}
				}

				hmin -= settings.MaxClimb;
				hmax += settings.MaxClimb;
				BBox3 bounds = polyMesh.Bounds;
				bounds.Min.Y = hmin;
				bounds.Max.Y = hmax;

				for (int i = 0; i < offMeshCons.Length; i++)
				{
					Vector3 p0 = offMeshCons[i].Pos0;
					Vector3 p1 = offMeshCons[i].Pos1;

					offMeshSides[i * 2 + 0] = BoundarySideExtensions.FromPoint(p0, bounds);
					offMeshSides[i * 2 + 1] = BoundarySideExtensions.FromPoint(p1, bounds);

					//off-mesh start position isn't touching mesh
					if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
					{
						if (p0.Y < bounds.Min.Y || p0.Y > bounds.Max.Y)
							offMeshSides[i * 2 + 0] = 0;
					}

					//count number of links to allocate
					if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
						offMeshConLinkCount++;
					if (offMeshSides[i * 2 + 1] == BoundarySide.Internal)
						offMeshConLinkCount++;

					if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
						storedOffMeshConCount++;
				}
			}

			//off-mesh connections stored as polygons, adjust values
			int totPolyCount = polyMesh.PolyCount + storedOffMeshConCount;
			int totVertCount = polyMesh.VertCount + storedOffMeshConCount * 2;

			//find portal edges
			int edgeCount = 0;
			int portalCount = 0;
			for (int i = 0; i < polyMesh.PolyCount; i++)
			{
				PolyMesh.Polygon p = polyMesh.Polys[i];
				for (int j = 0; j < nvp; j++)
				{
					if (p.Vertices[j] == PolyMesh.NullId)
						break;

					edgeCount++;
					
					if (PolyMesh.IsBoundaryEdge(p.NeighborEdges[j]))
					{
						int dir = p.NeighborEdges[j] % 16;
						if (dir != 15)
							portalCount++;
					}
				}
			}

			int maxLinkCount = edgeCount + portalCount * 2 + offMeshConLinkCount * 2;

			//find unique detail vertices
			int uniqueDetailVertCount = 0;
			int detailTriCount = 0;
			if (polyMeshDetail != null)
			{
				detailTriCount = polyMeshDetail.TrisCount;
				for (int i = 0; i < polyMesh.PolyCount; i++)
				{
					int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount;
					int numPolyVerts = polyMesh.Polys[i].VertexCount;
					uniqueDetailVertCount += numDetailVerts - numPolyVerts;
				}
			}
			else
			{
				uniqueDetailVertCount = 0;
				detailTriCount = 0;
				for (int i = 0; i < polyMesh.PolyCount; i++)
				{
					int numPolyVerts = polyMesh.Polys[i].VertexCount;
					uniqueDetailVertCount += numPolyVerts - 2;
				}
			}

			//allocate data
			header = new PathfindingCommon.NavMeshInfo();
			navVerts = new Vector3[totVertCount];
			navPolys = new Poly[totPolyCount];
			navDMeshes = new PolyMeshDetail.MeshData[polyMesh.PolyCount];
			navDVerts = new Vector3[uniqueDetailVertCount];
			navDTris = new PolyMeshDetail.TriangleData[detailTriCount];
			offMeshConnections = new OffMeshConnection[storedOffMeshConCount];

			//store header
			//HACK TiledNavMesh should figure out the X/Y/layer instead of the user maybe?
			header.X = 0;
			header.Y = 0;
			header.Layer = 0;
			header.PolyCount = totPolyCount;
			header.VertCount = totVertCount;
			header.MaxLinkCount = maxLinkCount;
			header.Bounds = polyMesh.Bounds;
			header.DetailMeshCount = polyMesh.PolyCount;
			header.DetailVertCount = uniqueDetailVertCount;
			header.DetailTriCount = detailTriCount;
			header.OffMeshBase = polyMesh.PolyCount;
			header.WalkableHeight = settings.AgentHeight;
			header.WalkableRadius = settings.AgentRadius;
			header.WalkableClimb = settings.MaxClimb;
			header.OffMeshConCount = storedOffMeshConCount;
			header.BvNodeCount = settings.BuildBoundingVolumeTree ? polyMesh.PolyCount * 2 : 0;
			header.BvQuantFactor = 1f / settings.CellSize;

			int offMeshVertsBase = polyMesh.VertCount;
			int offMeshPolyBase = polyMesh.PolyCount;

			//store vertices
			for (int i = 0; i < polyMesh.VertCount; i++)
			{
				PolyVertex iv = polyMesh.Verts[i];
				navVerts[i].X = polyMesh.Bounds.Min.X + iv.X * settings.CellSize;
				navVerts[i].Y = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight;
				navVerts[i].Z = polyMesh.Bounds.Min.Z + iv.Z * settings.CellSize;
			}

			//off-mesh link vertices
			int n = 0;
			for (int i = 0; i < offMeshCons.Length; i++)
			{
				//only store connections which start from this tile
				if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
				{
					navVerts[offMeshVertsBase + (n * 2 + 0)] = offMeshCons[i].Pos0;
					navVerts[offMeshVertsBase + (n * 2 + 1)] = offMeshCons[i].Pos1;
					n++;
				}
			}

			//store polygons
			for (int i = 0; i < polyMesh.PolyCount; i++)
			{
				navPolys[i] = new Poly();
				navPolys[i].VertCount = 0;
				navPolys[i].Tag = polyMesh.Polys[i].Tag;
				navPolys[i].Area = polyMesh.Polys[i].Area;
				navPolys[i].PolyType = PolygonType.Ground;
				navPolys[i].Verts = new int[nvp];
				navPolys[i].Neis = new int[nvp];
				for (int j = 0; j < nvp; j++)
				{
					if (polyMesh.Polys[i].Vertices[j] == PolyMesh.NullId)
						break;

					navPolys[i].Verts[j] = polyMesh.Polys[i].Vertices[j];
					if (PolyMesh.IsBoundaryEdge(polyMesh.Polys[i].NeighborEdges[j]))
					{
						//border or portal edge
						int dir = polyMesh.Polys[i].NeighborEdges[j] % 16;
						if (dir == 0xf) //border
							navPolys[i].Neis[j] = 0;
						else if (dir == 0) //portal x-
							navPolys[i].Neis[j] = Link.External | 4;
						else if (dir == 1) //portal z+
							navPolys[i].Neis[j] = Link.External | 2;
						else if (dir == 2) //portal x+
							navPolys[i].Neis[j] = Link.External | 0;
						else if (dir == 3) //portal z-
							navPolys[i].Neis[j] = Link.External | 6;
					}
					else
					{
						//normal connection
						navPolys[i].Neis[j] = polyMesh.Polys[i].NeighborEdges[j] + 1;
					}

					navPolys[i].VertCount++;
				}
			}

			//off-mesh connection vertices
			n = 0;
			for (int i = 0; i < offMeshCons.Length; i++)
			{
				//only store connections which start from this tile
				if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
				{
					navPolys[offMeshPolyBase + n].VertCount = 2;
					navPolys[offMeshPolyBase + n].Verts = new int[nvp];
					navPolys[offMeshPolyBase + n].Verts[0] = offMeshVertsBase + (n * 2 + 0);
					navPolys[offMeshPolyBase + n].Verts[1] = offMeshVertsBase + (n * 2 + 1);
					navPolys[offMeshPolyBase + n].Tag = offMeshCons[i].Flags;
					navPolys[offMeshPolyBase + n].Area = polyMesh.Polys[offMeshCons[i].Poly].Area; //HACK is this correct?
					navPolys[offMeshPolyBase + n].PolyType = PolygonType.OffMeshConnection;
					n++;
				}
			}
			
			//store detail meshes and vertices
			if (polyMeshDetail != null)
			{
				int vbase = 0;
				List<Vector3> storedDetailVerts = new List<Vector3>();
				for (int i = 0; i < polyMesh.PolyCount; i++)
				{
					int vb = polyMeshDetail.Meshes[i].VertexIndex;
					int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount;
					int numPolyVerts = navPolys[i].VertCount;
					navDMeshes[i].VertexIndex = vbase;
					navDMeshes[i].VertexCount = numDetailVerts - numPolyVerts;
					navDMeshes[i].TriangleIndex = polyMeshDetail.Meshes[i].TriangleIndex;
					navDMeshes[i].TriangleCount = polyMeshDetail.Meshes[i].TriangleCount;
					
					//Copy detail vertices 
					//first 'nv' verts are equal to nav poly verts
					//the rest are detail verts
					for (int j = 0; j < navDMeshes[i].VertexCount; j++)
					{
						storedDetailVerts.Add(polyMeshDetail.Verts[vb + numPolyVerts + j]);
					}

					vbase += numDetailVerts - numPolyVerts;
				}

				navDVerts = storedDetailVerts.ToArray();

				//store triangles
				for (int j = 0; j < polyMeshDetail.TrisCount; j++)
					navDTris[j] = polyMeshDetail.Tris[j];
			}
			else
			{
				//create dummy detail mesh by triangulating polys
				int tbase = 0;
				for (int i = 0; i < polyMesh.PolyCount; i++)
				{
					int numPolyVerts = navPolys[i].VertCount;
					navDMeshes[i].VertexIndex = 0;
					navDMeshes[i].VertexCount = 0;
					navDMeshes[i].TriangleIndex = tbase;
					navDMeshes[i].TriangleCount = numPolyVerts - 2;

					//triangulate polygon
					for (int j = 2; j < numPolyVerts; j++)
					{
						navDTris[tbase].VertexHash0 = 0;
						navDTris[tbase].VertexHash1 = j - 1;
						navDTris[tbase].VertexHash2 = j;

						//bit for each edge that belongs to the poly boundary
						navDTris[tbase].Flags = 1 << 2;
						if (j == 2) 
							navDTris[tbase].Flags |= 1 << 0;
						if (j == numPolyVerts - 1)
							navDTris[tbase].Flags |= 1 << 4;
						
						tbase++;
					}
				}
			}
			
			//store and create BV tree
			if (settings.BuildBoundingVolumeTree)
			{
				//build tree
				navBvTree = new BVTree(polyMesh.Verts, polyMesh.Polys, nvp, settings.CellSize, settings.CellHeight);
			}

			//store off-mesh connections
			n = 0;
			for (int i = 0; i < offMeshConnections.Length; i++)
			{
				//only store connections which start from this tile
				if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
				{
					offMeshConnections[n].Poly = offMeshPolyBase + n;

					//copy connection end points
					offMeshConnections[n].Pos0 = offMeshCons[i].Pos0;
					offMeshConnections[n].Pos1 = offMeshCons[i].Pos1;

					offMeshConnections[n].Radius = offMeshCons[i].Radius;
					offMeshConnections[n].Flags = offMeshCons[i].Flags;
					offMeshConnections[n].Side = offMeshSides[i * 2 + 1];
					offMeshConnections[n].Tag = offMeshCons[i].Tag;

					n++;
				}
			}
		}
コード例 #8
0
        private void InitializeUI()
        {
            settings = NavMeshGenerationSettings.Default;
            areaSettings = new AreaIdGenerationSettings();

            DockBase dock = new DockBase(gwenCanvas);
            dock.Dock = Pos.Fill;
            dock.SetSize(Width, Height);
            dock.RightDock.Width = 280;
            dock.BottomDock.Height = 150;

            statusBar = new StatusBar(gwenCanvas);

            Label genTime = new Label(statusBar);
            genTime.Name = "GenTime";
            genTime.Text = "Generation Time: 0ms";
            genTime.Dock = Pos.Left;

            LabeledCheckBox catchCheckBox = new LabeledCheckBox(statusBar);
            catchCheckBox.Text = "Intercept and log exceptions";
            catchCheckBox.Dock = Pos.Right;
            catchCheckBox.CheckChanged += (s, e) => interceptExceptions = catchCheckBox.IsChecked;
            catchCheckBox.IsChecked = true;

            Base genBase = new Base(dock);
            dock.RightDock.TabControl.AddPage("NavMesh Generation", genBase);

            Button generateButton = new Button(genBase);
            generateButton.Text = "Generate!";
            generateButton.Height = 30;
            generateButton.Dock = Pos.Top;
            generateButton.Released += (s, e) => GenerateNavMesh();

            GroupBox displaySettings = new GroupBox(genBase);
            displaySettings.Text = "Display";
            displaySettings.Dock = Pos.Top;
            displaySettings.Height = 60;

            Base levelCheckBase = new Base(displaySettings);
            levelCheckBase.Dock = Pos.Top;

            Label levelCheckLabel = new Label(levelCheckBase);
            levelCheckLabel.Text = "Level";
            levelCheckLabel.Dock = Pos.Left;

            CheckBox levelCheckBox = new CheckBox(levelCheckBase);
            levelCheckBox.Dock = Pos.Right;
            levelCheckBox.Checked += (s, e) => displayLevel = true;
            levelCheckBox.UnChecked += (s, e) => displayLevel = false;
            levelCheckBox.IsChecked = true;

            levelCheckBase.SizeToChildren();

            Base displayModeBase = new Base(displaySettings);
            displayModeBase.Dock = Pos.Top;
            displayModeBase.Padding = new Padding(0, 4, 0, 0);

            Label displayModeLabel = new Label(displayModeBase);
            displayModeLabel.Text = "Generation Step";
            displayModeLabel.Dock = Pos.Left;
            displayModeLabel.Padding = new Padding(0, 0, 4, 0);

            ComboBox displayModes = new ComboBox(displayModeBase);
            displayModes.Dock = Pos.Top;
            displayModes.AddItem("None", "", DisplayMode.None);
            displayModes.AddItem("Heightfield", "", DisplayMode.Heightfield);
            displayModes.AddItem("Compact Heightfield", "", DisplayMode.CompactHeightfield);
            displayModes.AddItem("Distance Field", "", DisplayMode.DistanceField);
            displayModes.AddItem("Regions", "", DisplayMode.Regions);
            displayModes.AddItem("Contours", "", DisplayMode.Contours);
            displayModes.AddItem("Polygon Mesh", "", DisplayMode.PolyMesh);
            displayModes.AddItem("Polygon Mesh Detail", "", DisplayMode.PolyMeshDetail);
            displayModes.AddItem("NavMesh", "", DisplayMode.NavMesh);
            displayModes.AddItem("Pathfinding", "", DisplayMode.Pathfinding);
            displayModes.ItemSelected += (s, e) => displayMode = (DisplayMode)e.SelectedItem.UserData;

            displayModes.SelectByUserData(DisplayMode.PolyMeshDetail);

            displayModeBase.SizeToChildren();
            displayModeBase.Height += 4; //accounts for the padding, GWEN.NET should do this

            const int leftMax = 125;
            const int rightMax = 20;

            GroupBox areaSetting = new GroupBox(genBase);
            areaSetting.Text = "Area";
            areaSetting.Dock = Pos.Top;
            areaSetting.Height = 90;

            var levelTris = level.GetTriangles();
            BBox3 bounds = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length).GetBoundingBox();

            Base maxTriSlope = CreateSliderOption(areaSetting, "Max Tri Slope:", 0.0001f, 3.14f, 3.14f, "N2", leftMax, rightMax, v => areaSettings.MaxTriSlope = v);
            Base minLevelHeight = CreateSliderOption(areaSetting, "Min Height:", bounds.Min.Y, bounds.Max.Y, bounds.Min.Y, "N0", leftMax, rightMax, v => areaSettings.MinLevelHeight = v);
            Base maxLevelHeight = CreateSliderOption(areaSetting, "Max Height:", bounds.Min.Y, bounds.Max.Y, bounds.Max.Y, "N0", leftMax, rightMax, v => areaSettings.MaxLevelHeight = v);

            GroupBox rsSettings = new GroupBox(genBase);
            rsSettings.Text = "Rasterization";
            rsSettings.Dock = Pos.Top;
            rsSettings.Height = 90;

            Base cellSizeSetting = CreateSliderOption(rsSettings, "Cell Size:", 0.1f, 2.0f, 0.3f, "N2", leftMax, rightMax, v => settings.CellSize = v);
            Base cellHeightSetting = CreateSliderOption(rsSettings, "Cell Height:", 0.1f, 2f, 0.2f, "N2", leftMax, rightMax, v => settings.CellHeight = v);

            GroupBox agentSettings = new GroupBox(genBase);
            agentSettings.Text = "Agent";
            agentSettings.Dock = Pos.Top;
            agentSettings.Height = 115;

            Base maxSlopeSetting = CreateSliderOption(agentSettings, "Max Climb:", 0.1f, 5.0f, 0.9f, "N0", leftMax, rightMax, v => settings.MaxClimb = v);
            Base maxHeightSetting = CreateSliderOption(agentSettings, "Height:", 0.1f, 5.0f, 2.0f, "N0", leftMax, rightMax, v => settings.AgentHeight = v);
            Base erodeRadius = CreateSliderOption(agentSettings, "Radius:", 0.0f, 5.0f, 0.6f, "N1", leftMax, rightMax, v => { settings.AgentRadius = v; agentCylinder.Radius = v; });
            Base addRemoveAgent = CreateAddRemoveButton(agentSettings, "Count", leftMax, rightMax, 0, MAX_AGENTS, () => { numActiveAgents++; GenerateCrowd(); }, () => { numActiveAgents--; GenerateCrowd(); });

            GroupBox regionSettings = new GroupBox(genBase);
            regionSettings.Text = "Region";
            regionSettings.Dock = Pos.Top;
            regionSettings.Height = 65;

            Base minRegionSize = CreateSliderOption(regionSettings, "Min Region Size:", 0f, 150f, 8f, "N0", leftMax, rightMax, v => settings.MinRegionSize = (int)Math.Round(v));
            Base mrgRegionSize = CreateSliderOption(regionSettings, "Merged Region Size:", 0f, 150f, 20f, "N0", leftMax, rightMax, v => settings.MergedRegionSize = (int)Math.Round(v));

            GroupBox navMeshSettings = new GroupBox(genBase);
            navMeshSettings.Text = "NavMesh";
            navMeshSettings.Dock = Pos.Top;
            navMeshSettings.Height = 90;

            Base maxEdgeLength = CreateSliderOption(navMeshSettings, "Max Edge Length:", 0f, 50f, 12f, "N0", leftMax, rightMax, v => settings.MaxEdgeLength = (int)Math.Round(v));
            Base maxEdgeErr = CreateSliderOption(navMeshSettings, "Max Edge Error:", 0f, 3f, 1.8f, "N1", leftMax, rightMax, v => settings.MaxEdgeError = v);
            Base vertsPerPoly = CreateSliderOption(navMeshSettings, "Verts Per Poly:", 3f, 12f, 6f, "N0", leftMax, rightMax, v => settings.VertsPerPoly = (int)Math.Round(v));

            GroupBox navMeshDetailSettings = new GroupBox(genBase);
            navMeshDetailSettings.Text = "NavMeshDetail";
            navMeshDetailSettings.Dock = Pos.Top;
            navMeshDetailSettings.Height = 65;

            Base sampleDistance = CreateSliderOption(navMeshDetailSettings, "Sample Distance:", 0f, 16f, 6f, "N0", leftMax, rightMax, v => settings.SampleDistance = (int)Math.Round(v));
            Base maxSampleError = CreateSliderOption(navMeshDetailSettings, "Max Sample Error:", 0f, 16f, 1f, "N0", leftMax, rightMax, v => settings.MaxSampleError = (int)Math.Round(v));

            Base logBase = new Base(dock);
            dock.BottomDock.TabControl.AddPage("Log", logBase);

            ListBox logBox = new ListBox(logBase);
            logBox.Dock = Pos.Fill;
            logBox.AllowMultiSelect = false;
            logBox.EnableScroll(true, true);
            Console.SetOut(new GwenTextWriter(logBox));
        }
コード例 #9
0
ファイル: PolyMesh.cs プロジェクト: keedongpark/SharpNav
 //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)
 {
 }
コード例 #10
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Heightfield"/> class.
 /// </summary>
 /// <param name="b">The world-space bounds.</param>
 /// <param name="settings">The settings to build with.</param>
 public Heightfield(BBox3 b, NavMeshGenerationSettings settings)
     : this(b, settings.CellSize, settings.CellHeight)
 {
 }
コード例 #11
0
ファイル: Heightfield.cs プロジェクト: keedongpark/SharpNav
 /// <summary>
 /// Initializes a new instance of the <see cref="Heightfield"/> class.
 /// </summary>
 /// <param name="b">The world-space bounds.</param>
 /// <param name="settings">The settings to build with.</param>
 public Heightfield(BBox3 b, NavMeshGenerationSettings settings)
     : this(b, settings.CellSize, settings.CellHeight)
 {
 }
コード例 #12
0
ファイル: PolyMeshDetail.cs プロジェクト: MaybeMars/SharpNav
		/// <summary>
		/// Initializes a new instance of the <see cref="PolyMeshDetail"/> class.
		/// </summary>
		/// <param name="mesh">The <see cref="PolyMesh"/>.</param>
		/// <param name="compactField">The <see cref="CompactHeightfield"/> used to add height detail.</param>
		/// <param name="settings">The settings to build with.</param>
		public PolyMeshDetail(PolyMesh mesh, CompactHeightfield compactField, NavMeshGenerationSettings settings)
			: this(mesh, compactField, settings.SampleDistance, settings.MaxSampleError)
		{
		}