Esempio n. 1
0
		static void GetSceneMeshes (Bounds bounds, List<string> tagMask, LayerMask layerMask, List<ExtraMesh> meshes) {

			if ( (tagMask != null && tagMask.Count > 0) || layerMask != 0 ) {
				var filters = GameObject.FindObjectsOfType(typeof(MeshFilter)) as MeshFilter[];

				var filteredFilters = new List<MeshFilter> (filters.Length/3);

				for (int i=0;i<filters.Length;i++) {
					MeshFilter filter = filters[i];
					Renderer rend = filter.GetComponent<Renderer>();

					if (rend != null && filter.sharedMesh != null && rend.enabled && (((1 << filter.gameObject.layer) & layerMask) != 0 || tagMask.Contains (filter.tag))) {
						if (filter.GetComponent<RecastMeshObj>() == null) {
							filteredFilters.Add (filter);
						}
					}
				}

				var cachedVertices = new Dictionary<Mesh, Vector3[]>();
				var cachedTris = new Dictionary<Mesh, int[]>();

				bool containedStatic = false;

				for (int i=0;i<filteredFilters.Count;i++) {
					MeshFilter filter = filteredFilters[i];

					// Note, guaranteed to have a renderer
					Renderer rend = filter.GetComponent<Renderer>();

					//Workaround for statically batched meshes
					if (rend.isPartOfStaticBatch) {
						containedStatic = true;
					} else {
						//Only include it if it intersects with the graph
						if (rend.bounds.Intersects (bounds)) {
							Mesh mesh = filter.sharedMesh;
							var smesh = new ExtraMesh();
							smesh.matrix = rend.localToWorldMatrix;
							smesh.original = filter;
							if (cachedVertices.ContainsKey (mesh)) {
								smesh.vertices = cachedVertices[mesh];
								smesh.triangles = cachedTris[mesh];
							} else {
								smesh.vertices = mesh.vertices;
								smesh.triangles = mesh.triangles;
								cachedVertices[mesh] = smesh.vertices;
								cachedTris[mesh] = smesh.triangles;
							}

							smesh.bounds = rend.bounds;

							meshes.Add (smesh);
						}
					}

					if (containedStatic)
						Debug.LogWarning ("Some meshes were statically batched. These meshes can not be used for navmesh calculation" +
							" due to technical constraints.\nDuring runtime scripts cannot access the data of meshes which have been statically batched.\n" +
							"One way to solve this problem is to use cached startup (Save & Load tab in the inspector) to only calculate the graph when the game is not playing.");
				}

	#if ASTARDEBUG
				int y = 0;
				foreach (ExtraMesh smesh in meshes) {
					y++;
					Vector3[] vecs = smesh.vertices;
					int[] tris = smesh.triangles;

					for (int i=0;i<tris.Length;i+=3) {
						Vector3 p1 = smesh.matrix.MultiplyPoint3x4(vecs[tris[i+0]]);
						Vector3 p2 = smesh.matrix.MultiplyPoint3x4(vecs[tris[i+1]]);
						Vector3 p3 = smesh.matrix.MultiplyPoint3x4(vecs[tris[i+2]]);

						Debug.DrawLine (p1,p2,Color.red,1);
						Debug.DrawLine (p2,p3,Color.red,1);
						Debug.DrawLine (p3,p1,Color.red,1);
					}

				}
	#endif
			}
		}
