540 lines
15 KiB
C#
540 lines
15 KiB
C#
// 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<int>[] vertexAdjacency;
|
|
|
|
public List<List<int>> equivalentVertices;
|
|
|
|
public bool[] isInsideVertex;
|
|
|
|
public bool[] excludedVertices;
|
|
|
|
public bool[] isLeftLegVertex;
|
|
|
|
public bool[] isRightLegVertex;
|
|
|
|
public Vector3[] bakedWorldNormals;
|
|
|
|
public Vector4[] bakedWorldTangents;
|
|
|
|
public Dictionary<HumanBodyBones, HashSet<Transform>> 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<HumanBodyBones, HashSet<Transform>>();
|
|
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<int>[] 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<int>[] array = new List<int>[vertexCount];
|
|
for (int i = 0; i < vertexCount; i++)
|
|
{
|
|
array[i] = new List<int>();
|
|
}
|
|
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<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>();
|
|
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<int>());
|
|
}
|
|
value.Add(k);
|
|
}
|
|
foreach (KeyValuePair<Vector3Int, List<int>> item in dictionary)
|
|
{
|
|
Vector3Int key2 = item.Key;
|
|
List<int> 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<Vector3Int, List<int>> dictionary2 = new Dictionary<Vector3Int, List<int>>();
|
|
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<int>());
|
|
}
|
|
value4.Add(num17);
|
|
}
|
|
foreach (KeyValuePair<Vector3Int, List<int>> item2 in dictionary2)
|
|
{
|
|
Vector3Int key4 = item2.Key;
|
|
List<int> 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<int>[] adj, int from, int to)
|
|
{
|
|
List<int> 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<List<int>>();
|
|
}
|
|
else
|
|
{
|
|
equivalentVertices.Clear();
|
|
}
|
|
float num2 = maxDistance * maxDistance;
|
|
Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>();
|
|
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<int>());
|
|
}
|
|
value.Add(i);
|
|
}
|
|
foreach (KeyValuePair<Vector3Int, List<int>> item in dictionary)
|
|
{
|
|
List<int> 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<int, List<int>> dictionary2 = new Dictionary<int, List<int>>();
|
|
for (int m = 0; m < count; m++)
|
|
{
|
|
int key2 = Find(m);
|
|
if (!dictionary2.TryGetValue(key2, out var value3))
|
|
{
|
|
value3 = (dictionary2[key2] = new List<int>());
|
|
}
|
|
value3.Add(value2[m]);
|
|
}
|
|
foreach (List<int> 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;
|
|
}
|
|
}
|