Example #1
0
        /// <summary>
        /// Allocate links for each of the tile's polygons' vertices
        /// </summary>
        public void ConnectIntLinks()
        {
            //Iterate through all the polygons
            for (int i = 0; i < PolyCount; i++)
            {
                Poly p = Polys[i];

                //Avoid Off-Mesh Connection polygons
                if (p.PolyType == PolygonType.OffMeshConnection)
                {
                    continue;
                }

                //Build edge links
                for (int j = p.VertCount - 1; j >= 0; j--)
                {
                    //Skip hard and non-internal edges
                    if (p.Neis[j] == 0 || Link.IsExternal(p.Neis[j]))
                    {
                        continue;
                    }

                    PolyId id;
                    idManager.SetPolyIndex(ref baseRef, p.Neis[j] - 1, out id);

                    //Initialize a new link
                    Link link = new Link();
                    link.Reference = id;
                    link.Edge      = j;
                    link.Side      = BoundarySide.Internal;
                    link.BMin      = link.BMax = 0;
                    p.Links.Add(link);
                }
            }
        }
Example #2
0
        /// <summary>
        /// Find the distance from a point to a triangle.
        /// </summary>
        /// <param name="indexPoly">Current polygon's index</param>
        /// <param name="pos">Current position</param>
        /// <param name="h">Resulting height</param>
        /// <returns>True, if a height is found. False, if otherwise.</returns>
        public bool ClosestHeight(int indexPoly, Vector3 pos, out float h)
        {
            Poly poly = Polys[indexPoly];

            PolyMeshDetail.MeshData pd = DetailMeshes[indexPoly];

            //find height at the location
            for (int j = 0; j < DetailMeshes[indexPoly].TriangleCount; j++)
            {
                PolyMeshDetail.TriangleData t = DetailTris[pd.TriangleIndex + j];
                Vector3[] v = new Vector3[3];

                for (int k = 0; k < 3; k++)
                {
                    if (t[k] < poly.VertCount)
                    {
                        v[k] = Verts[poly.Verts[t[k]]];
                    }
                    else
                    {
                        v[k] = DetailVerts[pd.VertexIndex + (t[k] - poly.VertCount)];
                    }
                }

                if (Distance.PointToTriangle(pos, v[0], v[1], v[2], out h))
                {
                    return(true);
                }
            }

            h = float.MaxValue;
            return(false);
        }
Example #3
0
        /// <summary>
        /// Find the closest point on an offmesh connection, which is in between the two points.
        /// </summary>
        /// <param name="poly">Current polygon</param>
        /// <param name="pos">Current position</param>
        /// <param name="closest">Resulting point that is closest.</param>
        public void ClosestPointOnPolyOffMeshConnection(Poly poly, Vector3 pos, out Vector3 closest)
        {
            Vector3 v0 = Verts[poly.Verts[0]];
            Vector3 v1 = Verts[poly.Verts[1]];
            float   d0 = (pos - v0).Length();
            float   d1 = (pos - v1).Length();
            float   u  = d0 / (d0 + d1);

            closest = Vector3.Lerp(v0, v1, u);
        }
Example #4
0
        /// <summary>
        /// Begin creating off-mesh links between the tile polygons.
        /// </summary>
        public void BaseOffMeshLinks()
        {
            //Base off-mesh connection start points
            for (int i = 0; i < OffMeshConnectionCount; i++)
            {
                int con = i;
                OffMeshConnection omc = OffMeshConnections[con];

                Vector3 extents = new Vector3(omc.Radius, WalkableClimb, omc.Radius);

                //Find polygon to connect to
                Vector3 p         = omc.Pos0;
                Vector3 nearestPt = new Vector3();
                PolyId  reference = FindNearestPoly(p, extents, ref nearestPt);
                if (reference == PolyId.Null)
                {
                    continue;
                }

                //Do extra checks
                if ((nearestPt.X - p.X) * (nearestPt.X - p.X) + (nearestPt.Z - p.Z) * (nearestPt.Z - p.Z) >
                    OffMeshConnections[con].Radius * OffMeshConnections[con].Radius)
                {
                    continue;
                }

                Poly poly = this.Polys[omc.Poly];

                //Make sure location is on current mesh
                Verts[poly.Verts[0]] = nearestPt;

                Link link = new Link();
                link.Reference = reference;
                link.Edge      = 0;
                link.Side      = BoundarySide.Internal;
                poly.Links.Add(link);

                //Start end-point always conects back to off-mesh connection
                int    landPolyIdx = idManager.DecodePolyIndex(ref reference);
                PolyId id;
                idManager.SetPolyIndex(ref baseRef, OffMeshConnections[con].Poly, out id);

                Link link2 = new Link();
                link2.Reference = id;
                link2.Edge      = 0xff;
                link2.Side      = BoundarySide.Internal;
                Polys[landPolyIdx].Links.Add(link2);
            }
        }
