예제 #1
0
		public void UpdateAreaInit (GraphUpdateObject o) {
			
			if (!o.updatePhysics) {
				return;
			}
			
			if (!dynamic) {
				throw new System.Exception ("Recast graph must be marked as dynamic to enable graph updates");
			}
			
			AstarProfiler.Reset ();
			AstarProfiler.StartProfile ("UpdateAreaInit");
			AstarProfiler.StartProfile ("CollectMeshes");
			
			RelevantGraphSurface.UpdateAllPositions ();
			
			List<ExtraMesh> extraMeshes;
			
			Bounds b = o.bounds;
			b.center -= forcedBounds.min;
			
			//Calculate world bounds of all affected tiles
			IntRect r = new IntRect (Mathf.FloorToInt (b.min.x / (tileSizeX*cellSize)), Mathf.FloorToInt (b.min.z / (tileSizeZ*cellSize)), Mathf.FloorToInt (b.max.x / (tileSizeX*cellSize)), Mathf.FloorToInt (b.max.z / (tileSizeZ*cellSize)));
			//Clamp to bounds
			r = IntRect.Intersection (r, new IntRect (0,0,tileXCount-1,tileZCount-1));
			
			Bounds tileBounds = new Bounds();
			
			Vector3 forcedBoundsMin = forcedBounds.min;
			Vector3 forcedBoundsMax = forcedBounds.max;
			
			float tcsx = tileSizeX*cellSize;
			float tcsz = tileSizeZ*cellSize;
			
			tileBounds.SetMinMax(new Vector3 (r.xmin*tcsx, 0, r.ymin*tcsz) + forcedBoundsMin,
						new Vector3 ((r.xmax+1)*tcsx + forcedBoundsMin.x, forcedBoundsMax.y, (r.ymax+1)*tcsz + forcedBoundsMin.z)
				);
			
			int voxelCharacterRadius = Mathf.CeilToInt (characterRadius/cellSize);			
			int borderSize = voxelCharacterRadius + 3;
			
			//Expand borderSize voxels on each side
			tileBounds.Expand (new Vector3 (borderSize,0,borderSize)*cellSize*2);
			Debug.DrawLine (tileBounds.min, tileBounds.max);
			//Debug.Break ();
			
			if (!CollectMeshes (out extraMeshes, tileBounds)) {
				//return;
			}
			
			Voxelize vox = globalVox;
			
			if (vox == null) {
				
				//Create the voxelizer and set all settings
				vox = new Voxelize (cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope);
				
				vox.maxEdgeLength = maxEdgeLength;
				
				if (dynamic) globalVox = vox;
				
			}
			
			vox.inputExtraMeshes = extraMeshes;
			
			AstarProfiler.EndProfile ("CollectMeshes");
			AstarProfiler.EndProfile ("UpdateAreaInit");
		}
예제 #2
0
		protected void BuildTileMesh (Voxelize vox, int x, int z) {
			
			AstarProfiler.StartProfile ("Build Tile");
			
			AstarProfiler.StartProfile ("Init");
			
			//World size of tile
			float tcsx = tileSizeX*cellSize;
			float tcsz = tileSizeZ*cellSize;
			
			int voxelCharacterRadius = Mathf.CeilToInt (characterRadius/cellSize);			
			
			Vector3 forcedBoundsMin = forcedBounds.min;
			Vector3 forcedBoundsMax = forcedBounds.max;
			
			Bounds bounds = new Bounds ();
			bounds.SetMinMax(new Vector3 (x*tcsx, 0, z*tcsz) + forcedBoundsMin,
						new Vector3 ((x+1)*tcsx + forcedBoundsMin.x, forcedBoundsMax.y, (z+1)*tcsz + forcedBoundsMin.z)
				);
			vox.borderSize = voxelCharacterRadius + 3;
			
			//Expand borderSize voxels on each side
			bounds.Expand (new Vector3 (vox.borderSize,0,vox.borderSize)*cellSize*2);
			
			vox.forcedBounds = bounds;
			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));
			
 #if ASTARDEBUG
			Debug.Log ("Building Tile " + x+","+z);
			Console.WriteLine ("Recast Graph -- Voxelizing");
