Esempio n. 1
0
        void BuildTiles(Queue <Int2> tileQueue, List <RasterizationMesh>[] meshBuckets, ManualResetEvent doneEvent, int threadIndex)
        {
            try {
                // Create the voxelizer and set all settings
                var vox = new Voxelize(CellHeight, cellSize, walkableClimb, walkableHeight, maxSlope, maxEdgeLength);

                while (true)
                {
                    Int2 tile;
                    lock (tileQueue) {
                        if (tileQueue.Count == 0)
                        {
                            return;
                        }

                        tile = tileQueue.Dequeue();
                    }

                    vox.inputMeshes = meshBuckets[tile.x + tile.y * tileXCount];
                    tiles[tile.x + tile.y * tileXCount] = BuildTileMesh(vox, tile.x, tile.y, threadIndex);
                }
            } catch (System.Exception e) {
                Debug.LogException(e);
            } finally {
                if (doneEvent != null)
                {
                    doneEvent.Set();
                }
            }
        }
Esempio n. 2
0
        void IUpdatableGraph.UpdateAreaInit(GraphUpdateObject o)
        {
            if (!o.updatePhysics)
            {
                return;
            }

            AstarProfiler.Reset();
            AstarProfiler.StartProfile("UpdateAreaInit");
            AstarProfiler.StartProfile("CollectMeshes");

            RelevantGraphSurface.UpdateAllPositions();

            // Calculate world bounds of all affected tiles
            IntRect touchingTiles = GetTouchingTiles(o.bounds);
            Bounds  tileBounds    = GetTileBounds(touchingTiles);

            // Expand TileBorderSizeInWorldUnits voxels in all directions
            tileBounds.Expand(new Vector3(1, 0, 1) * TileBorderSizeInWorldUnits * 2);

            var meshes = CollectMeshes(tileBounds);

            if (globalVox == null)
            {
                // Create the voxelizer and set all settings
                globalVox = new Voxelize(CellHeight, cellSize, walkableClimb, walkableHeight, maxSlope, maxEdgeLength);
            }

            globalVox.inputMeshes = meshes;

            AstarProfiler.EndProfile("CollectMeshes");
            AstarProfiler.EndProfile("UpdateAreaInit");
        }
Esempio n. 3
0
        void IUpdatableGraph.UpdateArea(GraphUpdateObject guo)
        {
            // Figure out which tiles are affected
            // Expand TileBorderSizeInWorldUnits voxels in all directions to make sure
            // all tiles that could be affected by the update are recalculated.
            var affectedTiles = GetTouchingTiles(guo.bounds, TileBorderSizeInWorldUnits);

            if (!guo.updatePhysics)
            {
                for (int z = affectedTiles.ymin; z <= affectedTiles.ymax; z++)
                {
                    for (int x = affectedTiles.xmin; x <= affectedTiles.xmax; x++)
                    {
                        NavmeshTile tile = tiles[z * tileXCount + x];
                        NavMeshGraph.UpdateArea(guo, tile);
                    }
                }
                return;
            }

            Voxelize vox = globalVox;

            if (vox == null)
            {
                throw new System.InvalidOperationException("No Voxelizer object. UpdateAreaInit should have been called before this function.");
            }

            AstarProfiler.StartProfile("Build Tiles");

            // Build the new tiles
            for (int x = affectedTiles.xmin; x <= affectedTiles.xmax; x++)
            {
                for (int z = affectedTiles.ymin; z <= affectedTiles.ymax; z++)
                {
                    stagingTiles.Add(BuildTileMesh(vox, x, z));
                }
            }

            uint graphIndex = (uint)AstarPath.active.data.GetGraphIndex(this);

            // Set the correct graph index
            for (int i = 0; i < stagingTiles.Count; i++)
            {
                NavmeshTile tile  = stagingTiles[i];
                GraphNode[] nodes = tile.nodes;

                for (int j = 0; j < nodes.Length; j++)
                {
                    nodes[j].GraphIndex = graphIndex;
                }
            }

            for (int i = 0; i < vox.inputMeshes.Count; i++)
            {
                vox.inputMeshes[i].Pool();
            }
            ListPool <RasterizationMesh> .Release(ref vox.inputMeshes);

            AstarProfiler.EndProfile("Build Tiles");
        }
