public static void OutputVertices() { NavmeshTile tile = navmesh.GetTile(0); float[] headerVerts = new float[tile.GetHeader().vertCount * 3]; org.critterai.Vector3[] buffer = new org.critterai.Vector3[tile.GetHeader().vertCount * 3]; tile.GetVerts(buffer); string filename = "Vertices.txt"; if (File.Exists(filename)) { File.Delete(filename); } File.AppendAllText(filename, "Left List is Raw (vertcount = " + vertCount + "), Right List is From Header (vertcount = " + tile.GetHeader().vertCount + ") (you might see data loss, as converted in/out of grid space.) \n\n"); for (int i = 0; i < vertCount; i++) { File.AppendAllText(filename, "Vertex " + i + ": x: " + vertices[i].x + " y: " + vertices[i].y + " z: " + vertices[i].z + "\t\t|"); File.AppendAllText(filename, "Vertex " + i + ": x: " + buffer[3 * i + 0].x + " y: " + headerVerts[3 * i + 1] + " z: " + headerVerts[3 * i + 2] + "\n"); } }
private void SetConfigFromTargetIntern(Navmesh navmesh) { NavmeshBuildInfo targetConfig = BuildTarget.BuildInfo; NMGenParams currConfig = mConfig.GetConfig(); // Note: Must ensure exact match with original configuration. // So this process is using the fields and trusting the // original configuration to have valid values. currConfig.tileSize = targetConfig.tileSize; currConfig.walkableHeight = targetConfig.walkableHeight; currConfig.walkableRadius = targetConfig.walkableRadius; currConfig.walkableStep = targetConfig.walkableStep; currConfig.xzCellSize = targetConfig.xzCellSize; currConfig.yCellSize = targetConfig.yCellSize; currConfig.borderSize = targetConfig.borderSize; mBoundsMin = navmesh.GetConfig().origin; int maxTiles = navmesh.GetMaxTiles(); // Make sure the maximum bounds fits the target mesh. // Note: Will not shrink the existing max bounds. for (int i = 0; i < maxTiles; i++) { NavmeshTile tile = navmesh.GetTile(i); if (tile == null) { continue; } NavmeshTileHeader tileHeader = tile.GetHeader(); if (tileHeader.polyCount == 0) { continue; } mBoundsMax = Vector3.Max(mBoundsMax, tileHeader.boundsMax); } mConfig.SetConfig(currConfig); mIsDirty = true; }
/// <summary> /// Gets the centroids for the polygons that are part of the tile. /// </summary> private static int GetCentroids(NavmeshTile tile , uint[] polyRefs , int polyCount , UnityEngine.Vector3[] centroids) { NavmeshTileHeader header = tile.GetHeader(); if (header.polyCount < 1) { return(0); } uint polyBase = tile.GetBasePolyRef(); NavmeshPoly[] polys = new NavmeshPoly[header.polyCount]; tile.GetPolys(polys); Vector3[] verts = new Vector3[header.vertCount]; tile.GetVerts(verts); UnityEngine.Vector3[] vverts = VectorHelper.ToUnityVector3Array(ref verts); int resultCount = 0; for (int i = 0; i < header.polyCount; i++) { uint polyRef = polyBase | ( uint )i; int iResult = IsInList(polyRef, polyRefs, polyCount); if (iResult == -1) { continue; } resultCount++; NavmeshPoly poly = polys[i]; centroids[iResult] = GetCentroid(vverts, poly.indices, poly.vertCount); } return(resultCount); }
/// <summary> /// Draws a debug visualization of an individual navmesh tile. /// </summary> /// <remarks> /// <para> /// The tile will be checked to see if it is in use before it is drawn. So there is no /// need for caller to do so. /// </para> /// </remarks> private static void Draw(NavmeshTile tile , NavmeshQuery query, uint[] markPolys, int markPolyCount , int colorId) { NavmeshTileHeader header = tile.GetHeader(); // Keep this check. Less trouble for clients. if (header.polyCount < 1) { return; } DebugDraw.SimpleMaterial.SetPass(0); uint polyBase = tile.GetBasePolyRef(); NavmeshPoly[] polys = new NavmeshPoly[header.polyCount]; tile.GetPolys(polys); Vector3[] verts = new Vector3[header.vertCount]; tile.GetVerts(verts); NavmeshDetailMesh[] meshes = new NavmeshDetailMesh[header.detailMeshCount]; tile.GetDetailMeshes(meshes); byte[] detailTris = new byte[header.detailTriCount * 4]; tile.GetDetailTris(detailTris); Vector3[] detailVerts = new Vector3[header.detailVertCount]; tile.GetDetailVerts(detailVerts); GL.Begin(GL.TRIANGLES); for (int i = 0; i < header.polyCount; i++) { NavmeshPoly poly = polys[i]; if (poly.Type == NavmeshPolyType.OffMeshConnection) { continue; } NavmeshDetailMesh mesh = meshes[i]; Color color = GetStandardColor(polyBase | (uint)i , poly.Area, colorId , query, markPolys, markPolyCount); GL.Color(color); for (int j = 0; j < mesh.triCount; j++) { int pTri = (int)(mesh.triBase + j) * 4; for (int k = 0; k < 3; k++) { // Note: iVert and pVert refer to different // arrays. int iVert = detailTris[pTri + k]; if (iVert < poly.vertCount) { // Get the vertex from the main vertices. int pVert = poly.indices[iVert]; GL.Vertex(verts[pVert]); } else { // Get the vertex from the detail vertices. int pVert = (int) (mesh.vertBase + iVert - poly.vertCount); GL.Vertex(detailVerts[pVert]); } } } } GL.End(); NavmeshLink[] links = new NavmeshLink[header.maxLinkCount]; tile.GetLinks(links); GL.Begin(GL.LINES); DrawPolyBoundaries(header , polys , verts , meshes , detailTris , detailVerts , links , new Color(0, 0.2f, 0.25f, 0.13f) , true); DrawPolyBoundaries(header , polys , verts , meshes , detailTris , detailVerts , links , new Color(0.65f, 0.2f, 0, 0.9f) , false); if (header.connCount == 0) { GL.End(); return; } NavmeshConnection[] conns = new NavmeshConnection[header.connCount]; tile.GetConnections(conns); for (int i = 0; i < header.polyCount; i++) { NavmeshPoly poly = polys[i]; if (poly.Type != NavmeshPolyType.OffMeshConnection) { continue; } Color color = GetStandardColor(polyBase | (uint)i , poly.Area, colorId , query, markPolys, markPolyCount); // Note: Alpha of less than one doesn't look good because connections tend to // overlay a lot of geometry, resulting is off color transitions. color.a = 1; GL.Color(color); NavmeshConnection conn = conns[i - header.connBase]; Vector3 va = verts[poly.indices[0]]; Vector3 vb = verts[poly.indices[1]]; // Check to see if start and end end-points have links. bool startSet = false; bool endSet = false; for (uint k = poly.firstLink; k != Navmesh.NullLink; k = links[k].next) { if (links[k].edge == 0) { startSet = true; } if (links[k].edge == 1) { endSet = true; } } // For linked endpoints: Draw a line between on-mesh location and endpoint, // and draw circle at the endpoint. // For un-linked endpoints: Draw a small red x-marker. if (startSet) { GL.Vertex(va); GL.Vertex(conn.endpoints[0]); DebugDraw.AppendCircle(conn.endpoints[0], conn.radius); } else { GL.Color(Color.red); DebugDraw.AppendXMarker(conn.endpoints[0], 0.1f); GL.Color(color); } if (endSet) { GL.Vertex(vb); GL.Vertex(conn.endpoints[1]); DebugDraw.AppendCircle(conn.endpoints[1], conn.radius); } else { GL.Color(Color.red); DebugDraw.AppendXMarker(conn.endpoints[1], 0.1f); GL.Color(color); } DebugDraw.AppendArc(conn.endpoints[0], conn.endpoints[1] , 0.25f , conn.IsBiDirectional ? 0.6f : 0 , 0.6f); } GL.End(); }
internal bool CanLoadFromTarget(BuildContext context, bool fullCheck) { INavmeshData target = BuildTarget; if (target == null || !target.HasNavmesh) { if (context != null) { context.LogError("Build target does not have an existing navigation mesh.", this); } return(false); } NavmeshBuildInfo targetConfig = target.BuildInfo; // Note: The tile size is checked since the original builder // may have supported a tile size not supported by the the standard build. if (targetConfig == null || targetConfig.tileSize >= 0 && targetConfig.tileSize < MinAllowedTileSize) { if (context != null) { context.LogError("Unavailable or unsupported build target configuration.", this); } return(false); } if (!fullCheck) { return(true); } Navmesh nm = target.GetNavmesh(); if (nm == null) { if (context != null) { context.LogError( "Build target does not have an existing navigation mesh. (It lied.)", this); } return(false); } NavmeshParams nmConfig = nm.GetConfig(); if (nmConfig.maxTiles < 2) { if (context != null) { context.LogError("Target navigation mesh is not tiled.", this); } return(false); } int tileCount = 0; for (int i = 0; i < nmConfig.maxTiles; i++) { NavmeshTile tile = nm.GetTile(i); if (tile == null) { continue; } NavmeshTileHeader header = tile.GetHeader(); if (header.polyCount == 0) { continue; } tileCount++; if (header.layer > 0) { if (context != null) { context.LogError( "Target navigation mesh contains layered tiles. (Not supported.)", this); } return(false); } } if (tileCount < 2) { if (context != null) { context.LogError( "Target navigation mesh is either not tiled or has no tiles loaded.", this); } return(false); } return(true); }
/// <summary> /// Gets the centroids for the polygons that are part of the tile. /// </summary> private static int GetCentroids(NavmeshTile tile , uint[] polyRefs , int polyCount , Vector3[] centroids) { NavmeshTileHeader header = tile.GetHeader(); if (header.polyCount < 1) return 0; uint polyBase = tile.GetBasePolyRef(); NavmeshPoly[] polys = new NavmeshPoly[header.polyCount]; tile.GetPolys(polys); Vector3[] verts = new Vector3[header.vertCount]; tile.GetVerts(verts); int resultCount = 0; for (int i = 0; i < header.polyCount; i++) { uint polyRef = polyBase | (uint)i; int iResult = IsInList(polyRef, polyRefs, polyCount); if (iResult == -1) continue; resultCount++; NavmeshPoly poly = polys[i]; centroids[iResult] = GetCentroid(verts, poly.indices, poly.vertCount); } return resultCount; }
/// <summary> /// Draws a debug visualization of an individual navmesh tile. /// </summary> /// <remarks> /// <para> /// The tile will be checked to see if it is in use before it is drawn. So there is no /// need for caller to do so. /// </para> /// </remarks> private static void Draw(NavmeshTile tile , NavmeshQuery query, uint[] markPolys, int markPolyCount , int colorId) { NavmeshTileHeader header = tile.GetHeader(); // Keep this check. Less trouble for clients. if (header.polyCount < 1) return; DebugDraw.SimpleMaterial.SetPass(0); uint polyBase = tile.GetBasePolyRef(); NavmeshPoly[] polys = new NavmeshPoly[header.polyCount]; tile.GetPolys(polys); Vector3[] verts = new Vector3[header.vertCount]; tile.GetVerts(verts); NavmeshDetailMesh[] meshes = new NavmeshDetailMesh[header.detailMeshCount]; tile.GetDetailMeshes(meshes); byte[] detailTris = new byte[header.detailTriCount * 4]; tile.GetDetailTris(detailTris); Vector3[] detailVerts = new Vector3[header.detailVertCount]; tile.GetDetailVerts(detailVerts); GL.Begin(GL.TRIANGLES); for (int i = 0; i < header.polyCount; i++) { NavmeshPoly poly = polys[i]; if (poly.Type == NavmeshPolyType.OffMeshConnection) continue; NavmeshDetailMesh mesh = meshes[i]; Color color = GetStandardColor(polyBase | (uint)i , poly.Area, colorId , query, markPolys, markPolyCount); GL.Color(color); for (int j = 0; j < mesh.triCount; j++) { int pTri = (int)(mesh.triBase + j) * 4; for (int k = 0; k < 3; k++) { // Note: iVert and pVert refer to different // arrays. int iVert = detailTris[pTri + k]; if (iVert < poly.vertCount) { // Get the vertex from the main vertices. int pVert = poly.indices[iVert]; GL.Vertex(verts[pVert]); } else { // Get the vertex from the detail vertices. int pVert = (int) (mesh.vertBase + iVert - poly.vertCount); GL.Vertex(detailVerts[pVert]); } } } } GL.End(); NavmeshLink[] links = new NavmeshLink[header.maxLinkCount]; tile.GetLinks(links); GL.Begin(GL.LINES); DrawPolyBoundaries(header , polys , verts , meshes , detailTris , detailVerts , links , new Color(0, 0.2f, 0.25f, 0.13f) , true); DrawPolyBoundaries(header , polys , verts , meshes , detailTris , detailVerts , links , new Color(0.65f, 0.2f, 0, 0.9f) , false); if (header.connCount == 0) { GL.End(); return; } NavmeshConnection[] conns = new NavmeshConnection[header.connCount]; tile.GetConnections(conns); for (int i = 0; i < header.polyCount; i++) { NavmeshPoly poly = polys[i]; if (poly.Type != NavmeshPolyType.OffMeshConnection) continue; Color color = GetStandardColor(polyBase | (uint)i , poly.Area, colorId , query, markPolys, markPolyCount); // Note: Alpha of less than one doesn't look good because connections tend to // overlay a lot of geometry, resulting is off color transitions. color.a = 1; GL.Color(color); NavmeshConnection conn = conns[i - header.connBase]; Vector3 va = verts[poly.indices[0]]; Vector3 vb = verts[poly.indices[1]]; // Check to see if start and end end-points have links. bool startSet = false; bool endSet = false; for (uint k = poly.firstLink; k != Navmesh.NullLink; k = links[k].next) { if (links[k].edge == 0) startSet = true; if (links[k].edge == 1) endSet = true; } // For linked endpoints: Draw a line between on-mesh location and endpoint, // and draw circle at the endpoint. // For un-linked endpoints: Draw a small red x-marker. if (startSet) { GL.Vertex(va); GL.Vertex(conn.endpoints[0]); DebugDraw.AppendCircle(conn.endpoints[0], conn.radius); } else { GL.Color(Color.red); DebugDraw.AppendXMarker(conn.endpoints[0], 0.1f); GL.Color(color); } if (endSet) { GL.Vertex(vb); GL.Vertex(conn.endpoints[1]); DebugDraw.AppendCircle(conn.endpoints[1], conn.radius); } else { GL.Color(Color.red); DebugDraw.AppendXMarker(conn.endpoints[1], 0.1f); GL.Color(color); } DebugDraw.AppendArc(conn.endpoints[0], conn.endpoints[1] , 0.25f , conn.IsBiDirectional ? 0.6f : 0 , 0.6f); } GL.End(); }