#endif
			AstarProfiler.EndProfile ("Init");
			
			
			//Init voxelizer
			vox.Init ();
			
			vox.CollectMeshes ();
			
			vox.VoxelizeInput ();
			
			AstarProfiler.StartProfile ("Filter Ledges");
			
			if (importMode) {
				if (System.IO.File.Exists(Application.dataPath+"/tile."+x+"."+z)) {
					System.IO.FileStream fs = System.IO.File.OpenRead (Application.dataPath+"/tile."+x+"."+z);
					byte[] bytes = new byte[fs.Length];
					fs.Read (bytes,0,(int)fs.Length);
					VoxelArea tmpVox = new VoxelArea(vox.width,vox.depth);
					Pathfinding.Voxels.VoxelSerializeUtility.DeserializeVoxelAreaData (bytes,tmpVox);
					Pathfinding.Voxels.VoxelSerializeUtility.MergeVoxelAreaData(tmpVox,vox.voxelArea,vox.voxelWalkableClimb);
				}
			}
			if (exportMode) {
				System.IO.FileStream fs = System.IO.File.Create(Application.dataPath+"/tile."+x+"."+z);
				byte[] bytes = Pathfinding.Voxels.VoxelSerializeUtility.SerializeVoxelAreaData(vox.voxelArea);
				fs.Write(bytes,0,bytes.Length);
				fs.Close();
			}
			
			vox.FilterLedges (vox.voxelWalkableHeight, vox.voxelWalkableClimb, vox.cellSize, vox.cellHeight, vox.forcedBounds.min);
			
			AstarProfiler.EndProfile ("Filter Ledges");
			
			AstarProfiler.StartProfile ("Filter Low Height Spans");
			vox.FilterLowHeightSpans (vox.voxelWalkableHeight, vox.cellSize, vox.cellHeight, vox.forcedBounds.min);
			AstarProfiler.EndProfile ("Filter Low Height Spans");
			
			vox.BuildCompactField ();
			
			vox.BuildVoxelConnections ();
			
#if ASTARDEBUG
			Console.WriteLine ("Recast Graph -- Eroding");
#endif
			
			vox.ErodeWalkableArea (voxelCharacterRadius);
					
#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");
			
			//matrix = Matrix4x4.TRS (vox.voxelOffset,Quaternion.identity,Int3.Precision*vox.cellScale);
			
			//Position the vertices correctly in the world
			for (int i=0;i<mesh.verts.Length;i++) {
				//Note the multiplication is Scalar multiplication of vectors
				mesh.verts[i] = ((mesh.verts[i]*Int3.Precision) * vox.cellScale) + (Int3)vox.voxelOffset;
				
				//Debug.DrawRay (matrix.MultiplyPoint3x4(vertices[i]),Vector3.up,Color.red);
			}
			
			
#if ASTARDEBUG
			Console.WriteLine ("Recast Graph -- Generating Nodes");
#endif
			
			//NavMeshGraph.GenerateNodes (this,vertices,mesh.tris, out _vectorVertices, out _vertices);
			
			/*NavmeshTile prevTile = tiles[x + z*tileXCount];
			if (prevTile != null) {
				for (int i=0;i<prevTile.nodes.Length;i++) {
					prevTile.nodes[i].v0 = -1;
					prevTile.nodes[i].v1 = -1;
					prevTile.nodes[i].v2 = -1;
				}
			}*/
			
			NavmeshTile tile = CreateTile (vox, mesh, x,z);
			tiles[tile.x + tile.z*tileXCount] = tile;
			
			AstarProfiler.EndProfile ("Build Nodes");
			
#if ASTARDEBUG
			Console.WriteLine ("Recast Graph -- Done");