Esempio n. 4
0
 private NavmeshTile CreateTile(Voxelize vox, VoxelMesh mesh, int x, int z, int threadIndex)
 {
     if (mesh.tris == null)
     {
         throw new ArgumentNullException("mesh.tris");
     }
     if (mesh.verts == null)
     {
         throw new ArgumentNullException("mesh.verts");
     }
     if (mesh.tris.Length % 3 != 0)
     {
         throw new ArgumentException("Indices array's length must be a multiple of 3 (mesh.tris)");
     }
     if (mesh.verts.Length >= 4095)
     {
         if (this.tileXCount * this.tileZCount == 1)
         {
             throw new ArgumentException("Too many vertices per tile (more than " + 4095 + ").\n<b>Try enabling tiling in the recast graph settings.</b>\n");
         }
         throw new ArgumentException("Too many vertices per tile (more than " + 4095 + ").\n<b>Try reducing tile size or enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector</b>");
     }
     else
     {
         NavmeshTile navmeshTile = new NavmeshTile
         {
             x      = x,
             z      = z,
             w      = 1,
             d      = 1,
             tris   = mesh.tris,
             bbTree = new BBTree()
         };
         navmeshTile.vertsInGraphSpace = Utility.RemoveDuplicateVertices(mesh.verts, navmeshTile.tris);
         navmeshTile.verts             = (Int3[])navmeshTile.vertsInGraphSpace.Clone();
         this.transform.Transform(navmeshTile.verts);
         uint num = (uint)(this.active.data.graphs.Length + threadIndex);
         if (num > 255u)
         {
             throw new Exception("Graph limit reached. Multithreaded recast calculations cannot be done because a few scratch graph indices are required.");
         }
         int num2 = x + z * this.tileXCount;
         num2 <<= 12;
         TriangleMeshNode.SetNavmeshHolder((int)num, navmeshTile);
         object active = this.active;
         lock (active)
         {
             navmeshTile.nodes = base.CreateNodes(navmeshTile.tris, num2, num);
         }
         navmeshTile.bbTree.RebuildFrom(navmeshTile.nodes);
         NavmeshBase.CreateNodeConnections(navmeshTile.nodes);
         TriangleMeshNode.SetNavmeshHolder((int)num, null);
         return(navmeshTile);
     }
 }
Esempio n. 5
0
        void IUpdatableGraph.UpdateArea(GraphUpdateObject guo)
        {
            IntRect touchingTiles = base.GetTouchingTiles(guo.bounds);

            if (!guo.updatePhysics)
            {
                for (int i = touchingTiles.ymin; i <= touchingTiles.ymax; i++)
                {
                    for (int j = touchingTiles.xmin; j <= touchingTiles.xmax; j++)
                    {
                        NavmeshTile graph = this.tiles[i * this.tileXCount + j];
                        NavMeshGraph.UpdateArea(guo, graph);
                    }
                }
                return;
            }
            Voxelize voxelize = this.globalVox;

            if (voxelize == null)
            {
                throw new InvalidOperationException("No Voxelizer object. UpdateAreaInit should have been called before this function.");
            }
            for (int k = touchingTiles.xmin; k <= touchingTiles.xmax; k++)
            {
                for (int l = touchingTiles.ymin; l <= touchingTiles.ymax; l++)
                {
                    this.stagingTiles.Add(this.BuildTileMesh(voxelize, k, l, 0));
                }
            }
            uint graphIndex = (uint)AstarPath.active.data.GetGraphIndex(this);

            for (int m = 0; m < this.stagingTiles.Count; m++)
            {
                NavmeshTile navmeshTile = this.stagingTiles[m];
                GraphNode[] nodes       = navmeshTile.nodes;
                for (int n = 0; n < nodes.Length; n++)
                {
                    nodes[n].GraphIndex = graphIndex;
                }
            }
            for (int num = 0; num < voxelize.inputMeshes.Count; num++)
            {
                voxelize.inputMeshes[num].Pool();
            }
            ListPool <RasterizationMesh> .Release(voxelize.inputMeshes);

            voxelize.inputMeshes = null;
        }
Esempio n. 6
0
        protected NavmeshTile BuildTileMesh(Voxelize vox, int x, int z, int threadIndex = 0)
        {
            vox.borderSize   = this.TileBorderSizeInVoxels;
            vox.forcedBounds = this.CalculateTileBoundsWithBorder(x, z);
            vox.width        = this.tileSizeX + vox.borderSize * 2;
            vox.depth        = this.tileSizeZ + vox.borderSize * 2;
            if (!this.useTiles && this.relevantGraphSurfaceMode == RecastGraph.RelevantGraphSurfaceMode.OnlyForCompletelyInsideTile)
            {
                vox.relevantGraphSurfaceMode = RecastGraph.RelevantGraphSurfaceMode.RequireForAll;
            }
            else
            {
                vox.relevantGraphSurfaceMode = this.relevantGraphSurfaceMode;
            }
            vox.minRegionSize = Mathf.RoundToInt(this.minRegionSize / (this.cellSize * this.cellSize));
            vox.Init();
            vox.VoxelizeInput(this.transform, this.CalculateTileBoundsWithBorder(x, z));
            vox.FilterLedges(vox.voxelWalkableHeight, vox.voxelWalkableClimb, vox.cellSize, vox.cellHeight);
            vox.FilterLowHeightSpans(vox.voxelWalkableHeight, vox.cellSize, vox.cellHeight);
            vox.BuildCompactField();
            vox.BuildVoxelConnections();
            vox.ErodeWalkableArea(this.CharacterRadiusInVoxels);
            vox.BuildDistanceField();
            vox.BuildRegions();
            VoxelContourSet cset = new VoxelContourSet();

            vox.BuildContours(this.contourMaxError, 1, cset, 5);
            VoxelMesh mesh;

            vox.BuildPolyMesh(cset, 3, out mesh);
            for (int i = 0; i < mesh.verts.Length; i++)
            {
                mesh.verts[i] *= 1000;
            }
            vox.transformVoxel2Graph.Transform(mesh.verts);
            return(this.CreateTile(vox, mesh, x, z, threadIndex));
        }
