// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts, // for ex. property getter/setter access. To get optimal decompilation results, please manually add the missing references to the list of loaded assemblies. // EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // Eden.AutoMorpher.ClothInstance using System; using System.Collections.Generic; using Eden.AutoMorpher; using UnityEngine; [Serializable] public class ClothInstance { public SkinnedMeshRenderer smr; public Mesh editableMesh; public Mesh bakedMesh; public Matrix4x4 worldNoScale; public Vector3[] worldVertices; public Vector3[] minDistanceVector; public float[] minDistance; public Vector3[] deltas; public Vector3[] deltasLocal; public List[] vertexAdjacency; public List> equivalentVertices; public bool[] isInsideVertex; public bool[] excludedVertices; public bool[] isLeftLegVertex; public bool[] isRightLegVertex; public Vector3[] bakedWorldNormals; public Vector4[] bakedWorldTangents; public Dictionary> humanoidMatchedBones; public ClothInstance(SkinnedMeshRenderer clotheSMR, bool duplicateMesh = true) { smr = clotheSMR; if (duplicateMesh) { string name = smr.sharedMesh.name; editableMesh = UnityEngine.Object.Instantiate(clotheSMR.sharedMesh); editableMesh.name = name + "_EditableMesh"; smr.sharedMesh = editableMesh; } else { editableMesh = smr.sharedMesh; } UpdateWorldVertices(); int vertexCount = editableMesh.vertexCount; minDistanceVector = new Vector3[vertexCount]; deltas = new Vector3[vertexCount]; minDistance = new float[vertexCount]; isInsideVertex = new bool[vertexCount]; excludedVertices = new bool[vertexCount]; isLeftLegVertex = new bool[vertexCount]; isRightLegVertex = new bool[vertexCount]; humanoidMatchedBones = new Dictionary>(); vertexAdjacency = BuildVertexAdjacency(editableMesh); BuildEquivalentVerticesFromWorld(); } public void UpdateWorldVertices() { if (bakedMesh == null) { bakedMesh = new Mesh(); } else { bakedMesh.Clear(); } smr.BakeMesh(bakedMesh); int vertexCount = editableMesh.vertexCount; Vector3 lossyScale = smr.transform.lossyScale; Vector3 vector = new Vector3(1f / Mathf.Max(lossyScale.x, 1E-08f), 1f / Mathf.Max(lossyScale.y, 1E-08f), 1f / Mathf.Max(lossyScale.z, 1E-08f)); worldNoScale = smr.transform.localToWorldMatrix * Matrix4x4.Scale(vector); worldVertices = new Vector3[vertexCount]; deltasLocal = new Vector3[vertexCount]; for (int i = 0; i < vertexCount; i++) { worldVertices[i] = worldNoScale.MultiplyPoint3x4(bakedMesh.vertices[i]); deltasLocal[i] = Vector3.zero; } Vector3[] normals = bakedMesh.normals; Vector4[] tangents = bakedMesh.tangents; bakedWorldNormals = new Vector3[vertexCount]; if (tangents != null && tangents.Length == vertexCount) { bakedWorldTangents = new Vector4[vertexCount]; } else { bakedWorldTangents = null; } for (int j = 0; j < vertexCount; j++) { bakedWorldNormals[j] = smr.transform.TransformDirection(normals[j]).normalized; if (bakedWorldTangents != null) { Vector3 normalized = smr.transform.TransformDirection(new Vector3(tangents[j].x, tangents[j].y, tangents[j].z)).normalized; bakedWorldTangents[j] = new Vector4(normalized.x, normalized.y, normalized.z, tangents[j].w); } } } public List[] BuildVertexAdjacency(Mesh mesh, float seamThreshold = 0.0001f, float proximityThreshold = 0f) { if (mesh == null) { throw new AutoMorpherException("Mesh is Missing", "[VertexAdjacencyUtil] BuildVertexAdjacency\n - mesh is null"); } int vertexCount = mesh.vertexCount; int[] triangles = mesh.triangles; Vector3[] vertices = mesh.vertices; List[] array = new List[vertexCount]; for (int i = 0; i < vertexCount; i++) { array[i] = new List(); } int num = triangles.Length / 3; for (int j = 0; j < num; j++) { int num2 = triangles[j * 3]; int num3 = triangles[j * 3 + 1]; int num4 = triangles[j * 3 + 2]; AddNeighbor(array, num2, num3); AddNeighbor(array, num3, num2); AddNeighbor(array, num3, num4); AddNeighbor(array, num4, num3); AddNeighbor(array, num4, num2); AddNeighbor(array, num2, num4); } if (seamThreshold > 0f) { float num5 = seamThreshold * 2f; float num6 = seamThreshold * seamThreshold; Dictionary> dictionary = new Dictionary>(); for (int k = 0; k < vertexCount; k++) { Vector3 vector = vertices[k]; Vector3Int key = new Vector3Int(Mathf.FloorToInt(vector.x / num5), Mathf.FloorToInt(vector.y / num5), Mathf.FloorToInt(vector.z / num5)); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List()); } value.Add(k); } foreach (KeyValuePair> item in dictionary) { Vector3Int key2 = item.Key; List value2 = item.Value; for (int l = -1; l <= 1; l++) { for (int m = -1; m <= 1; m++) { for (int n = -1; n <= 1; n++) { if (l < 0 || (l == 0 && m < 0) || (l == 0 && m == 0 && n < 0)) { continue; } Vector3Int vector3Int = new Vector3Int(key2.x + l, key2.y + m, key2.z + n); if (!dictionary.TryGetValue(vector3Int, out var value3)) { continue; } if (vector3Int == key2) { for (int num7 = 0; num7 < value2.Count; num7++) { int num8 = value2[num7]; Vector3 vector2 = vertices[num8]; for (int num9 = num7 + 1; num9 < value2.Count; num9++) { int num10 = value2[num9]; if ((vertices[num10] - vector2).sqrMagnitude <= num6) { AddNeighbor(array, num8, num10); AddNeighbor(array, num10, num8); } } } continue; } for (int num11 = 0; num11 < value2.Count; num11++) { int num12 = value2[num11]; Vector3 vector3 = vertices[num12]; for (int num13 = 0; num13 < value3.Count; num13++) { int num14 = value3[num13]; if ((vertices[num14] - vector3).sqrMagnitude <= num6) { AddNeighbor(array, num12, num14); AddNeighbor(array, num14, num12); } } } } } } } } if (proximityThreshold > 0f) { float num15 = proximityThreshold * 2f; float num16 = proximityThreshold * proximityThreshold; Dictionary> dictionary2 = new Dictionary>(); for (int num17 = 0; num17 < vertexCount; num17++) { Vector3 vector4 = vertices[num17]; Vector3Int key3 = new Vector3Int(Mathf.FloorToInt(vector4.x / num15), Mathf.FloorToInt(vector4.y / num15), Mathf.FloorToInt(vector4.z / num15)); if (!dictionary2.TryGetValue(key3, out var value4)) { value4 = (dictionary2[key3] = new List()); } value4.Add(num17); } foreach (KeyValuePair> item2 in dictionary2) { Vector3Int key4 = item2.Key; List value5 = item2.Value; for (int num18 = -1; num18 <= 1; num18++) { for (int num19 = -1; num19 <= 1; num19++) { for (int num20 = -1; num20 <= 1; num20++) { if (num18 < 0 || (num18 == 0 && num19 < 0) || (num18 == 0 && num19 == 0 && num20 < 0)) { continue; } Vector3Int vector3Int2 = new Vector3Int(key4.x + num18, key4.y + num19, key4.z + num20); if (!dictionary2.TryGetValue(vector3Int2, out var value6)) { continue; } if (vector3Int2 == key4) { for (int num21 = 0; num21 < value5.Count; num21++) { int num22 = value5[num21]; Vector3 vector5 = vertices[num22]; for (int num23 = num21 + 1; num23 < value5.Count; num23++) { int num24 = value5[num23]; if ((vertices[num24] - vector5).sqrMagnitude <= num16) { AddNeighbor(array, num22, num24); AddNeighbor(array, num24, num22); } } } continue; } for (int num25 = 0; num25 < value5.Count; num25++) { int num26 = value5[num25]; Vector3 vector6 = vertices[num26]; for (int num27 = 0; num27 < value6.Count; num27++) { int num28 = value6[num27]; if ((vertices[num28] - vector6).sqrMagnitude <= num16) { AddNeighbor(array, num26, num28); AddNeighbor(array, num28, num26); } } } } } } } } return array; static void AddNeighbor(List[] adj, int from, int to) { List list3 = adj[from]; if (!list3.Contains(to)) { list3.Add(to); } } } public void ApplyWorldVerticesToMesh() { if (editableMesh == null || smr == null || worldVertices == null) { return; } Mesh mesh = editableMesh; int vertexCount = mesh.vertexCount; Vector3[] vertices = mesh.vertices; SkinningUtil skinningUtil = new SkinningUtil(); Vector3[] array = null; int blendShapeCount = mesh.blendShapeCount; if (blendShapeCount > 0) { array = new Vector3[vertexCount]; Vector3[] array2 = new Vector3[vertexCount]; Vector3[] deltaNormals = new Vector3[vertexCount]; Vector3[] deltaTangents = new Vector3[vertexCount]; for (int i = 0; i < blendShapeCount; i++) { float blendShapeWeight = smr.GetBlendShapeWeight(i); if (Mathf.Approximately(blendShapeWeight, 0f)) { continue; } int frameIndex = mesh.GetBlendShapeFrameCount(i) - 1; float blendShapeFrameWeight = mesh.GetBlendShapeFrameWeight(i, frameIndex); mesh.GetBlendShapeFrameVertices(i, frameIndex, array2, deltaNormals, deltaTangents); float num = ((blendShapeFrameWeight != 0f) ? (blendShapeWeight / blendShapeFrameWeight) : 0f); if (!Mathf.Approximately(num, 0f)) { for (int j = 0; j < vertexCount; j++) { array[j] += array2[j] * num; } } } } for (int k = 0; k < vertexCount; k++) { Vector3 vector = skinningUtil.WorldPosToBindPos_Full(smr, mesh, k, worldVertices[k]); if (array != null) { vector -= array[k]; } vertices[k] = vector; } mesh.vertices = vertices; Vector3[] array3 = null; Vector3[] array4 = null; if (blendShapeCount > 0) { array3 = new Vector3[vertexCount]; array4 = new Vector3[vertexCount]; Vector3[] deltaVertices = new Vector3[vertexCount]; Vector3[] array5 = new Vector3[vertexCount]; Vector3[] array6 = new Vector3[vertexCount]; for (int l = 0; l < blendShapeCount; l++) { float blendShapeWeight2 = smr.GetBlendShapeWeight(l); if (Mathf.Approximately(blendShapeWeight2, 0f)) { continue; } int frameIndex2 = mesh.GetBlendShapeFrameCount(l) - 1; float blendShapeFrameWeight2 = mesh.GetBlendShapeFrameWeight(l, frameIndex2); mesh.GetBlendShapeFrameVertices(l, frameIndex2, deltaVertices, array5, array6); float num2 = ((blendShapeFrameWeight2 != 0f) ? (blendShapeWeight2 / blendShapeFrameWeight2) : 0f); if (!Mathf.Approximately(num2, 0f)) { for (int m = 0; m < vertexCount; m++) { array3[m] += array5[m] * num2; array4[m] += array6[m] * num2; } } } } if (bakedWorldNormals == null || bakedWorldNormals.Length != vertexCount) { return; } Vector3[] array7 = new Vector3[vertexCount]; bool flag = bakedWorldTangents != null && bakedWorldTangents.Length == vertexCount; Vector4[] array8 = (flag ? new Vector4[vertexCount] : null); for (int n = 0; n < vertexCount; n++) { Vector3 vector2 = skinningUtil.WorldDirToBindDir_Full(smr, mesh, n, bakedWorldNormals[n]); if (array3 != null) { vector2 -= array3[n]; } array7[n] = vector2.normalized; if (flag) { Vector3 vector3 = skinningUtil.WorldDirToBindDir_Full(targetWorldDir: new Vector3(bakedWorldTangents[n].x, bakedWorldTangents[n].y, bakedWorldTangents[n].z), smr: smr, bindMesh: mesh, vertexIndex: n); if (array4 != null) { vector3 -= array4[n]; } vector3 = vector3.normalized; array8[n] = new Vector4(vector3.x, vector3.y, vector3.z, bakedWorldTangents[n].w); } } mesh.normals = array7; if (array8 != null) { mesh.tangents = array8; } } public void BuildEquivalentVerticesFromWorld(float maxDistance = 1E-05f) { if (worldVertices == null || worldVertices.Length == 0) { Debug.LogWarning("[ClothInstance] BuildEquivalentVerticesFromWorld: worldVertices is null or empty. Call UpdateWorldVertices() first."); return; } int num = worldVertices.Length; if (equivalentVertices == null) { equivalentVertices = new List>(); } else { equivalentVertices.Clear(); } float num2 = maxDistance * maxDistance; Dictionary> dictionary = new Dictionary>(); for (int i = 0; i < num; i++) { Vector3 vector = worldVertices[i]; Vector3Int key = new Vector3Int(Mathf.FloorToInt(vector.x / maxDistance), Mathf.FloorToInt(vector.y / maxDistance), Mathf.FloorToInt(vector.z / maxDistance)); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List()); } value.Add(i); } foreach (KeyValuePair> item in dictionary) { List value2 = item.Value; int count = value2.Count; if (count < 2) { continue; } int[] parent = new int[count]; for (int j = 0; j < count; j++) { parent[j] = j; } for (int k = 0; k < count; k++) { int num3 = value2[k]; Vector3 vector2 = worldVertices[num3]; for (int l = k + 1; l < count; l++) { int num4 = value2[l]; Vector3 vector3 = worldVertices[num4]; if ((vector2 - vector3).sqrMagnitude <= num2) { Union(k, l); } } } Dictionary> dictionary2 = new Dictionary>(); for (int m = 0; m < count; m++) { int key2 = Find(m); if (!dictionary2.TryGetValue(key2, out var value3)) { value3 = (dictionary2[key2] = new List()); } value3.Add(value2[m]); } foreach (List value4 in dictionary2.Values) { if (value4.Count >= 2) { equivalentVertices.Add(value4); } } int Find(int x) { if (parent[x] != x) { parent[x] = Find(parent[x]); } return parent[x]; } void Union(int a, int b) { int num5 = Find(a); int num6 = Find(b); if (num5 != num6) { parent[num6] = num5; } } } } ~ClothInstance() { Dispose(); } public void Dispose() { if (bakedMesh != null) { UnityEngine.Object.DestroyImmediate(bakedMesh); bakedMesh = null; } worldVertices = null; minDistanceVector = null; minDistance = null; deltas = null; deltasLocal = null; isInsideVertex = null; excludedVertices = null; isLeftLegVertex = null; isRightLegVertex = null; vertexAdjacency = null; if (equivalentVertices != null) { for (int i = 0; i < equivalentVertices.Count; i++) { equivalentVertices[i]?.Clear(); } equivalentVertices.Clear(); equivalentVertices = null; } humanoidMatchedBones = null; smr = null; editableMesh = null; } }