Example #5
0
        /// <summary>
        /// Given a point, find the closest point on that poly.
        /// </summary>
        /// <param name="poly">The current polygon.</param>
        /// <param name="pos">The current position</param>
        /// <param name="closest">Reference to the closest point</param>
        public void ClosestPointOnPoly(Poly poly, Vector3 pos, ref Vector3 closest)
        {
            int indexPoly = 0;

            for (int i = 0; i < Polys.Length; i++)
            {
                if (Polys[i] == poly)
                {
                    indexPoly = i;
                    break;
                }
            }

            ClosestPointOnPoly(indexPoly, pos, ref closest);
        }
Example #6
0
        /// <summary>
        /// Given a point, find the closest point on that poly.
        /// </summary>
        /// <param name="indexPoly">The current poly's index</param>
        /// <param name="pos">The current position</param>
        /// <param name="closest">Reference to the closest point</param>
        public void ClosestPointOnPoly(int indexPoly, Vector3 pos, ref Vector3 closest)
        {
            Poly poly = Polys[indexPoly];

            //Off-mesh connections don't have detail polygons
            if (Polys[indexPoly].PolyType == PolygonType.OffMeshConnection)
            {
                ClosestPointOnPolyOffMeshConnection(poly, pos, out closest);
                return;
            }

            ClosestPointOnPolyBoundary(poly, pos, out closest);

            float h;

            if (ClosestHeight(indexPoly, pos, out h))
            {
                closest.Y = h;
            }
        }
Example #7
0
        /// <summary>
        /// Given a point, find the closest point on that poly.
        /// </summary>
        /// <param name="poly">The current polygon.</param>
        /// <param name="pos">The current position</param>
        /// <param name="closest">Reference to the closest point</param>
        public void ClosestPointOnPolyBoundary(Poly poly, Vector3 pos, out Vector3 closest)
        {
            //Clamp point to be inside the polygon
            Vector3[] verts        = new Vector3[PathfindingCommon.VERTS_PER_POLYGON];
            float[]   edgeDistance = new float[PathfindingCommon.VERTS_PER_POLYGON];
            float[]   edgeT        = new float[PathfindingCommon.VERTS_PER_POLYGON];
            int       numPolyVerts = poly.VertCount;

            for (int i = 0; i < numPolyVerts; i++)
            {
                verts[i] = Verts[poly.Verts[i]];
            }

            bool inside = Distance.PointToPolygonEdgeSquared(pos, verts, numPolyVerts, edgeDistance, edgeT);

            if (inside)
            {
                //Point is inside the polygon
                closest = pos;
            }
            else
            {
                //Point is outside the polygon
                //Clamp to nearest edge
                float minDistance = float.MaxValue;
                int   minIndex    = -1;
                for (int i = 0; i < numPolyVerts; i++)
                {
                    if (edgeDistance[i] < minDistance)
                    {
                        minDistance = edgeDistance[i];
                        minIndex    = i;
                    }
                }

                Vector3 va = verts[minIndex];
                Vector3 vb = verts[(minIndex + 1) % numPolyVerts];
                closest = Vector3.Lerp(va, vb, edgeT[minIndex]);
            }
        }