Esempio n. 7
0
        /** Create a tile at tile index \a x, \a z from the mesh.
         * \version Since version 3.7.6 the implementation is thread safe
         */
        NavmeshTile CreateTile(Voxelize vox, VoxelMesh mesh, int x, int z, int threadIndex)
        {
            if (mesh.tris == null)
            {
                throw new System.ArgumentNullException("mesh.tris");
            }
            if (mesh.verts == null)
            {
                throw new System.ArgumentNullException("mesh.verts");
            }
            if (mesh.tris.Length % 3 != 0)
            {
                throw new System.ArgumentException("Indices array's length must be a multiple of 3 (mesh.tris)");
            }
            if (mesh.verts.Length >= VertexIndexMask)
            {
                if (tileXCount * tileZCount == 1)
                {
                    throw new System.ArgumentException("Too many vertices per tile (more than " + VertexIndexMask + ")." +
                                                       "\n<b>Try enabling tiling in the recast graph settings.</b>\n");
                }
                else
                {
                    throw new System.ArgumentException("Too many vertices per tile (more than " + VertexIndexMask + ")." +
                                                       "\n<b>Try reducing tile size or enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector</b>");
                }
            }

            // Create a new navmesh tile and assign its settings
            var tile = new NavmeshTile {
                x      = x,
                z      = z,
                w      = 1,
                d      = 1,
                tris   = mesh.tris,
                bbTree = new BBTree(),
                graph  = this,
            };

            tile.vertsInGraphSpace = Utility.RemoveDuplicateVertices(mesh.verts, tile.tris);
            tile.verts             = (Int3[])tile.vertsInGraphSpace.Clone();
            transform.Transform(tile.verts);

            // Here we are faking a new graph
            // The tile is not added to any graphs yet, but to get the position queries from the nodes
            // to work correctly (not throw exceptions because the tile is not calculated) we fake a new graph
            // and direct the position queries directly to the tile
            // The thread index is added to make sure that if multiple threads are calculating tiles at the same time
            // they will not use the same temporary graph index
            uint temporaryGraphIndex = (uint)(active.data.graphs.Length + threadIndex);

            if (temporaryGraphIndex > GraphNode.MaxGraphIndex)
            {
                // Multithreaded tile calculations use fake graph indices, see above.
                throw new System.Exception("Graph limit reached. Multithreaded recast calculations cannot be done because a few scratch graph indices are required.");
            }

            TriangleMeshNode.SetNavmeshHolder((int)temporaryGraphIndex, tile);
            // We need to lock here because creating nodes is not thread safe
            // and we may be doing this from multiple threads at the same time
            tile.nodes = new TriangleMeshNode[tile.tris.Length / 3];
            lock (active) {
                CreateNodes(tile.nodes, tile.tris, x + z * tileXCount, temporaryGraphIndex);
            }

            tile.bbTree.RebuildFrom(tile.nodes);
            CreateNodeConnections(tile.nodes);
            // Remove the fake graph
            TriangleMeshNode.SetNavmeshHolder((int)temporaryGraphIndex, null);

            return(tile);
        }
Esempio n. 8
0
        protected NavmeshTile BuildTileMesh(Voxelize vox, int x, int z, int threadIndex = 0)
        {
            AstarProfiler.StartProfile("Build Tile");
            AstarProfiler.StartProfile("Init");

            vox.borderSize   = TileBorderSizeInVoxels;
            vox.forcedBounds = CalculateTileBoundsWithBorder(x, z);
            vox.width        = tileSizeX + vox.borderSize * 2;
            vox.depth        = tileSizeZ + vox.borderSize * 2;

            if (!useTiles && relevantGraphSurfaceMode == RelevantGraphSurfaceMode.OnlyForCompletelyInsideTile)
            {
                // This best reflects what the user would actually want
                vox.relevantGraphSurfaceMode = RelevantGraphSurfaceMode.RequireForAll;
            }
            else
            {
                vox.relevantGraphSurfaceMode = relevantGraphSurfaceMode;
            }

            vox.minRegionSize = Mathf.RoundToInt(minRegionSize / (cellSize * cellSize));

            AstarProfiler.EndProfile("Init");


            // Init voxelizer
            vox.Init();
            vox.VoxelizeInput(transform, CalculateTileBoundsWithBorder(x, z));

            AstarProfiler.StartProfile("Filter Ledges");


            vox.FilterLedges(vox.voxelWalkableHeight, vox.voxelWalkableClimb, vox.cellSize, vox.cellHeight);

            AstarProfiler.EndProfile("Filter Ledges");

            AstarProfiler.StartProfile("Filter Low Height Spans");
            vox.FilterLowHeightSpans(vox.voxelWalkableHeight, vox.cellSize, vox.cellHeight);
            AstarProfiler.EndProfile("Filter Low Height Spans");

            vox.BuildCompactField();
            vox.BuildVoxelConnections();
            vox.ErodeWalkableArea(CharacterRadiusInVoxels);
            vox.BuildDistanceField();
            vox.BuildRegions();

            var cset = new VoxelContourSet();

            vox.BuildContours(contourMaxError, 1, cset, Voxelize.RC_CONTOUR_TESS_WALL_EDGES | Voxelize.RC_CONTOUR_TESS_TILE_EDGES);

            VoxelMesh mesh;

            vox.BuildPolyMesh(cset, 3, out mesh);

            AstarProfiler.StartProfile("Build Nodes");

            // Position the vertices correctly in graph space (all tiles are laid out on the xz plane with the (0,0) tile at the origin)
            for (int i = 0; i < mesh.verts.Length; i++)
            {
                mesh.verts[i] *= Int3.Precision;
            }
            vox.transformVoxel2Graph.Transform(mesh.verts);

            NavmeshTile tile = CreateTile(vox, mesh, x, z, threadIndex);

            AstarProfiler.EndProfile("Build Nodes");

            AstarProfiler.EndProfile("Build Tile");
            return(tile);
        }
