mirror of
				https://github.com/maxartz15/VertexAnimation.git
				synced 2025-10-31 16:45:51 +01:00 
			
		
		
		
	MeshSimplifier
Basic setup to simplify meshes and generate LODs.
This commit is contained in:
		| @@ -16,6 +16,8 @@ namespace TAO.VertexAnimation.Editor | |||||||
| 		public int textureWidth = 512; | 		public int textureWidth = 512; | ||||||
|  |  | ||||||
| 		public bool generateLODS = true; | 		public bool generateLODS = true; | ||||||
|  | 		// TODO: Improve curve/lod settings. LOD-Mesh Quality pair. | ||||||
|  | 		//public Vector2[] lodLevels = new Vector2[4] { new Vector2(32, 100), new Vector2(32, 65), new Vector2(32, 30), new Vector2(3, 0) }; | ||||||
| 		public AnimationCurve lodCurve = new AnimationCurve(new Keyframe(0, 1), new Keyframe(1, 0.01f)); | 		public AnimationCurve lodCurve = new AnimationCurve(new Keyframe(0, 1), new Keyframe(1, 0.01f)); | ||||||
| 		public bool saveBakedDataToAsset = true; | 		public bool saveBakedDataToAsset = true; | ||||||
| 		public bool generateAnimationBook = true; | 		public bool generateAnimationBook = true; | ||||||
| @@ -41,8 +43,7 @@ namespace TAO.VertexAnimation.Editor | |||||||
|  |  | ||||||
| 			if (generateLODS) | 			if (generateLODS) | ||||||
| 			{ | 			{ | ||||||
| 				// TODO: LODs. | 				meshes = bakedData.mesh.GenerateLOD(3, lodCurve); | ||||||
| 				meshes = new Mesh[1] { bakedData.mesh }; |  | ||||||
| 			} | 			} | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| @@ -57,7 +58,10 @@ namespace TAO.VertexAnimation.Editor | |||||||
| 			AssetDatabaseUtils.RemoveChildAssets(this, new Object[2] { book, material }); | 			AssetDatabaseUtils.RemoveChildAssets(this, new Object[2] { book, material }); | ||||||
|  |  | ||||||
| 			// TODO: LODs | 			// TODO: LODs | ||||||
| 			AssetDatabase.AddObjectToAsset(bakedData.mesh, this); | 			foreach (var m in meshes) | ||||||
|  | 			{ | ||||||
|  | 				AssetDatabase.AddObjectToAsset(m, this); | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			foreach (var pm in bakedData.positionMaps) | 			foreach (var pm in bakedData.positionMaps) | ||||||
| 			{ | 			{ | ||||||
|   | |||||||
| @@ -243,5 +243,5 @@ namespace TAO.VertexAnimation | |||||||
| 			SkinnedMeshRenderer target = gameObject.AddComponent<SkinnedMeshRenderer>(); | 			SkinnedMeshRenderer target = gameObject.AddComponent<SkinnedMeshRenderer>(); | ||||||
| 			target.Combine(skinnedMeshes, meshes); | 			target.Combine(skinnedMeshes, meshes); | ||||||
| 		} | 		} | ||||||
| 	} |     } | ||||||
| } | } | ||||||
							
								
								
									
										33
									
								
								Runtime/Scripts/ModelBaker/MeshLodGenerator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Runtime/Scripts/ModelBaker/MeshLodGenerator.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | using UnityEngine; | ||||||