Example #8
0
 /// <summary>
 /// Find the closest point on an offmesh connection, which is in between the two points.
 /// </summary>
 /// <param name="poly">Current polygon</param>
 /// <param name="pos">Current position</param>
 /// <param name="closest">Resulting point that is closest.</param>
 public void ClosestPointOnPolyOffMeshConnection(Poly poly, Vector3 pos, out Vector3 closest)
 {
     Vector3 v0 = Verts[poly.Verts[0]];
     Vector3 v1 = Verts[poly.Verts[1]];
     float d0 = (pos - v0).Length();
     float d1 = (pos - v1).Length();
     float u = d0 / (d0 + d1);
     closest = Vector3.Lerp(v0, v1, u);
 }
Example #9
0
        /// <summary>
        /// Retrieve the tile and poly based off of a polygon reference
        /// </summary>
        /// <param name="reference">Polygon reference</param>
        /// <param name="tile">Resulting tile</param>
        /// <param name="poly">Resulting poly</param>
        /// <returns>True if tile and poly successfully retrieved</returns>
        public bool TryGetTileAndPolyByRef(int reference, out MeshTile tile, out Poly poly)
        {
            tile = null;
            poly = null;

            if (reference == 0)
                return false;

            //Get tile and poly indices
            int salt = 0, indexTile = 0, indexPoly = 0;
            DecodePolyId(reference, ref salt, ref indexTile, ref indexPoly);

            //Make sure indices are valid
            if (indexTile >= maxTiles)
                return false;

            if (tiles[indexTile].Salt != salt || tiles[indexTile].Header == null)
                return false;

            if (indexPoly >= tiles[indexTile].Header.PolyCount)
                return false;

            //Retrieve tile and poly
            tile = tiles[indexTile];
            poly = tiles[indexTile].Polys[indexPoly];
            return true;
        }
Example #10
0
        /// <summary>
        /// Find points on the left and right side.
        /// </summary>
        /// <param name="from">"From" polygon reference</param>
        /// <param name="fromPoly">"From" polygon data</param>
        /// <param name="fromTile">"From" mesh tile</param>
        /// <param name="to">"To" polygon reference</param>
        /// <param name="toPoly">"To" polygon data</param>
        /// <param name="toTile">"To" mesh tile</param>
        /// <param name="left">Resulting point on the left side</param>
        /// <param name="right">Resulting point on the right side</param>
        /// <returns>True, if points found. False, if otherwise.</returns>
        public bool GetPortalPoints(PolyId from, Poly fromPoly, MeshTile fromTile, PolyId to, Poly toPoly, MeshTile toTile, ref Vector3 left, ref Vector3 right)
        {
            //find the link that points to the 'to' polygon
            Link link = null;
            for (int i = fromPoly.FirstLink; i != Link.Null; i = fromTile.Links[i].Next)
            {
                if (fromTile.Links[i].Reference == to)
                {
                    link = fromTile.Links[i];
                    break;
                }
            }

            if (link == null)
                return false;

            //handle off-mesh connections
            if (fromPoly.PolyType == PolygonType.OffMeshConnection)
            {
                //find link that points to first vertex
                for (int i = fromPoly.FirstLink; i != Link.Null; i = fromTile.Links[i].Next)
                {
                    if (fromTile.Links[i].Reference == to)
                    {
                        int v = fromTile.Links[i].Edge;
                        left = fromTile.Verts[fromPoly.Verts[v]];
                        right = fromTile.Verts[fromPoly.Verts[v]];
                        return true;
                    }
                }

                return false;
            }

            if (toPoly.PolyType == PolygonType.OffMeshConnection)
            {
                //find link that points to first vertex
                for (int i = toPoly.FirstLink; i != Link.Null; i = toTile.Links[i].Next)
                {
                    if (toTile.Links[i].Reference == from)
                    {
                        int v = toTile.Links[i].Edge;
                        left = toTile.Verts[toPoly.Verts[v]];
                        right = toTile.Verts[toPoly.Verts[v]];
                        return true;
                    }
                }

                return false;
            }

            //find portal vertices
            int v0 = fromPoly.Verts[link.Edge];
            int v1 = fromPoly.Verts[(link.Edge + 1) % fromPoly.VertCount];
            left = fromTile.Verts[v0];
            right = fromTile.Verts[v1];

            //if the link is at the tile boundary, clamp the vertices to tile width
            if (link.Side != BoundarySide.Internal)
            {
                //unpack portal limits
                if (link.BMin != 0 || link.BMax != 255)
                {
                    float s = 1.0f / 255.0f;
                    float tmin = link.BMin * s;
                    float tmax = link.BMax * s;
                    left = Vector3.Lerp(fromTile.Verts[v0], fromTile.Verts[v1], tmin);
                    right = Vector3.Lerp(fromTile.Verts[v0], fromTile.Verts[v1], tmax);
                }
            }

            return true;
        }
