Exemplo n.º 1
0
	void Prepare(Mesh oldMesh, bool cachePreparation = true) {
#if UNITY_4_OR_ABOVE
		if ( !oldMesh.isReadable ) {
			Debug.LogError("The mesh is not readable. Switch on the \"Read/Write Enabled\"" +
				" option on the mesh's import settings.");
			return;
		}
#endif

		var usePhysics = type == ExplosionType.Physics;

		MeshExplosionPreparation prep;

		if ( cache.TryGetValue(oldMesh, out prep) ) {
			// The caching is different for physics explosions and non-physics explosions, so make
			// sure that we have the correct stuff:
			if ( (usePhysics && prep.physicsMeshes != null) ||
				(!usePhysics && prep.startMesh != null) ) {

				preparation = prep;
				return;
			}
		}

		// Make a copy of the mesh but with every triangle made discrete so that it doesn't share
		// any vertices with any other triangle.

		var oldVertices = oldMesh.vertices;
		var oldNormals = oldMesh.normals;
		var oldTangents = oldMesh.tangents;
		var oldUV = oldMesh.uv;
		var oldUV2 = oldMesh.uv2;
		var oldColors = oldMesh.colors;

		var subMeshCount = oldMesh.subMeshCount;
		var oldMeshTriangles = new int[subMeshCount][];
		var frontMeshTrianglesPerSubMesh = usePhysics ?
			prep.frontMeshTrianglesPerSubMesh = new int[subMeshCount] : null;
		int frontTriangles = 0;

		for ( var subMesh = 0; subMesh < subMeshCount; ++subMesh ) {
			int[] triangles;
			oldMeshTriangles[subMesh] = triangles = oldMesh.GetTriangles(subMesh);
			var frontMeshTrianglesInThisSubMesh = triangles.Length / 3;
			if ( usePhysics )
				frontMeshTrianglesPerSubMesh[subMesh] = frontMeshTrianglesInThisSubMesh;
			frontTriangles += frontMeshTrianglesInThisSubMesh;
		}

		prep.totalFrontTriangles = frontTriangles;
		var totalTriangles = frontTriangles * 2; // back faces
		var newTotalVertices = usePhysics ?
			3 * 2 : // one triangle, both sides
			totalTriangles * 3;

		const int vertexLimit = 65534;
		if ( newTotalVertices > vertexLimit ) {
			Debug.LogError("The mesh has too many triangles to explode. It must have" +
				" " + ((vertexLimit / 3) / 2) + " or fewer triangles.");
			return;
		}

		var newVertices = new Vector3[newTotalVertices];
		var newNormals = oldNormals == null || oldNormals.Length == 0 ?
			null : new Vector3[newTotalVertices];
		var newTangents = oldTangents == null || oldTangents.Length == 0 ?
			null : new Vector4[newTotalVertices];
		var newUV = oldUV == null || oldUV.Length == 0 ?
			null : new Vector2[newTotalVertices];
		var newUV2 = oldUV2 == null || oldUV2.Length == 0 ?
			null : new Vector2[newTotalVertices];
		var newColors = oldColors == null || oldColors.Length == 0 ?
			null : new Color[newTotalVertices];

		var triangleCentroids = prep.triangleCentroids = new Vector3[frontTriangles];

		var physicsMeshes = prep.physicsMeshes = usePhysics ? new Mesh[frontTriangles] : null;
		var rotations = prep.rotations = usePhysics ? new Quaternion[frontTriangles] : null;

		var physicsMeshTriangles = usePhysics ? new int[] { 0, 1, 2, 3, 4, 5 } : null;

		var newVertexNumber = 0;
		var wholeMeshTriangleIndex = 0;

		var invRotation = Quaternion.identity;

		for ( var subMesh = 0; subMesh < subMeshCount; ++subMesh ) {
			var triangles = oldMeshTriangles[subMesh];
			var n = triangles.Length;

			int i = 0;

			while ( i < n ) {
				var triangleStartI = i;
				var centroid = Vector3.zero;

				for ( int repeat = 0; repeat < 2; ++repeat ) {
					i = triangleStartI;
					var back = repeat == 1;

					while ( i < n ) {
						var oldVertexNumber = triangles[back ?
							(triangleStartI + (3 - 1 - (i - triangleStartI))) : i];

						if ( usePhysics && (newVertexNumber % 6) == 0 ) { // Start of a triangle
							var a = oldVertices[oldVertexNumber];
							var b = oldVertices[triangles[i + 1]];
							var c = oldVertices[triangles[i + 2]];

							var triangleRealNormal = Vector3.Cross(b - a, c - a);
							// We want to rotate the triangle so that it is flat on the x-z plane.
							// The reason for that is so that we can use an axis-aligned box
							// collider to be its physics proxy.
							rotations[wholeMeshTriangleIndex] =
								Quaternion.FromToRotation(Vector3.up, triangleRealNormal);
							invRotation =
								Quaternion.FromToRotation(triangleRealNormal, Vector3.up);
							triangleCentroids[wholeMeshTriangleIndex] = centroid =
								(a + b + c) / 3;
						}

						if ( !back ) {
							newVertices[newVertexNumber] = invRotation *
								(oldVertices[oldVertexNumber] - centroid);

							if ( newNormals != null ) {
								newNormals[newVertexNumber] = invRotation *
									oldNormals[oldVertexNumber];
							}
							if ( newTangents != null ) {
								newTangents[newVertexNumber] = invRotation *
									oldTangents[oldVertexNumber];
							}
						} else {
							// This stuff is handled by MeshExplosion.SetBackTriangleVertices().
						}

						if ( newUV != null ) {
							newUV[newVertexNumber] = oldUV[oldVertexNumber];
						}
						if ( newUV2 != null ) {
							newUV2[newVertexNumber] = oldUV2[oldVertexNumber];
						}
						if ( newColors != null ) {
							newColors[newVertexNumber] = oldColors[oldVertexNumber];
						}

						// It's important that these are here rather than in a for statement so
						// that they get executed even if we break.
						++i;
						++newVertexNumber;

						if ( (newVertexNumber % 6) == 0 ) { // End of a triangle
							if ( usePhysics ) {
								MeshExplosion.SetBackTriangleVertices(
									newVertices, newNormals, newTangents, 1);

								var mesh = new Mesh();

								mesh.vertices = newVertices;
								if ( newNormals != null )
									mesh.normals = newNormals;
								if ( newTangents != null ) {
									mesh.tangents = newTangents;
								}
								if ( newUV != null )
									mesh.uv = newUV;
								if ( newUV2 != null )
									mesh.uv2 = newUV2;
								if ( newColors != null )
									mesh.colors = newColors;
								mesh.triangles = physicsMeshTriangles;

								physicsMeshes[wholeMeshTriangleIndex] = mesh;

								newVertexNumber = 0;
							}
							break;
						} else if ( (newVertexNumber % 3) == 0 && !back ) {
							break;
						}
					}
				}

				++wholeMeshTriangleIndex;
			}
		}

		var newMeshCenter = Vector3.zero;
		if ( !usePhysics ) {
			var newMesh = prep.startMesh = new Mesh();
#if UNITY_4_OR_ABOVE
			newMesh.MarkDynamic();
#endif
			newMesh.vertices = newVertices;
			if ( newNormals != null )
				newMesh.normals = newNormals;
			if ( newTangents != null )
				newMesh.tangents = newTangents;
			if ( newUV != null )
				newMesh.uv = newUV;
			if ( newUV2 != null )
				newMesh.uv2 = newUV2;
			if ( newColors != null )
				newMesh.colors = newColors;

			newMesh.subMeshCount = subMeshCount;
			newVertexNumber = 0;
			for ( var subMesh = 0; subMesh < subMeshCount; ++subMesh ) {
				var n = oldMeshTriangles[subMesh].Length * 2;
				var newTriangles = new int[n];
				for ( var i = 0; i < n; ++i, ++newVertexNumber ) {
					newTriangles[i] = newVertexNumber;
				}
				newMesh.SetTriangles(newTriangles, subMesh);
			}

			if ( useMeshBoundsCenter )
				newMeshCenter = newMesh.bounds.center;
		}

		var triangleNormals = prep.triangleNormals = new Vector3[frontTriangles];

		var firstVertexIndex = 0;
		for ( var triangleNumber = 0; triangleNumber < frontTriangles;
			++triangleNumber, firstVertexIndex += 6 ) {

			Vector3 centroid;
			if ( usePhysics ) {
				centroid = triangleCentroids[triangleNumber];
			} else {
				centroid =
					(newVertices[firstVertexIndex] +
					newVertices[firstVertexIndex + 1] +
					newVertices[firstVertexIndex + 2]) / 3;
				triangleCentroids[triangleNumber] = centroid;
			}

			Vector3 normal;
			if ( useNormals && newNormals != null ) {
				if ( usePhysics ) {
					newNormals = physicsMeshes[triangleNumber].normals;
					firstVertexIndex = 0;
				}

				normal =
					((newNormals[firstVertexIndex] +
					newNormals[firstVertexIndex + 1] +
					newNormals[firstVertexIndex + 2]) / 3).normalized;
			} else {
				normal = centroid;
				if ( useMeshBoundsCenter ) {
					normal -= newMeshCenter;
				}
				normal.Normalize();
			}

			triangleNormals[triangleNumber] = normal;
		}

		preparation = prep;
		if ( cachePreparation )
			cache[oldMesh] = prep;

		if ( fadeTime != 0 && !shadersAlreadyHandleTransparency ) {
			// Preload any replacement shaders that will be needed:
			foreach ( var i in GetComponent<Renderer>().sharedMaterials ) {
				var shader = i.shader;
				var replacement = Fade.GetReplacementFor(shader);
				if ( replacement == null || !replacement.name.StartsWith("Transparent/") ) {
					Debug.LogWarning("Couldn't find an explicitly transparent version of shader" +
						" '" + shader.name + "' so fading may not work. If the shader does" +
						" support transparency then this warning can be avoided by enabling" +
						" the 'Shaders Already Handle Transparency' option.");
				}
			}
		}
	}