public GetNodes ( GraphNodeDelegateCancelable del ) : void | ||
del | GraphNodeDelegateCancelable | |
리턴 | void |
/// <summary> /// ³õʼ»¯graphNodeÕ¤¸ñÆ÷ /// </summary> public void InitRasterizer(int inCellSize = 4000) { if (this.graphs == null || this.graphs.Length == 0) { return; } rasterizer = new GraphNodeRasterizer(); Int2 min = new Int2(2147483647, 2147483647); Int2 max = new Int2(-2147483648, -2147483648); for (int j = 0; j < this.graphs.Length; j++) { RecastGraph recastGraph2 = this.graphs[j] as RecastGraph; if (recastGraph2 == null) { return; } recastGraph2.GetNodes(delegate(GraphNode node) { TriangleMeshNode triangleMeshNode = node as TriangleMeshNode; if (triangleMeshNode != null) { Int2 xz = triangleMeshNode.GetVertex(0).xz; Int2 xz2 = triangleMeshNode.GetVertex(1).xz; Int2 xz3 = triangleMeshNode.GetVertex(2).xz; min.Min(ref xz); min.Min(ref xz2); min.Min(ref xz3); max.Max(ref xz); max.Max(ref xz2); max.Max(ref xz3); } return(true); }); } rasterizer.Init(min, max.x - min.x, max.y - min.y, inCellSize); for (int k = 0; k < this.graphs.Length; k++) { RecastGraph recastGraph3 = this.graphs[k] as RecastGraph; if (recastGraph3 != null) { recastGraph3.GetNodes(delegate(GraphNode node) { TriangleMeshNode triangleMeshNode = node as TriangleMeshNode; if (triangleMeshNode != null) { Int2 xz = triangleMeshNode.GetVertex(0).xz; Int2 xz2 = triangleMeshNode.GetVertex(1).xz; Int2 xz3 = triangleMeshNode.GetVertex(2).xz; rasterizer.AddTriangle(ref xz, ref xz2, ref xz3, triangleMeshNode); } return(true); }); } } }
public GraphNodeRasterizer InitRasterizer(int inCellSize, bool bUseForceBoundsSize = false) { if (this.graphs == null || this.graphs.Length == 0) { return(null); } GraphNodeRasterizer r = new GraphNodeRasterizer(); VInt2 min = new VInt2(2147483647, 2147483647); VInt2 max = new VInt2(-2147483648, -2147483648); if (bUseForceBoundsSize) { for (int i = 0; i < this.graphs.Length; i++) { RecastGraph recastGraph = this.graphs[i] as RecastGraph; if (recastGraph == null) { return(null); } VInt2 vInt = new VInt2((int)(recastGraph.forcedBounds.min.x * 1000f), (int)(recastGraph.forcedBounds.min.z * 1000f)); VInt2 vInt2 = new VInt2((int)(recastGraph.forcedBounds.max.x * 1000f), (int)(recastGraph.forcedBounds.max.z * 1000f)); min.Min(ref vInt); max.Max(ref vInt2); } r.Init(min, max.x - min.x, max.y - min.y, inCellSize); } else { for (int j = 0; j < this.graphs.Length; j++) { RecastGraph recastGraph2 = this.graphs[j] as RecastGraph; if (recastGraph2 == null) { return(null); } recastGraph2.GetNodes(delegate(GraphNode node) { TriangleMeshNode triangleMeshNode = node as TriangleMeshNode; if (triangleMeshNode != null) { VInt2 xz = triangleMeshNode.GetVertex(0).xz; VInt2 xz2 = triangleMeshNode.GetVertex(1).xz; VInt2 xz3 = triangleMeshNode.GetVertex(2).xz; min.Min(ref xz); min.Min(ref xz2); min.Min(ref xz3); max.Max(ref xz); max.Max(ref xz2); max.Max(ref xz3); } return(true); }); } r.Init(min, max.x - min.x, max.y - min.y, inCellSize); } for (int k = 0; k < this.graphs.Length; k++) { RecastGraph recastGraph3 = this.graphs[k] as RecastGraph; if (recastGraph3 != null) { recastGraph3.GetNodes(delegate(GraphNode node) { TriangleMeshNode triangleMeshNode = node as TriangleMeshNode; if (triangleMeshNode != null) { VInt2 xz = triangleMeshNode.GetVertex(0).xz; VInt2 xz2 = triangleMeshNode.GetVertex(1).xz; VInt2 xz3 = triangleMeshNode.GetVertex(2).xz; r.AddTriangle(ref xz, ref xz2, ref xz3, triangleMeshNode); } return(true); }); } } return(r); }
public static IEnumerable <Progress> ScanAllTiles(this RecastGraph self) { self.transform = self.CalculateTransform(); self.InitializeTileInfo(); // If this is true, just fill the graph with empty tiles if (self.scanEmptyGraph) { self.FillWithEmptyTiles(); yield break; } // A walkableClimb higher than walkableHeight can cause issues when generating the navmesh since then it can in some cases // Both be valid for a character to walk under an obstacle and climb up on top of it (and that cannot be handled with navmesh without links) // The editor scripts also enforce this but we enforce it here too just to be sure self.walkableClimb = Mathf.Min(self.walkableClimb, self.walkableHeight); yield return(new Progress(0, "Finding Meshes")); var bounds = self.transform.Transform(new Bounds(self.forcedBoundsSize * 0.5f, self.forcedBoundsSize)); var meshes = self.CollectMeshes(bounds); var buckets = self.PutMeshesIntoTileBuckets(meshes); Queue <Int2> tileQueue = new Queue <Int2>(); // Put all tiles in the queue for (int z = 0; z < self.tileZCount; z++) { for (int x = 0; x < self.tileXCount; x++) { tileQueue.Enqueue(new Int2(x, z)); } } var workQueue = new ParallelWorkQueue <Int2>(tileQueue); // Create the voxelizers and set all settings (one for each thread) var voxelizers = new Voxelize[workQueue.threadCount]; for (int i = 0; i < voxelizers.Length; i++) { voxelizers[i] = new Voxelize(self.CellHeight, self.cellSize, self.walkableClimb, self.walkableHeight, self.maxSlope, self.maxEdgeLength); } workQueue.action = (tile, threadIndex) => { voxelizers[threadIndex].inputMeshes = buckets[tile.x + tile.y * self.tileXCount]; self.tiles[tile.x + tile.y * self.tileXCount] = self.BuildTileMesh(voxelizers[threadIndex], tile.x, tile.y, threadIndex); }; // Prioritize responsiveness while playing // but when not playing prioritize throughput // (the Unity progress bar is also pretty slow to update) int timeoutMillis = Application.isPlaying ? 1 : 200; // Scan all tiles in parallel foreach (var done in workQueue.Run(timeoutMillis)) { yield return(new Progress(Mathf.Lerp(0.1f, 0.9f, done / (float)self.tiles.Length), "Calculated Tiles: " + done + "/" + self.tiles.Length)); } yield return(new Progress(0.9f, "Assigning Graph Indices")); // Assign graph index to nodes uint graphIndex = (uint)AstarPath.active.data.GetGraphIndex(self); self.GetNodes(node => node.GraphIndex = graphIndex); // First connect all tiles with an EVEN coordinate sum // This would be the white squares on a chess board. // Then connect all tiles with an ODD coordinate sum (which would be all black squares on a chess board). // This will prevent the different threads that do all // this in parallel from conflicting with each other. // The directions are also done separately // first they are connected along the X direction and then along the Z direction. // Looping over 0 and then 1 for (int coordinateSum = 0; coordinateSum <= 1; coordinateSum++) { for (int direction = 0; direction <= 1; direction++) { for (int i = 0; i < self.tiles.Length; i++) { if ((self.tiles[i].x + self.tiles[i].z) % 2 == coordinateSum) { tileQueue.Enqueue(new Int2(self.tiles[i].x, self.tiles[i].z)); } } workQueue = new ParallelWorkQueue <Int2>(tileQueue); workQueue.action = (tile, threadIndex) => { // Connect with tile at (x+1,z) and (x,z+1) if (direction == 0 && tile.x < self.tileXCount - 1) { self.ConnectTiles(self.tiles[tile.x + tile.y * self.tileXCount], self.tiles[tile.x + 1 + tile.y * self.tileXCount]); } if (direction == 1 && tile.y < self.tileZCount - 1) { self.ConnectTiles(self.tiles[tile.x + tile.y * self.tileXCount], self.tiles[tile.x + (tile.y + 1) * self.tileXCount]); } }; var numTilesInQueue = tileQueue.Count; // Connect all tiles in parallel foreach (var done in workQueue.Run(timeoutMillis)) { yield return(new Progress(0.95f, "Connected Tiles " + (numTilesInQueue - done) + "/" + numTilesInQueue + " (Phase " + (direction + 1 + 2 * coordinateSum) + " of 4)")); } } } for (int i = 0; i < meshes.Count; i++) { meshes[i].Pool(); } ListPool <RasterizationMesh> .Release(ref meshes); // This may be used by the TileHandlerHelper script to update the tiles // while taking NavmeshCuts into account after the graph has been completely recalculated. if (self.OnRecalculatedTiles != null) { self.OnRecalculatedTiles(self.tiles.Clone() as NavmeshTile[]); } }