Example #11
0
        /// <summary>
        /// Connect Off-Mesh links between polygons from two different tiles.
        /// </summary>
        /// <param name="target">Target Tile</param>
        /// <param name="side">Polygon edge</param>
        public void ConnectExtOffMeshLinks(MeshTile target, BoundarySide side)
        {
            //Connect off-mesh links, specifically links which land from target tile to this tile
            BoundarySide oppositeSide = side.GetOpposite();

            //Iterate through all the off-mesh connections of target tile
            for (int i = 0; i < target.OffMeshConnectionCount; i++)
            {
                OffMeshConnection targetCon = target.OffMeshConnections[i];
                if (targetCon.Side != oppositeSide)
                {
                    continue;
                }

                Poly targetPoly = target.Polys[targetCon.Poly];

                //Skip off-mesh connections which start location could not be connected at all
                if (targetPoly.Links.Count == 0)
                {
                    continue;
                }

                Vector3 extents = new Vector3(targetCon.Radius, target.WalkableClimb, targetCon.Radius);

                //Find polygon to connect to
                Vector3 p         = targetCon.Pos1;
                Vector3 nearestPt = new Vector3();
                PolyId  reference = FindNearestPoly(p, extents, ref nearestPt);
                if (reference == PolyId.Null)
                {
                    continue;
                }

                //Further checks
                if ((nearestPt.X - p.X) * (nearestPt.X - p.X) + (nearestPt.Z - p.Z) * (nearestPt.Z - p.Z) >
                    (targetCon.Radius * targetCon.Radius))
                {
                    continue;
                }

                //Make sure the location is on the current mesh
                target.Verts[targetPoly.Verts[1]] = nearestPt;

                //Link off-mesh connection to target poly
                Link link = new Link();
                link.Reference = reference;
                link.Edge      = i;
                link.Side      = oppositeSide;
                target.Polys[i].Links.Add(link);

                //link target poly to off-mesh connection
                if ((targetCon.Flags & OffMeshConnectionFlags.Bidirectional) != 0)
                {
                    int    landPolyIdx = idManager.DecodePolyIndex(ref reference);
                    PolyId id;
                    id = target.baseRef;
                    idManager.SetPolyIndex(ref id, targetCon.Poly, out id);

                    Link bidiLink = new Link();
                    bidiLink.Reference = id;
                    bidiLink.Edge      = 0xff;
                    bidiLink.Side      = side;
                    Polys[landPolyIdx].Links.Add(bidiLink);
                }
            }
        }
Example #12
0
 /// <summary>
 /// The cost between two points may vary depending on the type of polygon.
 /// </summary>
 /// <param name="pa">Point A</param>
 /// <param name="pb">Point B</param>
 /// <param name="curPoly">Current polygon</param>
 /// <returns>Cost</returns>
 public float GetCost(Vector3 pa, Vector3 pb, Poly curPoly)
 {
     return (pa - pb).Length() * areaCost[(int)curPoly.Area.Id];
 }