#endif
			
			AstarProfiler.EndProfile ("Build Tile");
		}
예제 #3
0
		/** Create a tile at tile index \a x , \a z from the mesh.
		 * \warning This implementation is not thread safe. It uses cached variables to improve performance
		 */
		NavmeshTile CreateTile (Voxelize vox, VoxelMesh mesh, int x, int z) {
			
			if (mesh.tris == null) throw new System.ArgumentNullException ("The mesh must be valid. tris is null.");
			if (mesh.verts == null) throw new System.ArgumentNullException ("The mesh must be valid. verts is null.");
			
			//Create a new navmesh tile and assign its settings
			NavmeshTile tile = new NavmeshTile();
			
			tile.x = x;
			tile.z = z;
			tile.w = 1;
			tile.d = 1;
			tile.tris = mesh.tris;
			tile.verts = mesh.verts;
			tile.bbTree = new BBTree(tile);
			
			if (tile.tris.Length % 3 != 0) throw new System.ArgumentException ("Indices array's length must be a multiple of 3 (mesh.tris)");
			
			if (tile.verts.Length >= VertexIndexMask) throw new System.ArgumentException ("Too many vertices per tile (more than "+VertexIndexMask+")." +
				"\nTry enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector");
			
			//Dictionary<Int3, int> firstVerts = new Dictionary<Int3, int> ();
			Dictionary<Int3, int> firstVerts = cachedInt3_int_dict;
			firstVerts.Clear();
			
			int[] compressedPointers = new int[tile.verts.Length];
			
			int count = 0;
			for (int i=0;i<tile.verts.Length;i++) {
				try {
					firstVerts.Add (tile.verts[i], count);
					compressedPointers[i] = count;
					tile.verts[count] = tile.verts[i];
					count++;
				} catch {
					//There are some cases, rare but still there, that vertices are identical
					compressedPointers[i] = firstVerts[tile.verts[i]];
				}
			}
			
			for (int i=0;i<tile.tris.Length;i++) {
				tile.tris[i] = compressedPointers[tile.tris[i]];
			}
			
			Int3[] compressed = new Int3[count];
			for (int i=0;i<count;i++) compressed[i] = tile.verts[i];
			
			tile.verts = compressed;
			
			TriangleMeshNode[] nodes = new TriangleMeshNode[tile.tris.Length/3];
			tile.nodes = nodes;
			
			//Here we are faking a new graph
			//The tile is not added to any graphs yet, but to get the position querys 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
			int graphIndex = AstarPath.active.astarData.graphs.Length;
			
			TriangleMeshNode.SetNavmeshHolder (graphIndex, tile);
			
			//This index will be ORed to the triangle indices
			int tileIndex = x + z*tileXCount;
			tileIndex <<= TileIndexOffset;
			
			//Create nodes and assign triangle indices
			for (int i=0;i<nodes.Length;i++) {
				TriangleMeshNode node = new TriangleMeshNode(active);
				nodes[i] = node;
				node.GraphIndex = (uint)graphIndex;
				node.v0 = tile.tris[i*3+0] | tileIndex;
				node.v1 = tile.tris[i*3+1] | tileIndex;
				node.v2 = tile.tris[i*3+2] | tileIndex;
				
				//Degenerate triangles might ocurr, but they will not cause any large troubles anymore
				//if (Polygon.IsColinear (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
				//	Debug.Log ("COLINEAR!!!!!!");
				//}
				
				//Make sure the triangle is clockwise
				if (!Polygon.IsClockwise (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}
				
				node.Walkable = true;
				node.Penalty = initialPenalty;
				node.UpdatePositionFromVertices();
				tile.bbTree.Insert (node);
			}
			
			CreateNodeConnections (tile.nodes);
			
			//Remove the fake graph
			TriangleMeshNode.SetNavmeshHolder (graphIndex, null);
			
			return tile;
		}
예제 #4
0
		public void UpdateAreaInit (GraphUpdateObject o) {

			if (!o.updatePhysics) {
				return;
			}

			if (!dynamic) {
				throw new System.Exception ("Recast graph must be marked as dynamic to enable graph updates");
			}

			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);

			int voxelCharacterRadius = Mathf.CeilToInt (characterRadius/cellSize);
			int borderSize = voxelCharacterRadius + 3;

			//Expand borderSize voxels on each side
			tileBounds.Expand (new Vector3 (borderSize,0,borderSize)*cellSize*2);

			List<ExtraMesh> extraMeshes;

			CollectMeshes (out extraMeshes, tileBounds);

			Voxelize vox = globalVox;

			if (vox == null) {

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

				vox.maxEdgeLength = maxEdgeLength;

				if (dynamic) globalVox = vox;

			}

			vox.inputExtraMeshes = extraMeshes;

			AstarProfiler.EndProfile ("CollectMeshes");
			AstarProfiler.EndProfile ("UpdateAreaInit");
		}