Esempio n. 2
0
		/** Rasterizes a collider to a mesh assuming it's vertices should be multiplied with the matrix.
		 * Note that the bounds of the returned ExtraMesh is based on collider.bounds. So you might want to
		 * call myExtraMesh.RecalculateBounds on the returned mesh to recalculate it if the collider.bounds would
		 * not give the correct value.
		  * */
		ExtraMesh RasterizeCollider (Collider col, Matrix4x4 localToWorldMatrix) {
			if (col is BoxCollider) {
				var collider = col as BoxCollider;

				Matrix4x4 matrix = Matrix4x4.TRS (collider.center, Quaternion.identity, collider.size*0.5f);
				matrix = localToWorldMatrix * matrix;

				Bounds b = collider.bounds;

				var m = new ExtraMesh(BoxColliderVerts,BoxColliderTris, b, matrix);

#if ASTARDEBUG

				Vector3[] verts = BoxColliderVerts;
				int[] tris = BoxColliderTris;

				for (int i=0;i<tris.Length;i+=3) {
					Debug.DrawLine (matrix.MultiplyPoint3x4(verts[tris[i]]),matrix.MultiplyPoint3x4(verts[tris[i+1]]), Color.yellow);
					Debug.DrawLine (matrix.MultiplyPoint3x4(verts[tris[i+2]]),matrix.MultiplyPoint3x4(verts[tris[i+1]]), Color.yellow);
					Debug.DrawLine (matrix.MultiplyPoint3x4(verts[tris[i]]),matrix.MultiplyPoint3x4(verts[tris[i+2]]), Color.yellow);

					//Normal debug
					/*Vector3 va = matrix.MultiplyPoint3x4(verts[tris[i]]);
					Vector3 vb = matrix.MultiplyPoint3x4(verts[tris[i+1]]);
					Vector3 vc = matrix.MultiplyPoint3x4(verts[tris[i+2]]);

					Debug.DrawRay ((va+vb+vc)/3, Vector3.Cross(vb-va,vc-va).normalized,Color.blue);*/
				}
#endif
				return m;
			} else if (col is SphereCollider || col is CapsuleCollider) {

				var scollider = col as SphereCollider;
				var ccollider = col as CapsuleCollider;

				float radius = (scollider != null ? scollider.radius : ccollider.radius);
				float height = scollider != null ? 0 : (ccollider.height*0.5f/radius) - 1;

				Matrix4x4 matrix = Matrix4x4.TRS (scollider != null ? scollider.center : ccollider.center, Quaternion.identity, Vector3.one*radius);
				matrix = localToWorldMatrix * matrix;

				//Calculate the number of rows to use
				//grows as sqrt(x) to the radius of the sphere/capsule which I have found works quite good
				int rows = Mathf.Max (4,Mathf.RoundToInt(colliderRasterizeDetail*Mathf.Sqrt(matrix.MultiplyVector(Vector3.one).magnitude)));

				if (rows > 100) {
					Debug.LogWarning ("Very large detail for some collider meshes. Consider decreasing Collider Rasterize Detail (RecastGraph)");
				}

				int cols = rows;

				Vector3[] verts;
				int[] trisArr;


				//Check if we have already calculated a similar capsule
				CapsuleCache cached = null;
				for (int i=0;i<capsuleCache.Count;i++) {
					CapsuleCache c = capsuleCache[i];
					if (c.rows == rows && Mathf.Approximately (c.height, height)) {
						cached = c;
					}
				}

				if (cached == null) {
					//Generate a sphere/capsule mesh

					verts = new Vector3[(rows)*cols + 2];

					var tris = new List<int>();
					verts[verts.Length-1] = Vector3.up;

					for (int r=0;r<rows;r++) {
						for (int c=0;c<cols;c++) {
							verts[c + r*cols] = new Vector3 (Mathf.Cos (c*Mathf.PI*2/cols)*Mathf.Sin ((r*Mathf.PI/(rows-1))), Mathf.Cos ((r*Mathf.PI/(rows-1))) + (r < rows/2 ? height : -height) , Mathf.Sin (c*Mathf.PI*2/cols)*Mathf.Sin ((r*Mathf.PI/(rows-1))));
						}
					}

					verts[verts.Length-2] = Vector3.down;

					for (int i=0, j = cols-1;i<cols; j = i++) {
						tris.Add (verts.Length-1);
						tris.Add (0*cols + j);
						tris.Add (0*cols + i);
					}

					for (int r=1;r<rows;r++) {
						for (int i=0, j = cols-1;i<cols; j = i++) {
							tris.Add (r*cols + i);
							tris.Add (r*cols + j);
							tris.Add ((r-1)*cols + i);

							tris.Add ((r-1)*cols + j);
							tris.Add ((r-1)*cols + i);
							tris.Add (r*cols + j);
						}
					}

					for (int i=0, j = cols-1;i<cols; j = i++) {
						tris.Add (verts.Length-2);
						tris.Add ((rows-1)*cols + j);
						tris.Add ((rows-1)*cols + i);
					}

					//Enqueue calculated mesh to the cache
					cached = new CapsuleCache ();
					cached.rows = rows;
					cached.height = height;
					cached.verts = verts;
					cached.tris = tris.ToArray();
					capsuleCache.Add (cached);
				}

				//Read from cache
				verts = cached.verts;
				trisArr = cached.tris;

				Bounds b = col.bounds;

				var m = new ExtraMesh(verts,trisArr, b, matrix);

#if ASTARDEBUG
				for (int i=0;i<trisArr.Length;i+=3) {
					Debug.DrawLine (matrix.MultiplyPoint3x4(verts[trisArr[i]]),matrix.MultiplyPoint3x4(verts[trisArr[i+1]]), Color.yellow);
					Debug.DrawLine (matrix.MultiplyPoint3x4(verts[trisArr[i+2]]),matrix.MultiplyPoint3x4(verts[trisArr[i+1]]), Color.yellow);
					Debug.DrawLine (matrix.MultiplyPoint3x4(verts[trisArr[i]]),matrix.MultiplyPoint3x4(verts[trisArr[i+2]]), Color.yellow);
				}
#endif
				return m;
			} else if (col is MeshCollider) {
				var collider = col as MeshCollider;

				if ( collider.sharedMesh != null ) {
					var m = new ExtraMesh(collider.sharedMesh.vertices, collider.sharedMesh.triangles, collider.bounds, localToWorldMatrix);
					return m;
				}
			}

			return new ExtraMesh();
		}