Example #13
0
        /// <summary>
        /// Get edge midpoint between two prolygons
        /// </summary>
        /// <param name="from">"From" polygon reference</param>
        /// <param name="fromPoly">"From" polygon data</param>
        /// <param name="fromTile">"From" mesh tile</param>
        /// <param name="to">"To" polygon reference</param>
        /// <param name="toPoly">"To" polygon data</param>
        /// <param name="toTile">"To" mesh tile</param>
        /// <param name="mid">Edge midpoint</param>
        /// <returns>True, if midpoint found. False, if otherwise.</returns>
        public bool GetEdgeMidPoint(PolyId from, Poly fromPoly, MeshTile fromTile, PolyId to, Poly toPoly, MeshTile toTile, ref Vector3 mid)
        {
            Vector3 left = new Vector3();
            Vector3 right = new Vector3();
            if (!GetPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, ref left, ref right))
                return false;

            mid = (left + right) * 0.5f;

            return true;
        }
Example #14
0
 /// <summary>
 /// Finds a random point on a polygon.
 /// </summary>
 /// <param name="tile">The current mesh tile</param>
 /// <param name="poly">The current polygon</param>
 /// <param name="polyRef">Polygon reference</param>
 /// <returns>Resulting random point</returns>
 public Vector3 FindRandomPointOnPoly(MeshTile tile, Poly poly, PolyId polyRef)
 {
     Vector3 result;
     this.FindRandomPointOnPoly(tile, poly, polyRef, out result);
     return result;
 }
Example #15
0
        /// <summary>
        /// Finds a random point on a polygon.
        /// </summary>
        /// <param name="tile">The current mesh tile</param>
        /// <param name="poly">The current polygon</param>
        /// <param name="polyRef">Polygon reference</param>
        /// <param name="randomPt">Resulting random point</param>
        public void FindRandomPointOnPoly(MeshTile tile, Poly poly, PolyId polyRef, out Vector3 randomPt)
        {
            Vector3[] verts = new Vector3[PathfindingCommon.VERTS_PER_POLYGON];
            float[] areas = new float[PathfindingCommon.VERTS_PER_POLYGON];
            for (int j = 0; j < poly.VertCount; j++)
                verts[j] = tile.Verts[poly.Verts[j]];

            float s = (float)rand.NextDouble();
            float t = (float)rand.NextDouble();

            PathfindingCommon.RandomPointInConvexPoly(verts, poly.VertCount, areas, s, t, out randomPt);

            //TODO bad state again.
            float h = 0.0f;
            if (!GetPolyHeight(polyRef, randomPt, ref h))
                throw new InvalidOperationException("Outside bounds?");

            randomPt.Y = h;
        }
Example #16
0
        /// <summary>
        /// Given a point, find the closest point on that poly.
        /// </summary>
        /// <param name="poly">The current polygon.</param>
        /// <param name="pos">The current position</param>
        /// <param name="closest">Reference to the closest point</param>
        public void ClosestPointOnPolyBoundary(Poly poly, Vector3 pos, out Vector3 closest)
        {
            //Clamp point to be inside the polygon
            Vector3[] verts = new Vector3[PathfindingCommon.VERTS_PER_POLYGON];
            float[] edgeDistance = new float[PathfindingCommon.VERTS_PER_POLYGON];
            float[] edgeT = new float[PathfindingCommon.VERTS_PER_POLYGON];
            int numPolyVerts = poly.VertCount;
            for (int i = 0; i < numPolyVerts; i++)
                verts[i] = Verts[poly.Verts[i]];

            bool inside = Distance.PointToPolygonEdgeSquared(pos, verts, numPolyVerts, edgeDistance, edgeT);
            if (inside)
            {
                //Point is inside the polygon
                closest = pos;
            }
            else
            {
                //Point is outside the polygon
                //Clamp to nearest edge
                float minDistance = float.MaxValue;
                int minIndex = -1;
                for (int i = 0; i < numPolyVerts; i++)
                {
                    if (edgeDistance[i] < minDistance)
                    {
                        minDistance = edgeDistance[i];
                        minIndex = i;
                    }
                }

                Vector3 va = verts[minIndex];
                Vector3 vb = verts[(minIndex + 1) % numPolyVerts];
                closest = Vector3.Lerp(va, vb, edgeT[minIndex]);
            }
        }