예제 #5
0
		protected void ScanAllTiles (OnScanStatus statusCallback) {
			
#if ASTARDEBUG
			Console.WriteLine ("Recast Graph -- Collecting Meshes");
#endif	
			
			AstarProfiler.StartProfile ("Finding Meshes");
			List<ExtraMesh> extraMeshes;
			
			System.Console.WriteLine ("Collecting Meshes");
			
			CollectMeshes (out extraMeshes, forcedBounds);
			
			AstarProfiler.EndProfile ("Finding Meshes");
			
			//----
			
			//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
			Console.WriteLine ("Recast Graph -- Creating Voxel Base");
#endif
			
			//Create the voxelizer and set all settings
			Voxelize vox = new Voxelize (cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope);
			vox.inputExtraMeshes = extraMeshes;
			
			vox.maxEdgeLength = maxEdgeLength;
			
			int lastUp = -1;
			System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
			watch.Start();
			
			//Generate all tiles
			for (int z=0;z<td;z++) {
				for (int x=0;x<tw;x++) {
					
					int tileNum = z*tileXCount + x;
					System.Console.WriteLine ("Generating Tile #"+(tileNum) + " of " + td*tw);
					
					//Call statusCallback only 10 times since it is very slow in the editor
					if ((tileNum*10/tiles.Length > lastUp || watch.ElapsedMilliseconds > 2000) && statusCallback != null) {
						lastUp = tileNum*10/tiles.Length;
						watch.Reset();
						watch.Start();
						
						statusCallback (new Progress (AstarMath.MapToRange (0.1f, 0.9f, tileNum/(float)tiles.Length), "Building Tile " + tileNum + "/" + tiles.Length));
					}
					
					BuildTileMesh (vox, x,z);
				}
			}
			
			System.Console.WriteLine ("Assigning Graph Indices");
			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);
			
			for (int z=0;z<td;z++) {
				for (int x=0;x<tw;x++) {
					System.Console.WriteLine ("Connecing Tile #"+(z*tileXCount + x) + " of " + td*tw);
					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 ();
		}
예제 #6
0
 private RecastGraph.NavmeshTile CreateTile(Voxelize vox, VoxelMesh mesh, int x, int z)
 {
     if (mesh.tris == null)
     {
         throw new ArgumentNullException("mesh.tris");
     }
     if (mesh.verts == null)
     {
         throw new ArgumentNullException("mesh.verts");
     }
     RecastGraph.NavmeshTile navmeshTile = new RecastGraph.NavmeshTile();
     navmeshTile.x = x;
     navmeshTile.z = z;
     navmeshTile.w = 1;
     navmeshTile.d = 1;
     navmeshTile.tris = mesh.tris;
     navmeshTile.verts = mesh.verts;
     navmeshTile.bbTree = new BBTree();
     if (navmeshTile.tris.Length % 3 != 0)
     {
         throw new ArgumentException("Indices array's length must be a multiple of 3 (mesh.tris)");
     }
     if (navmeshTile.verts.Length >= 4095)
     {
         throw new ArgumentException("Too many vertices per tile (more than " + 4095 + ").\nTry enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector");
     }
     Dictionary<Int3, int> dictionary = this.cachedInt3_int_dict;
     dictionary.Clear();
     int[] array = new int[navmeshTile.verts.Length];
     int num = 0;
     for (int i = 0; i < navmeshTile.verts.Length; i++)
     {
         if (!dictionary.ContainsKey(navmeshTile.verts[i]))
         {
             dictionary.Add(navmeshTile.verts[i], num);
             array[i] = num;
             navmeshTile.verts[num] = navmeshTile.verts[i];
             num++;
         }
         else
         {
             array[i] = dictionary[navmeshTile.verts[i]];
         }
     }
     for (int j = 0; j < navmeshTile.tris.Length; j++)
     {
         navmeshTile.tris[j] = array[navmeshTile.tris[j]];
     }
     Int3[] array2 = new Int3[num];
     for (int k = 0; k < num; k++)
     {
         array2[k] = navmeshTile.verts[k];
     }
     navmeshTile.verts = array2;
     TriangleMeshNode[] array3 = new TriangleMeshNode[navmeshTile.tris.Length / 3];
     navmeshTile.nodes = array3;
     int graphIndex = AstarPath.active.astarData.graphs.Length;
     TriangleMeshNode.SetNavmeshHolder(graphIndex, navmeshTile);
     int num2 = x + z * this.tileXCount;
     num2 <<= 12;
     for (int l = 0; l < array3.Length; l++)
     {
         TriangleMeshNode triangleMeshNode = new TriangleMeshNode(this.active);
         array3[l] = triangleMeshNode;
         triangleMeshNode.GraphIndex = (uint)graphIndex;
         triangleMeshNode.v0 = (navmeshTile.tris[l * 3] | num2);
         triangleMeshNode.v1 = (navmeshTile.tris[l * 3 + 1] | num2);
         triangleMeshNode.v2 = (navmeshTile.tris[l * 3 + 2] | num2);
         if (!Polygon.IsClockwise(triangleMeshNode.GetVertex(0), triangleMeshNode.GetVertex(1), triangleMeshNode.GetVertex(2)))
         {
             int v = triangleMeshNode.v0;
             triangleMeshNode.v0 = triangleMeshNode.v2;
             triangleMeshNode.v2 = v;
         }
         triangleMeshNode.Walkable = true;
         triangleMeshNode.Penalty = this.initialPenalty;
         triangleMeshNode.UpdatePositionFromVertices();
     }
     navmeshTile.bbTree.RebuildFrom(array3);
     this.CreateNodeConnections(navmeshTile.nodes);
     TriangleMeshNode.SetNavmeshHolder(graphIndex, null);
     return navmeshTile;
 }
예제 #7
0
		protected void ScanAllTiles (OnScanStatus statusCallback) {

#if ASTARDEBUG
			System.Console.WriteLine ("Recast Graph -- Collecting Meshes");
#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 (AstarMath.MapToRange (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);

			for (int z=0;z<td;z++) {
				for (int x=0;x<tw;x++) {
#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 ();
		}
예제 #8
0
 protected void ScanAllTiles(OnScanStatus statusCallback)
 {
     int num = (int)(this.forcedBounds.size.x / this.cellSize + 0.5f);
     int num2 = (int)(this.forcedBounds.size.z / this.cellSize + 0.5f);
     if (!this.useTiles)
     {
         this.tileSizeX = num;
         this.tileSizeZ = num2;
     }
     else
     {
         this.tileSizeX = this.editorTileSize;
         this.tileSizeZ = this.editorTileSize;
     }
     int num3 = (num + this.tileSizeX - 1) / this.tileSizeX;
     int num4 = (num2 + this.tileSizeZ - 1) / this.tileSizeZ;
     this.tileXCount = num3;
     this.tileZCount = num4;
     if (this.tileXCount * this.tileZCount > 524288)
     {
         throw new Exception(string.Concat(new object[]
         {
             "Too many tiles (",
             this.tileXCount * this.tileZCount,
             ") maximum is ",
             524288,
             "\nTry disabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* inspector."
         }));
     }
     this.tiles = new RecastGraph.NavmeshTile[this.tileXCount * this.tileZCount];
     if (this.scanEmptyGraph)
     {
         for (int i = 0; i < num4; i++)
         {
             for (int j = 0; j < num3; j++)
             {
                 this.tiles[i * this.tileXCount + j] = RecastGraph.NewEmptyTile(j, i);
             }
         }
         return;
     }
     Console.WriteLine("Collecting Meshes");
     List<ExtraMesh> inputExtraMeshes;
     this.CollectMeshes(out inputExtraMeshes, this.forcedBounds);
     this.walkableClimb = Mathf.Min(this.walkableClimb, this.walkableHeight);
     Voxelize voxelize = new Voxelize(this.cellHeight, this.cellSize, this.walkableClimb, this.walkableHeight, this.maxSlope);
     voxelize.inputExtraMeshes = inputExtraMeshes;
     voxelize.maxEdgeLength = this.maxEdgeLength;
     int num5 = -1;
     Stopwatch stopwatch = Stopwatch.StartNew();
     for (int k = 0; k < num4; k++)
     {
         for (int l = 0; l < num3; l++)
         {
             int num6 = k * this.tileXCount + l;
             Console.WriteLine(string.Concat(new object[]
             {
                 "Generating Tile #",
                 num6,
                 " of ",
                 num4 * num3
             }));
             if (statusCallback != null && (num6 * 10 / this.tiles.Length > num5 || stopwatch.ElapsedMilliseconds > 2000L))
             {
                 num5 = num6 * 10 / this.tiles.Length;
                 stopwatch.Reset();
                 stopwatch.Start();
                 statusCallback(new Progress(AstarMath.MapToRange(0.1f, 0.9f, (float)num6 / (float)this.tiles.Length), string.Concat(new object[]
                 {
                     "Building Tile ",
                     num6,
                     "/",
                     this.tiles.Length
                 })));
             }
             this.BuildTileMesh(voxelize, l, k);
         }
     }
     Console.WriteLine("Assigning Graph Indices");
     if (statusCallback != null)
     {
         statusCallback(new Progress(0.9f, "Connecting tiles"));
     }
     uint graphIndex = (uint)AstarPath.active.astarData.GetGraphIndex(this);
     GraphNodeDelegateCancelable del = delegate(GraphNode n)
     {
         n.GraphIndex = graphIndex;
         return true;
     };
     this.GetNodes(del);
     for (int m = 0; m < num4; m++)
     {
         for (int n2 = 0; n2 < num3; n2++)
         {
             Console.WriteLine(string.Concat(new object[]
             {
                 "Connecing Tile #",
                 m * this.tileXCount + n2,
                 " of ",
                 num4 * num3
             }));
             if (n2 < num3 - 1)
             {
                 this.ConnectTiles(this.tiles[n2 + m * this.tileXCount], this.tiles[n2 + 1 + m * this.tileXCount]);
             }
             if (m < num4 - 1)
             {
                 this.ConnectTiles(this.tiles[n2 + m * this.tileXCount], this.tiles[n2 + (m + 1) * this.tileXCount]);
             }
         }
     }
 }
예제 #9
0
 protected void BuildTileMesh(Voxelize vox, int x, int z)
 {
     float num = (float)this.tileSizeX * this.cellSize;
     float num2 = (float)this.tileSizeZ * this.cellSize;
     int num3 = Mathf.CeilToInt(this.characterRadius / this.cellSize);
     Vector3 min = this.forcedBounds.min;
     Vector3 max = this.forcedBounds.max;
     Bounds forcedBounds = default(Bounds);
     forcedBounds.SetMinMax(new Vector3((float)x * num, 0f, (float)z * num2) + min, new Vector3((float)(x + 1) * num + min.x, max.y, (float)(z + 1) * num2 + min.z));
     vox.borderSize = num3 + 3;
     forcedBounds.Expand(new Vector3((float)vox.borderSize, 0f, (float)vox.borderSize) * this.cellSize * 2f);
     vox.forcedBounds = forcedBounds;
     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.CollectMeshes();
     vox.VoxelizeInput();
     vox.FilterLedges(vox.voxelWalkableHeight, vox.voxelWalkableClimb, vox.cellSize, vox.cellHeight, vox.forcedBounds.min);
     vox.FilterLowHeightSpans(vox.voxelWalkableHeight, vox.cellSize, vox.cellHeight, vox.forcedBounds.min);
     vox.BuildCompactField();
     vox.BuildVoxelConnections();
     vox.ErodeWalkableArea(num3);
     vox.BuildDistanceField();
     vox.BuildRegions();
     VoxelContourSet cset = new VoxelContourSet();
     vox.BuildContours(this.contourMaxError, 1, cset, 1);
     VoxelMesh mesh;
     vox.BuildPolyMesh(cset, 3, out mesh);
     for (int i = 0; i < mesh.verts.Length; i++)
     {
         mesh.verts[i] = mesh.verts[i] * 1000 * vox.cellScale + (Int3)vox.voxelOffset;
     }
     RecastGraph.NavmeshTile navmeshTile = this.CreateTile(vox, mesh, x, z);
     this.tiles[navmeshTile.x + navmeshTile.z * this.tileXCount] = navmeshTile;
 }
예제 #10
0
 public void UpdateAreaInit(GraphUpdateObject o)
 {
     if (!o.updatePhysics)
     {
         return;
     }
     if (!this.dynamic)
     {
         throw new Exception("Recast graph must be marked as dynamic to enable graph updates");
     }
     RelevantGraphSurface.UpdateAllPositions();
     IntRect touchingTiles = this.GetTouchingTiles(o.bounds);
     Bounds tileBounds = this.GetTileBounds(touchingTiles);
     int num = Mathf.CeilToInt(this.characterRadius / this.cellSize);
     int num2 = num + 3;
     tileBounds.Expand(new Vector3((float)num2, 0f, (float)num2) * this.cellSize * 2f);
     List<ExtraMesh> inputExtraMeshes;
     this.CollectMeshes(out inputExtraMeshes, tileBounds);
     Voxelize voxelize = this.globalVox;
     if (voxelize == null)
     {
         voxelize = new Voxelize(this.cellHeight, this.cellSize, this.walkableClimb, this.walkableHeight, this.maxSlope);
         voxelize.maxEdgeLength = this.maxEdgeLength;
         if (this.dynamic)
         {
             this.globalVox = voxelize;
         }
     }
     voxelize.inputExtraMeshes = inputExtraMeshes;
 }
예제 #11
0
		protected void BuildTileMesh (Voxelize vox, int x, int z) {
			AstarProfiler.StartProfile("Build Tile");

			AstarProfiler.StartProfile("Init");

			//World size of tile
			float tcsx = tileSizeX*cellSize;
			float tcsz = tileSizeZ*cellSize;

			int voxelCharacterRadius = Mathf.CeilToInt(characterRadius/cellSize);

			Vector3 forcedBoundsMin = forcedBounds.min;
			Vector3 forcedBoundsMax = forcedBounds.max;

			var bounds = new Bounds();
			bounds.SetMinMax(new Vector3(x*tcsx, 0, z*tcsz) + forcedBoundsMin,
				new Vector3((x+1)*tcsx + forcedBoundsMin.x, forcedBoundsMax.y, (z+1)*tcsz + forcedBoundsMin.z)
				);
			vox.borderSize = voxelCharacterRadius + 3;

			//Expand borderSize voxels on each side
			bounds.Expand(new Vector3(vox.borderSize, 0, vox.borderSize)*cellSize*2);

			vox.forcedBounds = bounds;
			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));

 #if ASTARDEBUG
			Debug.Log("Building Tile " + x+","+z);
			System.Console.WriteLine("Recast Graph -- Voxelizing");
#endif
			AstarProfiler.EndProfile("Init");


			//Init voxelizer
			vox.Init();

			vox.CollectMeshes();

			vox.VoxelizeInput();

			AstarProfiler.StartProfile("Filter Ledges");


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

			AstarProfiler.EndProfile("Filter Ledges");

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

			vox.BuildCompactField();

			vox.BuildVoxelConnections();

#if ASTARDEBUG
			System.Console.WriteLine("Recast Graph -- Eroding");
#endif

			vox.ErodeWalkableArea(voxelCharacterRadius);

#if ASTARDEBUG
			System.Console.WriteLine("Recast Graph -- Building Distance Field");
#endif

			vox.BuildDistanceField();

#if ASTARDEBUG
			System.Console.WriteLine("Recast Graph -- Building Regions");
#endif

			vox.BuildRegions();

#if ASTARDEBUG
			System.Console.WriteLine("Recast Graph -- Building Contours");
#endif

			var cset = new VoxelContourSet();

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

#if ASTARDEBUG
			System.Console.WriteLine("Recast Graph -- Building Poly Mesh");
#endif

			VoxelMesh mesh;

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

#if ASTARDEBUG
			System.Console.WriteLine("Recast Graph -- Building Nodes");
#endif

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

			AstarProfiler.StartProfile("Build Nodes");

			// Debug code
			//matrix = Matrix4x4.TRS (vox.voxelOffset,Quaternion.identity,Int3.Precision*vox.cellScale);

			//Position the vertices correctly in the world
			for (int i = 0; i < mesh.verts.Length; i++) {
				//Note the multiplication is Scalar multiplication of vectors
				mesh.verts[i] = ((mesh.verts[i]*Int3.Precision) * vox.cellScale) + (Int3)vox.voxelOffset;

				// Debug code
				//Debug.DrawRay (matrix.MultiplyPoint3x4(vertices[i]),Vector3.up,Color.red);
			}


#if ASTARDEBUG
			System.Console.WriteLine("Recast Graph -- Generating Nodes");
#endif

			NavmeshTile tile = CreateTile(vox, mesh, x, z);
			tiles[tile.x + tile.z*tileXCount] = tile;

			AstarProfiler.EndProfile("Build Nodes");

#if ASTARDEBUG
			System.Console.WriteLine("Recast Graph -- Done");
#endif

			AstarProfiler.EndProfile("Build Tile");
		}
		protected IEnumerable<Progress> ScanAllTiles () {

			// 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 this is true, just fill the graph with empty tiles
			if (scanEmptyGraph) {
				FillWithEmptyTiles();
				yield break;
			}

			yield return new Progress(0, "Finding Meshes");
			List<ExtraMesh> extraMeshes;
			CollectMeshes (out extraMeshes, forcedBounds);

			// 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;

			// Generate all tiles
			for (int z=0;z<td;z++) {
				for (int x=0;x<tw;x++) {

					int tileNum = z*tileXCount + x;
					yield return new Progress(Mathf.Lerp(0.1f, 0.9f, tileNum/(float)tiles.Length), "Generating Tile " + tileNum + "/" + tiles.Length);

					BuildTileMesh (vox, x,z);
				}
			}

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

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

			GetNodes (node => {
				node.GraphIndex = graphIndex;
				return true;
			});

			for (int z=0;z<td;z++) {
				for (int x=0;x<tw;x++) {
					yield return new Progress(Mathf.Lerp(0.9f, 1.0f, (z*tileXCount+x)/(float)tiles.Length), "Connecting Tile #"+(z*tileXCount + x) + "/" + tiles.Length);

					// Connect with tile at (x+1,z) and (x,z+1)
					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]);
				}
			}
		}