Esempio n. 9
0
        protected IEnumerable <Progress> ScanAllTiles()
        {
            transform = CalculateTransform();
            InitializeTileInfo();

            // If this is true, just fill the graph with empty tiles
            if (scanEmptyGraph)
            {
                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
            walkableClimb = Mathf.Min(walkableClimb, walkableHeight);

            yield return(new Progress(0, "Finding Meshes"));

            var bounds  = transform.Transform(new Bounds(forcedBoundsSize * 0.5f, forcedBoundsSize));
            var meshes  = CollectMeshes(bounds);
            var buckets = PutMeshesIntoTileBuckets(meshes);

            Queue <Int2> tileQueue = new Queue <Int2>();

            // Put all tiles in the queue
            for (int z = 0; z < tileZCount; z++)
            {
                for (int x = 0; x < 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(CellHeight, cellSize, walkableClimb, walkableHeight, maxSlope, maxEdgeLength);
            }
            workQueue.action = (tile, threadIndex) => {
                voxelizers[threadIndex].inputMeshes = buckets[tile.x + tile.y * tileXCount];
                tiles[tile.x + tile.y * tileXCount] = 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)tiles.Length), "Calculated Tiles: " + done + "/" + tiles.Length));
            }

            yield return(new Progress(0.9f, "Assigning Graph Indices"));

            // Assign graph index to nodes
            uint graphIndex = (uint)AstarPath.active.data.GetGraphIndex(this);

            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 < tiles.Length; i++)
                    {
                        if ((tiles[i].x + tiles[i].z) % 2 == coordinateSum)
                        {
                            tileQueue.Enqueue(new Int2(tiles[i].x, 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 < tileXCount - 1)
                        {
                            ConnectTiles(tiles[tile.x + tile.y * tileXCount], tiles[tile.x + 1 + tile.y * tileXCount]);
                        }
                        if (direction == 1 && tile.y < tileZCount - 1)
                        {
                            ConnectTiles(tiles[tile.x + tile.y * tileXCount], tiles[tile.x + (tile.y + 1) * 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 (OnRecalculatedTiles != null)
            {
                OnRecalculatedTiles(tiles.Clone() as NavmeshTile[]);
            }
        }
Esempio n. 10
0
        protected IEnumerable <Progress> ScanAllTiles()
        {
            this.transform = this.CalculateTransform();
            this.InitializeTileInfo();
            if (this.scanEmptyGraph)
            {
                base.FillWithEmptyTiles();
                yield break;
            }
            this.walkableClimb = Mathf.Min(this.walkableClimb, this.walkableHeight);
            yield return(new Progress(0f, "Finding Meshes"));

            Bounds bounds = this.transform.Transform(new Bounds(this.forcedBoundsSize * 0.5f, this.forcedBoundsSize));
            List <RasterizationMesh> meshes = this.CollectMeshes(bounds);

            List <RasterizationMesh>[] buckets = this.PutMeshesIntoTileBuckets(meshes);
            Queue <Int2> tileQueue             = new Queue <Int2>();

            for (int i = 0; i < this.tileZCount; i++)
            {
                for (int j = 0; j < this.tileXCount; j++)
                {
                    tileQueue.Enqueue(new Int2(j, i));
                }
            }
            ParallelWorkQueue <Int2> workQueue = new ParallelWorkQueue <Int2>(tileQueue);

            Voxelize[] voxelizers = new Voxelize[workQueue.threadCount];
            for (int k = 0; k < voxelizers.Length; k++)
            {
                voxelizers[k] = new Voxelize(this.CellHeight, this.cellSize, this.walkableClimb, this.walkableHeight, this.maxSlope, this.maxEdgeLength);
            }
            workQueue.action = delegate(Int2 tile, int threadIndex)
            {
                voxelizers[threadIndex].inputMeshes = buckets[tile.x + tile.y * this.$this.tileXCount];
                this.$this.tiles[tile.x + tile.y * this.$this.tileXCount] = this.$this.BuildTileMesh(voxelizers[threadIndex], tile.x, tile.y, threadIndex);
            };
            int timeoutMillis = (!Application.isPlaying) ? 200 : 1;

            foreach (int done in workQueue.Run(timeoutMillis))
            {
                yield return(new Progress(Mathf.Lerp(0.1f, 0.9f, (float)done / (float)this.tiles.Length), string.Concat(new object[]
                {
                    "Calculated Tiles: ",
                    done,
                    "/",
                    this.tiles.Length
                })));
            }
            yield return(new Progress(0.9f, "Assigning Graph Indices"));

            uint graphIndex = (uint)AstarPath.active.data.GetGraphIndex(this);

            this.GetNodes(delegate(GraphNode node)
            {
                node.GraphIndex = graphIndex;
            });
            for (int coordinateSum = 0; coordinateSum <= 1; coordinateSum++)
            {
                int direction;
                for (direction = 0; direction <= 1; direction++)
                {
                    for (int l = 0; l < this.tiles.Length; l++)
                    {
                        if ((this.tiles[l].x + this.tiles[l].z) % 2 == coordinateSum)
                        {
                            tileQueue.Enqueue(new Int2(this.tiles[l].x, this.tiles[l].z));
                        }
                    }
                    workQueue        = new ParallelWorkQueue <Int2>(tileQueue);
                    workQueue.action = delegate(Int2 tile, int threadIndex)
                    {
                        if (direction == 0 && tile.x < this.$this.tileXCount - 1)
                        {
                            this.$this.ConnectTiles(this.$this.tiles[tile.x + tile.y * this.$this.tileXCount], this.$this.tiles[tile.x + 1 + tile.y * this.$this.tileXCount]);
                        }
                        if (direction == 1 && tile.y < this.$this.tileZCount - 1)
                        {
                            this.$this.ConnectTiles(this.$this.tiles[tile.x + tile.y * this.$this.tileXCount], this.$this.tiles[tile.x + (tile.y + 1) * this.$this.tileXCount]);
                        }
                    };
                    int numTilesInQueue = tileQueue.Count;
                    foreach (int done2 in workQueue.Run(timeoutMillis))
                    {
                        yield return(new Progress(0.95f, string.Concat(new object[]
                        {
                            "Connected Tiles ",
                            numTilesInQueue - done2,
                            "/",
                            numTilesInQueue,
                            " (Phase ",
                            direction + 1 + 2 * coordinateSum,
                            " of 4)"
                        })));
                    }
                }
            }
            for (int m = 0; m < meshes.Count; m++)
            {
                meshes[m].Pool();
            }
            ListPool <RasterizationMesh> .Release(meshes);

            if (this.OnRecalculatedTiles != null)
            {
                this.OnRecalculatedTiles(this.tiles.Clone() as NavmeshTile[]);
            }
            yield break;
        }
Esempio n. 11
0
        protected void ScanAllTiles(OnScanStatus statusCallback)
        {
#if ASTARDEBUG
            System.Console.WriteLine("Recast Graph -- Collecting Meshes");
#endif

#if BNICKSON_UPDATED
            editorTileSize = (int)(EditorVars.GridSize / cellSize);
#endif

            //----

            //Voxel grid size
            int gw = (int)(forcedBounds.size.x / cellSize + 0.5f);
            int gd = (int)(forcedBounds.size.z / cellSize + 0.5f);

            if (!useTiles)
            {
                tileSizeX = gw;
                tileSizeZ = gd;
            }
            else
            {
                tileSizeX = editorTileSize;
                tileSizeZ = editorTileSize;
            }

            //Number of tiles
            int tw = (gw + tileSizeX - 1) / tileSizeX;
            int td = (gd + tileSizeZ - 1) / tileSizeZ;

            tileXCount = tw;
            tileZCount = td;

            if (tileXCount * tileZCount > TileIndexMask + 1)
            {
                throw new System.Exception("Too many tiles (" + (tileXCount * tileZCount) + ") maximum is " + (TileIndexMask + 1) +
                                           "\nTry disabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* inspector.");
            }

            tiles = new NavmeshTile[tileXCount * tileZCount];

#if ASTARDEBUG
            System.Console.WriteLine("Recast Graph -- Creating Voxel Base");
#endif

            // If this is true, just fill the graph with empty tiles
            if (scanEmptyGraph)
            {
                for (int z = 0; z < td; z++)
                {
                    for (int x = 0; x < tw; x++)
                    {
                        tiles[z * tileXCount + x] = NewEmptyTile(x, z);
                    }
                }
                return;
            }

            AstarProfiler.StartProfile("Finding Meshes");
            List <ExtraMesh> extraMeshes;

#if !NETFX_CORE || UNITY_EDITOR
            System.Console.WriteLine("Collecting Meshes");
#endif
            CollectMeshes(out extraMeshes, forcedBounds);

            AstarProfiler.EndProfile("Finding Meshes");

            // 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
            walkableClimb = Mathf.Min(walkableClimb, walkableHeight);

            //Create the voxelizer and set all settings
            var vox = new Voxelize(cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope);
            vox.inputExtraMeshes = extraMeshes;

            vox.maxEdgeLength = maxEdgeLength;

            int lastInfoCallback = -1;
            var watch            = System.Diagnostics.Stopwatch.StartNew();

            //Generate all tiles
            for (int z = 0; z < td; z++)
            {
                for (int x = 0; x < tw; x++)
                {
                    int tileNum = z * tileXCount + x;
#if !NETFX_CORE || UNITY_EDITOR
                    System.Console.WriteLine("Generating Tile #" + (tileNum) + " of " + td * tw);
#endif

                    //Call statusCallback only 10 times since it is very slow in the editor
                    if (statusCallback != null && (tileNum * 10 / tiles.Length > lastInfoCallback || watch.ElapsedMilliseconds > 2000))
                    {
                        lastInfoCallback = tileNum * 10 / tiles.Length;
                        watch.Reset();
                        watch.Start();

                        statusCallback(new Progress(Mathf.Lerp(0.1f, 0.9f, tileNum / (float)tiles.Length), "Building Tile " + tileNum + "/" + tiles.Length));
                    }

                    BuildTileMesh(vox, x, z);
                }
            }

#if !NETFX_CORE
            System.Console.WriteLine("Assigning Graph Indices");
#endif

            if (statusCallback != null)
            {
                statusCallback(new Progress(0.9f, "Connecting tiles"));
            }

            //Assign graph index to nodes
            uint graphIndex = (uint)AstarPath.active.astarData.GetGraphIndex(this);

            GraphNodeDelegateCancelable del = delegate(GraphNode n) {
                n.GraphIndex = graphIndex;
                return(true);
            };
            GetNodes(del);

#if BNICKSON_UPDATED
#if DEBUG
            if (useCenterTileOnly && (3 != tileXCount || 3 != tileZCount))
            {
                EB.Debug.LogError("RecastGenerator.ScanAllTiles() : Incorrect amount of tiles generated if ceneter tile is all that is required");
            }
#endif

            int centerXTile = (tileXCount / 2);
            int centerZTile = (tileZCount / 2);
#endif

            for (int z = 0; z < td; z++)
            {
                for (int x = 0; x < tw; x++)
                {
#if BNICKSON_UPDATED
                    // if we're only using the center tile, and this is not the center tile
                    if (useCenterTileOnly && !(centerZTile == z && centerXTile == x))
                    {
                        continue;
                    }
#endif

#if !NETFX_CORE
                    System.Console.WriteLine("Connecing Tile #" + (z * tileXCount + x) + " of " + td * tw);
#endif
                    if (x < tw - 1)
                    {
                        ConnectTiles(tiles[x + z * tileXCount], tiles[x + 1 + z * tileXCount]);
                    }
                    if (z < td - 1)
                    {
                        ConnectTiles(tiles[x + z * tileXCount], tiles[x + (z + 1) * tileXCount]);
                    }
                }
            }

            AstarProfiler.PrintResults();
        }
Esempio n. 12
0
		public override void Scan () {
			AstarProfiler.Reset ();
			//AstarProfiler.StartProfile ("Base Scan");
			
			//base.Scan ();
			
			//AstarProfiler.EndProfile ("Base Scan");
			if (useCRecast) {
				ScanCRecast ();
				
			} else {
			
#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Collecting Meshes");
#endif	
				AstarProfiler.StartProfile ("Collecting Meshes");
				
				AstarProfiler.StartProfile ("Collecting Meshes");
				MeshFilter[] filters;
				ExtraMesh[] extraMeshes;
				
				if (!CollectMeshes (out filters, out extraMeshes)) {
					nodes = new Node[0];
					return;
				}
				
				AstarProfiler.EndProfile ("Collecting Meshes");
				
#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Creating Voxel Base");
#endif
				
				Voxelize vox = new Voxelize (cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope);
				
				vox.maxEdgeLength = maxEdgeLength;
				vox.forcedBounds = forcedBounds;
				vox.includeOutOfBounds = includeOutOfBounds;
				
#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Voxelizing");
#endif
				AstarProfiler.EndProfile ("Collecting Meshes");
				
				//g.GetComponent<Voxelize>();
				vox.VoxelizeMesh (filters, extraMeshes);
				
				/*bool[,] open = new bool[width,depth];
				int[,] visited = new int[width+1,depth+1];
				
				for (int z=0;z<depth;z++) {
					for (int x = 0;x < width;x++) {
						open[x,z] = graphNodes[z*width+x].walkable;
					}
				}*/
				
				/*for (int i=0;i<depth*width;i++) {
					open[i] = graphNodes[i].walkable;
				}
				
				
				int wd = width*depth;
				
				List<int> boundary = new List<int>();
				
				int p = 0;
				
				for (int i=0;i<wd;i++) {
					if (!open[i]) {
						boundary.Add (i);
						
						p = i;
						
						int backtrack = i-1;
						
						
					}*/

#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Eroding");
#endif
				
				vox.ErodeWalkableArea (Mathf.CeilToInt (2*characterRadius/cellSize));
				
#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Building Distance Field");
#endif
				
				vox.BuildDistanceField ();

#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Building Regions");
#endif
				
				vox.BuildRegions ();
				
#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Building Contours");
#endif
				
				VoxelContourSet cset = new VoxelContourSet ();
				
				vox.BuildContours (contourMaxError,1,cset,Voxelize.RC_CONTOUR_TESS_WALL_EDGES);
				
#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Building Poly Mesh");
#endif
				
				VoxelMesh mesh;
				
				vox.BuildPolyMesh (cset,3,out mesh);
				
#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Building Nodes");
#endif
				
				Vector3[] vertices = new Vector3[mesh.verts.Length];
				
				AstarProfiler.StartProfile ("Build Nodes");
				
				for (int i=0;i<vertices.Length;i++) {
					vertices[i] = (Vector3)mesh.verts[i];
				}
				
				matrix = Matrix4x4.TRS (vox.voxelOffset,Quaternion.identity,Int3.Precision*Voxelize.CellScale);
				//Int3.Precision*Voxelize.CellScale+(Int3)vox.voxelOffset
				
				//GenerateNodes (this,vectorVertices,triangles, out originalVertices, out _vertices);
				
#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Generating Nodes");
#endif
				
				NavMeshGraph.GenerateNodes (this,vertices,mesh.tris, out _vectorVertices, out _vertices);
				
				AstarProfiler.EndProfile ("Build Nodes");
				
				AstarProfiler.PrintResults ();
				
#if ASTARDEBUG
				Console.WriteLine ("Recast Graph -- Done");
#endif
				
			}
		}
Esempio n. 13
0
        public void ScanCRecast()
        {
            //#if (!UNITY_EDITOR && !UNITY_STANDALONE_OSX && !UNITY_STANDALONE_WIN) || UNITY_WEBPLAYER || UNITY_IPHONE || UNITY_ANDROID || UNITY_DASHBOARD_WIDGET || UNITY_XBOX360 || UNITY_PS3
        #if (UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN)
            System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
            myProcess.StartInfo.FileName = GetRecastPath();             //"/Users/arong/Recast/build/Debug/Recast";
            //System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo ();
            //startInfo.UseShellExecute = true;
            myProcess.StartInfo.UseShellExecute        = false;
            myProcess.StartInfo.RedirectStandardInput  = true;
            myProcess.StartInfo.RedirectStandardOutput = true;
            myProcess.StartInfo.Arguments = "";

            MeshFilter[] filters;
            ExtraMesh[]  extraMeshes;
            //Get all meshes which should be used
            CollectMeshes(out filters, out extraMeshes);

            Vector3[] inputVerts;
            int[]     inputTris;
            //Get polygon soup from meshes
            Voxelize.CollectMeshes(filters, extraMeshes, forcedBounds, out inputVerts, out inputTris);

            //Bild .obj file
            System.Text.StringBuilder arguments = new System.Text.StringBuilder();
            arguments.Append("o recastMesh.obj\n");
            for (int i = 0; i < inputVerts.Length; i++)
            {
                arguments.Append("v " + inputVerts[i].x.ToString("0.000") + " ").Append(inputVerts[i].y.ToString("0.000") + " ").Append(inputVerts[i].z.ToString("0.000"));
                arguments.Append("\n");
            }

            //Build .obj file tris
            for (int i = 0; i < inputTris.Length - 2; i += 3)
            {
                arguments.Append("f " + (inputTris[i] + 1) + "//0 ").Append((inputTris[i + 1] + 1) + "//0 ").Append((inputTris[i + 2] + 1) + "//0");
                //Debug.DrawLine (inputVerts[inputTris[i]],inputVerts[inputTris[i+1]],Color.red);
                //Debug.DrawLine (inputVerts[inputTris[i+1]],inputVerts[inputTris[i+2]],Color.red);
                //Debug.DrawLine (inputVerts[inputTris[i+2]],inputVerts[inputTris[i]],Color.red);

                arguments.Append("\n");
            }

            string tmpPath = System.IO.Path.GetTempPath();
            tmpPath += "recastMesh.obj";

            try {
                using (System.IO.StreamWriter outfile = new System.IO.StreamWriter(tmpPath)) {
                    outfile.Write(arguments.ToString());
                }

                myProcess.StartInfo.Arguments = tmpPath
                                                + "\n" + cellSize + "\n" +
                                                cellHeight + "\n" +
                                                walkableHeight + "\n" +
                                                walkableClimb + "\n" +
                                                maxSlope + "\n" +
                                                maxEdgeLength + "\n" +
                                                contourMaxError + "\n" +
                                                regionMinSize + "\n" +
                                                characterRadius;


                /*		public int erosionRadius = 2; /< Voxels to erode away from the edges of the mesh /
                 * public float contourMaxError = 2F; /< Max distance from simplified edge to real edge /
                 *
                 * public float cellSize = 0.5F; /< Voxel sample size (x,z) /
                 * public float cellHeight = 0.4F; /< Voxel sample size (y) /
                 * public float walkableHeight = 2F; /< Character height/
                 * public float walkableClimb = 0.5F; /< Height the character can climb /
                 * public float maxSlope = 30; /< Max slope in degrees the character can traverse /
                 * public float maxEdgeLength = 20; /< Longer edges will be subdivided. Reducing this value can im
                 * public bool useCRecast = true;
                 * public bool includeOutOfBounds = false;*/

                myProcess.Start();
                System.IO.StreamReader sOut = myProcess.StandardOutput;

                //string result = sOut.ReadToEnd ();
                //Debug.Log (result);
                //return;

                bool      failed            = false;
                bool      startedVerts      = false;
                int       readVerts         = 0;
                bool      startedTris       = false;
                int       vCount            = -1;
                int       readTris          = 0;
                int       trisCount         = 0;
                Vector3[] verts             = null;
                int[]     tris              = null;
                int       internalVertCount = 0;

                Vector3 bmin = Vector3.zero;

                float cs = 1F;
                float ch = 1F;

                while (sOut.Peek() >= 0)
                {
                    string line = sOut.ReadLine();
                    int    resultInt;

                    if (line == "")
                    {
                        continue;
                    }

                    if (!int.TryParse(line, out resultInt))
                    {
                        //Debug.Log ("Syntax Error at '"+line+"'");
                        failed = true;
                        break;
                    }

                    if (!startedVerts)
                    {
                        verts = new Vector3[resultInt];

                        if (resultInt == 0)
                        {
                            failed = true;
                            break;
                        }

                        bmin.x = float.Parse(sOut.ReadLine());
                        bmin.y = float.Parse(sOut.ReadLine());
                        bmin.z = float.Parse(sOut.ReadLine());
                        cs     = float.Parse(sOut.ReadLine());
                        ch     = float.Parse(sOut.ReadLine());

                        startedVerts = true;
                        //Debug.Log ("Starting Reading "+resultInt+" verts "+bmin.ToString ()+" - "+cs+" * "+ch);
                    }
                    else if (readVerts < verts.Length)
                    {
                        resultInt *= 1;
                        if (internalVertCount == 0)
                        {
                            verts[readVerts].x = resultInt * cs + bmin.x;
                        }
                        else if (internalVertCount == 1)
                        {
                            verts[readVerts].y = resultInt * ch + bmin.y;
                        }
                        else
                        {
                            verts[readVerts].z = resultInt * cs + bmin.z;
                        }

                        internalVertCount++;

                        if (internalVertCount == 3)
                        {
                            internalVertCount = 0;
                            readVerts++;
                        }
                    }
                    else if (!startedTris)
                    {
                        trisCount   = resultInt;
                        startedTris = true;
                    }
                    else if (vCount == -1)
                    {
                        vCount = resultInt;
                        tris   = new int[trisCount * vCount];
                        //Debug.Log ("Starting Reading "+trisCount+" - "+tris.Length+" tris at vertsCount "+readVerts);
                        //Debug.Log ("Max vertices per polygon: "+vCount);
                    }
                    else if (readTris < tris.Length)
                    {
                        tris[readTris] = resultInt;
                        readTris++;
                    }
                }

                if (!myProcess.HasExited)
                {
                    myProcess.Kill();
                }

                sOut.Close();
                myProcess.Close();

                if (failed)
                {
                    return;
                }

                matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one);

                NavMeshGraph.GenerateNodes(this, verts, tris, out _vectorVertices, out _vertices);
            } finally {
                //Debug.Log (tmpPath);
                System.IO.File.Delete(tmpPath);
            }
        #else
            Debug.LogError("The C++ version of recast can only be used in editor or standalone mode, I'm sure it cannot be used in the webplayer, but other platforms are not tested yet\n" +
                           "If you are in the Unity Editor, try switching Platform to Standalone just when scanning, scanned graphs can be cached to enable them to be used in a webplayer");
            _vectorVertices = new Vector3[0];
            _vertices       = new Int3[0];
            nodes           = new Node[0];
        #endif
        }
Esempio n. 14
0
        public override void Scan()
        {
            AstarProfiler.Reset();
            //AstarProfiler.StartProfile ("Base Scan");

            //base.Scan ();

            //AstarProfiler.EndProfile ("Base Scan");
            if (useCRecast)
            {
                ScanCRecast();
            }
            else
            {
                MeshFilter[] filters;
                ExtraMesh[]  extraMeshes;

                if (!CollectMeshes(out filters, out extraMeshes))
                {
                    nodes = new Node[0];
                    return;
                }

                Voxelize vox = new Voxelize(cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope);

                vox.maxEdgeLength      = maxEdgeLength;
                vox.forcedBounds       = forcedBounds;
                vox.includeOutOfBounds = includeOutOfBounds;


                //g.GetComponent<Voxelize>();
                vox.VoxelizeMesh(filters, extraMeshes);

                /*bool[,] open = new bool[width,depth];
                 * int[,] visited = new int[width+1,depth+1];
                 *
                 * for (int z=0;z<depth;z++) {
                 *      for (int x = 0;x < width;x++) {
                 *              open[x,z] = graphNodes[z*width+x].walkable;
                 *      }
                 * }*/

                /*for (int i=0;i<depth*width;i++) {
                 *      open[i] = graphNodes[i].walkable;
                 * }
                 *
                 *
                 * int wd = width*depth;
                 *
                 * List<int> boundary = new List<int>();
                 *
                 * int p = 0;
                 *
                 * for (int i=0;i<wd;i++) {
                 *      if (!open[i]) {
                 *              boundary.Add (i);
                 *
                 *              p = i;
                 *
                 *              int backtrack = i-1;
                 *
                 *
                 *      }*/

                vox.ErodeWalkableArea(Mathf.CeilToInt(2 * characterRadius / cellSize));


                vox.BuildDistanceField();

                vox.BuildRegions();

                VoxelContourSet cset = new VoxelContourSet();

                vox.BuildContours(contourMaxError, 1, cset, Voxelize.RC_CONTOUR_TESS_WALL_EDGES);

                VoxelMesh mesh;

                vox.BuildPolyMesh(cset, 3, out mesh);


                Vector3[] vertices = new Vector3[mesh.verts.Length];

                AstarProfiler.StartProfile("Build Nodes");

                for (int i = 0; i < vertices.Length; i++)
                {
                    vertices[i] = (Vector3)mesh.verts[i];
                }

                matrix = Matrix4x4.TRS(vox.voxelOffset, Quaternion.identity, Int3.Precision * Voxelize.CellScale);
                //Int3.Precision*Voxelize.CellScale+(Int3)vox.voxelOffset

                //GenerateNodes (this,vectorVertices,triangles, out originalVertices, out _vertices);

                NavMeshGraph.GenerateNodes(this, vertices, mesh.tris, out _vectorVertices, out _vertices);

                AstarProfiler.EndProfile("Build Nodes");

                AstarProfiler.PrintResults();
            }
        }