Example #17
0
		/// <summary>
		/// Only use this function if it is known that the provided polygon reference is valid.
		/// </summary>
		/// <param name="reference">Polygon reference</param>
		/// <param name="tile">Resulting tile</param>
		/// <param name="poly">Resulting poly</param>
		public void TryGetTileAndPolyByRefUnsafe(PolyId reference, out MeshTile tile, out Poly poly)
		{
			int salt, polyIndex, tileIndex;
			idManager.Decode(ref reference, out polyIndex, out tileIndex, out salt);
			tile = tileList[tileIndex];
			poly = tileList[tileIndex].Polys[polyIndex];
		}
Example #18
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++;
				}
			}
		}
Example #19
0
 /// <summary>
 /// Only use this function if it is known that the provided polygon reference is valid.
 /// </summary>
 /// <param name="reference">Polygon reference</param>
 /// <param name="tile">Resulting tile</param>
 /// <param name="poly">Resulting poly</param>
 public void TryGetTileAndPolyByRefUnsafe(PolyId reference, out MeshTile tile, out Poly poly)
 {
     int salt, polyIndex, tileIndex;
     reference.Decode(polyBits, tileBits, saltBits, out polyIndex, out tileIndex, out salt);
     tile = tiles[tileIndex];
     poly = tiles[tileIndex].Polys[polyIndex];
 }
Example #20
0
        /// <summary>
        /// Retrieve the tile and poly based off of a polygon reference
        /// </summary>
        /// <param name="reference">Polygon reference</param>
        /// <param name="tile">Resulting tile</param>
        /// <param name="poly">Resulting poly</param>
        /// <returns>True if tile and poly successfully retrieved</returns>
        public bool TryGetTileAndPolyByRef(PolyId reference, out MeshTile tile, out Poly poly)
        {
            tile = null;
            poly = null;

            if (reference == PolyId.Null)
                return false;

            //Get tile and poly indices
            int salt, polyIndex, tileIndex;
            reference.Decode(polyBits, tileBits, saltBits, out polyIndex, out tileIndex, out salt);

            //Make sure indices are valid
            if (tileIndex >= maxTiles)
                return false;

            if (tiles[tileIndex].Salt != salt || tiles[tileIndex].Header == null)
                return false;

            if (polyIndex >= tiles[tileIndex].Header.PolyCount)
                return false;

            //Retrieve tile and poly
            tile = tiles[tileIndex];
            poly = tiles[tileIndex].Polys[polyIndex];
            return true;
        }
Example #21
0
 /// <summary>
 /// Only use this function if it is known that the provided polygon reference is valid.
 /// </summary>
 /// <param name="reference">Polygon reference</param>
 /// <param name="tile">Resulting tile</param>
 /// <param name="poly">Resulting poly</param>
 public void TryGetTileAndPolyByRefUnsafe(int reference, out MeshTile tile, out Poly poly)
 {
     int salt = 0, indexTile = 0, indexPoly = 0;
     DecodePolyId(reference, ref salt, ref indexTile, ref indexPoly);
     tile = tiles[indexTile];
     poly = tiles[indexTile].Polys[indexPoly];
 }
Example #22
0
        /// <summary>
        /// Given a point, find the closest point on that poly.
        /// </summary>
        /// <param name="poly">The current polygon.</param>
        /// <param name="pos">The current position</param>
        /// <param name="closest">Reference to the closest point</param>
        public void ClosestPointOnPoly(Poly poly, Vector3 pos, ref Vector3 closest)
        {
            int indexPoly = 0;
            for (int i = 0; i < Polys.Length; i++)
            {
                if (Polys[i] == poly)
                {
                    indexPoly = i;
                    break;
                }
            }

            ClosestPointOnPoly(indexPoly, pos, ref closest);
        }