|  |  | ||||||
|  | namespace TAO.VertexAnimation | ||||||
|  | { | ||||||
|  | 	public static class MeshLodGenerator | ||||||
|  | 	{ | ||||||
|  | 		public static Mesh[] GenerateLOD(this Mesh mesh, int lods, float[] quality) | ||||||
|  | 		{ | ||||||
|  | 			Mesh[] lodMeshes = new Mesh[lods]; | ||||||
|  |  | ||||||
|  | 			for (int lm = 0; lm < lodMeshes.Length; lm++) | ||||||
|  | 			{ | ||||||
|  | 				lodMeshes[lm] = mesh.Copy(); | ||||||
|  | 				lodMeshes[lm] = lodMeshes[lm].Simplify(quality[lm]); | ||||||
|  | 				lodMeshes[lm].name = string.Format("{0}_LOD{1}", lodMeshes[lm].name, lm); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return lodMeshes; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		public static Mesh[] GenerateLOD(this Mesh mesh, int lods, AnimationCurve qualityCurve) | ||||||
|  | 		{ | ||||||
|  | 			float[] quality = new float[lods]; | ||||||
|  |  | ||||||
|  | 			for (int q = 0; q < quality.Length; q++) | ||||||
|  | 			{ | ||||||
|  | 				quality[q] = qualityCurve.Evaluate(1f / quality.Length * q); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return GenerateLOD(mesh, lods, quality); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								Runtime/Scripts/ModelBaker/MeshLodGenerator.cs.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Runtime/Scripts/ModelBaker/MeshLodGenerator.cs.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | fileFormatVersion: 2 | ||||||
|  | guid: c65b5fa78d8074a439c6ba86df4c4ffc | ||||||
|  | MonoImporter: | ||||||
|  |   externalObjects: {} | ||||||
|  |   serializedVersion: 2 | ||||||
|  |   defaultReferences: [] | ||||||
|  |   executionOrder: 0 | ||||||
|  |   icon: {instanceID: 0} | ||||||
|  |   userData:  | ||||||
|  |   assetBundleName:  | ||||||
|  |   assetBundleVariant:  | ||||||
							
								
								
									
										289
									
								
								Runtime/Scripts/ModelBaker/MeshSimplifier.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								Runtime/Scripts/ModelBaker/MeshSimplifier.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,289 @@ | |||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Linq; | ||||||
|  | using UnityEngine; | ||||||
|  |  | ||||||
|  | namespace TAO.VertexAnimation | ||||||
|  | { | ||||||
|  | 	public static class MeshSimplifier | ||||||
|  | 	{ | ||||||
|  | 		// Convert mesh into Triangles. | ||||||
|  | 		// Change triangles. | ||||||
|  | 		// Generate new mesh data based on Triangles. | ||||||
|  | 	 | ||||||
|  | 		// Everything is basically done through the triangle. | ||||||
|  | 		// When something changes in the triangle all correlated sub data changes as well (uv, normals, verts, etc). | ||||||
|  | 	 | ||||||
|  | 		public class Triangle | ||||||
|  | 		{ | ||||||
|  | 			// Vertices (Vector3) | ||||||
|  | 			// Normals (Vector3) | ||||||
|  | 			// UVs (UV0, UV1, ..., UV7) | ||||||
|  | 			// Other... | ||||||
|  | 	 | ||||||
|  | 			public List<Vector3> vertices = new List<Vector3>(3); | ||||||
|  | 			public List<Vector3> normals = new List<Vector3>(3); | ||||||
|  | 			public Dictionary<int, List<Vector2>> uvs = new Dictionary<int, List<Vector2>>(); | ||||||
|  | 	 | ||||||
|  | 			public float Perimeter() | ||||||
|  | 			{ | ||||||
|  | 				return Vector3.Distance(vertices[0], vertices[1]) + Vector3.Distance(vertices[1], vertices[2]) + Vector3.Distance(vertices[2], vertices[0]); | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			// If two or more points have the same values the triangle has no surface area and will be 'zero'. | ||||||
|  | 			public bool IsZero() | ||||||
|  | 			{ | ||||||
|  | 				if (vertices[0] == vertices[1] || vertices[0] == vertices[2] || vertices[1] == vertices[2]) | ||||||
|  | 				{ | ||||||
|  | 					return true; | ||||||
|  | 				} | ||||||
|  | 	 | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			// Returns the closest vertex index of a vertex within this triangle. | ||||||
|  | 			public int GetClosestVertexIndex(Vector3 vertex) | ||||||
|  | 			{ | ||||||
|  | 				float distance = Mathf.Infinity; | ||||||
|  | 				int closestVertex = -1; | ||||||
|  | 	 | ||||||
|  | 				for (int v = 0; v < vertices.Count; v++) | ||||||
|  | 				{ | ||||||
|  | 					if (vertices[v] != vertex) | ||||||
|  | 					{ | ||||||
|  | 						float dist = Vector3.Distance(vertices[v], vertex); | ||||||
|  | 	 | ||||||
|  | 						if (dist < distance) | ||||||
|  | 						{ | ||||||
|  | 							distance = dist; | ||||||
|  | 							closestVertex = v; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 	 | ||||||
|  | 				return closestVertex; | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			// Update triangle by copying data from a point in this triangle. | ||||||
|  | 			public bool UpdateVertex(int curVertexIndex, int newVertexIndex) | ||||||
|  | 			{ | ||||||
|  | 				vertices[curVertexIndex] = vertices[newVertexIndex]; | ||||||
|  | 				normals[curVertexIndex] = normals[newVertexIndex]; | ||||||
|  | 	 | ||||||
|  | 				foreach (var uv in uvs) | ||||||
|  | 				{ | ||||||
|  | 					uv.Value[curVertexIndex] = uv.Value[newVertexIndex]; | ||||||
|  | 				} | ||||||
|  | 	 | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			// Update triangle by copying data from an other triangle. | ||||||
|  | 			public bool UpdateVertex(Triangle sourceTriangle, int sourceVertexIndex, int newSourceVertexIndex) | ||||||
|  | 			{ | ||||||
|  | 				if (sourceTriangle != this) | ||||||
|  | 				{ | ||||||
|  | 					Vector3 sourceVertex = sourceTriangle.vertices[sourceVertexIndex]; | ||||||
|  | 					int index = vertices.IndexOf(sourceVertex); | ||||||
|  | 	 | ||||||
|  | 					if (index != -1) | ||||||
|  | 					{ | ||||||
|  | 						// Set all the new data. | ||||||
|  | 						vertices[index] = sourceTriangle.vertices[newSourceVertexIndex]; | ||||||
|  | 						normals[index] = sourceTriangle.normals[newSourceVertexIndex]; | ||||||
|  | 	 | ||||||
|  | 						foreach (var uv in uvs) | ||||||
|  | 						{ | ||||||
|  | 							uv.Value[index] = sourceTriangle.uvs[uv.Key][newSourceVertexIndex]; | ||||||
|  | 						} | ||||||
|  | 	 | ||||||
|  | 						return true; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 	 | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		public static Mesh Simplify(this Mesh mesh, float quality) | ||||||
|  | 		{ | ||||||
|  | 			string name = mesh.name; | ||||||
|  |  | ||||||
|  | 			List<Triangle> triangles = mesh.ToTriangles(); | ||||||
|  | 	 | ||||||
|  | 			int targetCount = Mathf.FloorToInt(triangles.Count * quality); | ||||||
|  | 			int loopCount = 0; | ||||||
|  |  | ||||||
|  | 			while (triangles.Count > targetCount) | ||||||
|  | 			{ | ||||||
|  | 				// Sort by perimeter. | ||||||
|  | 				// TODO: Better priority system. Maybe allow user to pass in method. | ||||||
|  | 				if (loopCount % triangles.Count == 0) | ||||||
|  | 				{ | ||||||
|  | 					triangles.SortByPerimeter(); | ||||||
|  | 				} | ||||||
|  | 	 | ||||||
|  | 				// Select tri/vert to simplify. | ||||||
|  | 				int curTriIndex = 0; | ||||||
|  | 				// TODO: Select vert by shortest total distance to the two other verts in the triangle. | ||||||
|  | 				int curVertIndex = 0; | ||||||
|  | 				Vector3 curVert = triangles[curTriIndex].vertices[curVertIndex]; | ||||||
|  | 	 | ||||||
|  | 				// Select closest vert within triangle to merge into. | ||||||
|  | 				int newVertIndex = triangles[curTriIndex].GetClosestVertexIndex(curVert); | ||||||
|  | 	 | ||||||
|  | 				// Update all triangles. | ||||||
|  | 				// TODO: Apply only to connected triangles. | ||||||
|  | 				for (int t = 0; t < triangles.Count; t++) | ||||||
|  | 				{ | ||||||
|  | 					triangles[t].UpdateVertex(triangles[curTriIndex], curVertIndex, newVertIndex); | ||||||
|  | 				} | ||||||
|  | 				triangles[curTriIndex].UpdateVertex(curVertIndex, newVertIndex); | ||||||
|  | 	 | ||||||
|  | 				// Remove all zero triangles. | ||||||
|  | 				triangles.RemoveAll(t => t.IsZero()); | ||||||
|  | 	 | ||||||
|  | 				loopCount++; | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			mesh.Clear(); | ||||||
|  | 			mesh = triangles.ToMesh(); | ||||||
|  | 			mesh.name = name; | ||||||
|  | 	 | ||||||
|  | 			return mesh; | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		public static List<Triangle> ToTriangles(this Mesh mesh) | ||||||
|  | 		{ | ||||||
|  | 			List<Triangle> triangles = new List<Triangle>(); | ||||||
|  | 	 | ||||||
|  | 			List<Vector3> verts = new List<Vector3>(mesh.vertices); | ||||||
|  | 			List<Vector3> normals = new List<Vector3>(mesh.normals); | ||||||
|  | 			List<int> tris = new List<int>(mesh.triangles); | ||||||
|  | 	 | ||||||
|  | 			Dictionary<int, List<Vector2>> uvs = new Dictionary<int, List<Vector2>>(); | ||||||
|  | 			for (int u = 0; u < 8; u++) | ||||||
|  | 			{ | ||||||
|  | 				List<Vector2> coordinates = new List<Vector2>(); | ||||||
|  | 				mesh.GetUVs(u, coordinates); | ||||||
|  | 	 | ||||||
|  | 				if (coordinates != null && coordinates.Any()) | ||||||
|  | 				{ | ||||||
|  | 					uvs.Add(u, coordinates); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			for (int t = 0; t < tris.Count; t += 3) | ||||||
|  | 			{ | ||||||
|  | 				Triangle tri = new Triangle(); | ||||||
|  | 	 | ||||||
|  | 				tri.vertices.Add(verts[tris[t + 0]]); | ||||||
|  | 				tri.vertices.Add(verts[tris[t + 1]]); | ||||||
|  | 				tri.vertices.Add(verts[tris[t + 2]]); | ||||||
|  | 	 | ||||||
|  | 				tri.normals.Add(normals[tris[t + 0]]); | ||||||
|  | 				tri.normals.Add(normals[tris[t + 1]]); | ||||||
|  | 				tri.normals.Add(normals[tris[t + 2]]); | ||||||
|  | 	 | ||||||
|  | 				foreach (var uv in uvs) | ||||||
|  | 				{ | ||||||
|  | 					if (tri.uvs.TryGetValue(uv.Key, out List<Vector2> coordinates)) | ||||||
|  | 					{ | ||||||
|  | 						coordinates.Add(uv.Value[tris[t + 0]]); | ||||||
|  | 						coordinates.Add(uv.Value[tris[t + 1]]); | ||||||
|  | 						coordinates.Add(uv.Value[tris[t + 2]]); | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 					{ | ||||||
|  | 						tri.uvs.Add(uv.Key, new List<Vector2> | ||||||
|  | 						{  | ||||||
|  | 							uv.Value[tris[t + 0]],  | ||||||
|  | 							uv.Value[tris[t + 1]],  | ||||||
|  | 							uv.Value[tris[t + 2]] | ||||||
|  | 						}); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 	 | ||||||
|  | 				triangles.Add(tri); | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			return triangles; | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		public static Mesh ToMesh(this List<Triangle> triangles) | ||||||
|  | 		{ | ||||||
|  | 			Mesh mesh = new Mesh(); | ||||||
|  | 			mesh.Clear(); | ||||||
|  | 	 | ||||||
|  | 			List<Vector3> vertices = new List<Vector3>(triangles.Count * 3); | ||||||
|  | 			List<int> tris = new List<int>(triangles.Count * 3); | ||||||
|  | 			List<Vector3> normals = new List<Vector3>(triangles.Count * 3); | ||||||
|  | 			Dictionary<int, List<Vector2>> uvs = new Dictionary<int, List<Vector2>>(); | ||||||
|  | 	 | ||||||
|  | 			int skipped = 0; | ||||||
|  | 			for (int t = 0; t < triangles.Count; t++) | ||||||
|  | 			{ | ||||||
|  | 				for (int v = 0; v < triangles[t].vertices.Count; v++) | ||||||
|  | 				{ | ||||||
|  | 					// Check for existing matching vert. | ||||||
|  | 					int vIndex = vertices.IndexOf(triangles[t].vertices[v]); | ||||||
|  | 					if (vIndex != -1) | ||||||
|  | 					{ | ||||||
|  | 						// Check for existing matching normal. | ||||||
|  | 						if (normals[vIndex] == triangles[t].normals[v]) | ||||||
|  | 						{ | ||||||
|  | 							// We have a duplicate. | ||||||
|  | 							// Don't add the data and instead point to existing. | ||||||
|  | 							tris.Add(vIndex); | ||||||
|  | 							skipped++; | ||||||
|  | 							continue; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 	 | ||||||
|  | 					// Add data when it doesn't exist. | ||||||
|  | 					vertices.Add(triangles[t].vertices[v]); | ||||||
|  | 					normals.Add(triangles[t].normals[v]); | ||||||
|  | 	 | ||||||
|  | 					foreach (var uv in triangles[t].uvs) | ||||||
|  | 					{ | ||||||
|  | 						if (uvs.TryGetValue(uv.Key, out List<Vector2> coordinates)) | ||||||
|  | 						{ | ||||||
|  | 							coordinates.Add(uv.Value[v]); | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							uvs.Add(uv.Key, new List<Vector2> | ||||||
|  | 							{ | ||||||
|  | 								uv.Value[v], | ||||||
|  | 							}); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 	 | ||||||
|  | 					tris.Add(t * 3 + v - skipped); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			mesh.vertices = vertices.ToArray(); | ||||||
|  | 			mesh.normals = normals.ToArray(); | ||||||
|  | 	 | ||||||
|  | 			foreach (var uv in uvs) | ||||||
|  | 			{ | ||||||
|  | 				mesh.SetUVs(uv.Key, uv.Value); | ||||||
|  | 			} | ||||||
|  | 	 | ||||||
|  | 			mesh.triangles = tris.ToArray(); | ||||||
|  | 	 | ||||||
|  | 			mesh.Optimize(); | ||||||
|  | 			mesh.RecalculateBounds(); | ||||||
|  | 			mesh.RecalculateTangents(); | ||||||
|  | 	 | ||||||
|  | 			return mesh; | ||||||
|  | 		} | ||||||
|  | 	 | ||||||
|  | 		public static List<Triangle> SortByPerimeter(this List<Triangle> triangles) | ||||||
|  | 		{ | ||||||
|  | 			triangles.Sort((x, y) => x.Perimeter().CompareTo(y.Perimeter())); | ||||||
|  | 	 | ||||||
|  | 			return triangles; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								Runtime/Scripts/ModelBaker/MeshSimplifier.cs.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Runtime/Scripts/ModelBaker/MeshSimplifier.cs.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | fileFormatVersion: 2 | ||||||
|  | guid: 9a779acf4568ca24484403e1eb61b7f3 | ||||||
|  | MonoImporter: | ||||||
|  |   externalObjects: {} | ||||||
|  |   serializedVersion: 2 | ||||||
|  |   defaultReferences: [] | ||||||
|  |   executionOrder: 0 | ||||||
|  |   icon: {instanceID: 0} | ||||||
|  |   userData:  | ||||||
|  |   assetBundleName:  | ||||||
|  |   assetBundleVariant:  | ||||||
							
								
								
									
										32
									
								
								Runtime/Scripts/ModelBaker/MeshUtils.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Runtime/Scripts/ModelBaker/MeshUtils.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | using UnityEngine; | ||||||
|  |  | ||||||
|  | namespace TAO.VertexAnimation | ||||||
|  | { | ||||||
|  | 	public static class MeshUtils | ||||||
|  | 	{ | ||||||
|  | 		public static Mesh Copy(this Mesh mesh) | ||||||
|  | 		{ | ||||||
|  | 			Mesh copy = new Mesh | ||||||
|  | 			{ | ||||||
|  | 				name = mesh.name, | ||||||
|  | 				vertices = mesh.vertices, | ||||||
|  | 				triangles = mesh.triangles, | ||||||
|  | 				normals = mesh.normals, | ||||||
|  | 				tangents = mesh.tangents, | ||||||
|  | 				colors = mesh.colors, | ||||||
|  | 				uv = mesh.uv, | ||||||
|  | 				uv2 = mesh.uv2, | ||||||
|  | 				uv3 = mesh.uv3, | ||||||
|  | 				uv4 = mesh.uv4, | ||||||
|  | 				uv5 = mesh.uv5, | ||||||
|  | 				uv6 = mesh.uv6, | ||||||
|  | 				uv7 = mesh.uv7, | ||||||
|  | 				uv8 = mesh.uv8, | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			copy.RecalculateBounds(); | ||||||
|  |  | ||||||
|  | 			return copy; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								Runtime/Scripts/ModelBaker/MeshUtils.cs.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Runtime/Scripts/ModelBaker/MeshUtils.cs.meta
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | fileFormatVersion: 2 | ||||||
|  | guid: af0818363d7ad6640b54b45d0b879c52 | ||||||
|  | MonoImporter: | ||||||
|  |   externalObjects: {} | ||||||
|  |   serializedVersion: 2 | ||||||
|  |   defaultReferences: [] | ||||||
|  |   executionOrder: 0 | ||||||
|  |   icon: {instanceID: 0} | ||||||
|  |   userData:  | ||||||
|  |   assetBundleName:  | ||||||
|  |   assetBundleVariant:  | ||||||
		Reference in New Issue
	
	Block a user