Esempio n. 3
0
		/** Find all relevant RecastMeshObj components and create ExtraMeshes for them */
		public void GetRecastMeshObjs (Bounds bounds, List<ExtraMesh> buffer) {
			List<RecastMeshObj> buffer2 = ListPool<RecastMeshObj>.Claim ();

			// Get all recast mesh objects inside the bounds
			RecastMeshObj.GetAllInBounds (buffer2, bounds);

			var cachedVertices = new Dictionary<Mesh, Vector3[]>();
			var cachedTris = new Dictionary<Mesh, int[]>();

			// Create an ExtraMesh object
			// for each RecastMeshObj
			for (int i=0;i<buffer2.Count;i++) {
				MeshFilter filter = buffer2[i].GetMeshFilter();
				Renderer rend = filter != null ? filter.GetComponent<Renderer>() : null;

				if (filter != null && rend != null) {
					Mesh mesh = filter.sharedMesh;

					var smesh = new ExtraMesh();
					smesh.matrix = rend.localToWorldMatrix;
					smesh.original = filter;
					smesh.area = buffer2[i].area;

					// Don't read the vertices and triangles from the
					// mesh if we have seen the same mesh previously
					if (cachedVertices.ContainsKey (mesh)) {
						smesh.vertices = cachedVertices[mesh];
						smesh.triangles = cachedTris[mesh];
					} else {
						smesh.vertices = mesh.vertices;
						smesh.triangles = mesh.triangles;
						cachedVertices[mesh] = smesh.vertices;
						cachedTris[mesh] = smesh.triangles;
					}

					smesh.bounds = rend.bounds;

					buffer.Add (smesh);
				} else {
					Collider coll = buffer2[i].GetCollider();

					if (coll == null) {
						Debug.LogError ("RecastMeshObject ("+buffer2[i].gameObject.name +") didn't have a collider or MeshFilter+Renderer attached");
						continue;
					}

					ExtraMesh smesh = RasterizeCollider (coll);
					smesh.area = buffer2[i].area;

					//Make sure a valid ExtraMesh was returned
					if (smesh.vertices != null) buffer.Add(smesh);
				}
			}

			//Clear cache to avoid memory leak
			capsuleCache.Clear();

			ListPool<RecastMeshObj>.Release (buffer2);
		}
Esempio n. 4
0
		void CollectTreeMeshes (Terrain terrain, List<ExtraMesh> extraMeshes) {
			TerrainData data = terrain.terrainData;

			for (int i=0;i<data.treeInstances.Length;i++) {
				TreeInstance instance = data.treeInstances[i];
				TreePrototype prot = data.treePrototypes[instance.prototypeIndex];

				// Make sure that the tree prefab exists
				if (prot.prefab == null) {
					continue;
				}

				var collider = prot.prefab.GetComponent<Collider>();

				if (collider == null) {
					var b = new Bounds(terrain.transform.position + Vector3.Scale(instance.position,data.size), new Vector3(instance.widthScale,instance.heightScale,instance.widthScale));

					Matrix4x4 matrix = Matrix4x4.TRS (terrain.transform.position +  Vector3.Scale(instance.position,data.size), Quaternion.identity, new Vector3(instance.widthScale,instance.heightScale,instance.widthScale)*0.5f);


					var m = new ExtraMesh(BoxColliderVerts,BoxColliderTris, b, matrix);

#if ASTARDEBUG
					Debug.DrawRay (instance.position, Vector3.up, Color.red,1);
#endif
					extraMeshes.Add (m);
				} else {
					//The prefab has a collider, use that instead
					Vector3 pos = terrain.transform.position + Vector3.Scale(instance.position,data.size);
					var scale = new Vector3(instance.widthScale,instance.heightScale,instance.widthScale);

					//Generate a mesh from the collider
					ExtraMesh m = RasterizeCollider (collider,Matrix4x4.TRS (pos,Quaternion.identity,scale));

					//Make sure a valid mesh was generated
					if (m.vertices != null) {
#if ASTARDEBUG
						Debug.DrawRay (pos, Vector3.up, Color.yellow,1);
#endif
						//The bounds are incorrectly based on collider.bounds
						m.RecalculateBounds ();
						extraMeshes.Add (m);
					}
				}
			}
		}