포매팅
This commit is contained in:
@@ -1,58 +1,56 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.AutoMorpherDev
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public static class AutoMorpherDev
|
||||
{
|
||||
public readonly struct ScopeTimer : IDisposable
|
||||
{
|
||||
private readonly bool _enabled;
|
||||
public readonly struct ScopeTimer : IDisposable
|
||||
{
|
||||
private readonly bool _enabled;
|
||||
|
||||
private readonly string _label;
|
||||
private readonly string _label;
|
||||
|
||||
private readonly Stopwatch _sw;
|
||||
private readonly Stopwatch _sw;
|
||||
|
||||
public ScopeTimer(bool enabled, string label)
|
||||
{
|
||||
_enabled = enabled;
|
||||
_label = label;
|
||||
if (enabled)
|
||||
{
|
||||
_sw = Stopwatch.StartNew();
|
||||
}
|
||||
else
|
||||
{
|
||||
_sw = null;
|
||||
}
|
||||
}
|
||||
public ScopeTimer(bool enabled, string label)
|
||||
{
|
||||
this._enabled = enabled;
|
||||
this._label = label;
|
||||
if (enabled)
|
||||
{
|
||||
this._sw = Stopwatch.StartNew();
|
||||
}
|
||||
else
|
||||
{
|
||||
this._sw = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_enabled && _sw != null)
|
||||
{
|
||||
_sw.Stop();
|
||||
UnityEngine.Debug.Log($"[DevTimer] {_label}: {_sw.ElapsedMilliseconds} ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
if (this._enabled && this._sw != null)
|
||||
{
|
||||
this._sw.Stop();
|
||||
UnityEngine.Debug.Log($"[DevTimer] {this._label}: {this._sw.ElapsedMilliseconds} ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool isDeveloperMode;
|
||||
public static bool isDeveloperMode;
|
||||
|
||||
public static void Log(string message)
|
||||
{
|
||||
if (isDeveloperMode)
|
||||
{
|
||||
UnityEngine.Debug.Log(message);
|
||||
}
|
||||
}
|
||||
public static void Log(string message)
|
||||
{
|
||||
if (isDeveloperMode)
|
||||
{
|
||||
UnityEngine.Debug.Log(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static ScopeTimer Profile(string label)
|
||||
{
|
||||
return new ScopeTimer(isDeveloperMode, label);
|
||||
}
|
||||
public static ScopeTimer Profile(string label)
|
||||
{
|
||||
return new ScopeTimer(isDeveloperMode, label);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.AutoMorpherException
|
||||
@@ -6,11 +6,11 @@ using System;
|
||||
|
||||
public class AutoMorpherException : Exception
|
||||
{
|
||||
public string title;
|
||||
public string title;
|
||||
|
||||
public AutoMorpherException(string title, string message)
|
||||
: base(message)
|
||||
{
|
||||
this.title = title;
|
||||
}
|
||||
public AutoMorpherException(string title, string message)
|
||||
: base(message)
|
||||
{
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BakedBodyMesh
|
||||
@@ -6,25 +6,25 @@ using UnityEngine;
|
||||
|
||||
public class BakedBodyMesh
|
||||
{
|
||||
public SkinnedMeshRenderer smr;
|
||||
public SkinnedMeshRenderer smr;
|
||||
|
||||
public Mesh bakedMesh;
|
||||
public Mesh bakedMesh;
|
||||
|
||||
public BakedBodyMesh(SkinnedMeshRenderer _smr)
|
||||
{
|
||||
smr = _smr;
|
||||
bakedMesh = new Mesh();
|
||||
smr.BakeMesh(bakedMesh);
|
||||
}
|
||||
public BakedBodyMesh(SkinnedMeshRenderer _smr)
|
||||
{
|
||||
this.smr = _smr;
|
||||
this.bakedMesh = new Mesh();
|
||||
this.smr.BakeMesh(this.bakedMesh);
|
||||
}
|
||||
|
||||
public void ReBakeMesh()
|
||||
{
|
||||
smr.BakeMesh(bakedMesh);
|
||||
}
|
||||
public void ReBakeMesh()
|
||||
{
|
||||
this.smr.BakeMesh(this.bakedMesh);
|
||||
}
|
||||
|
||||
~BakedBodyMesh()
|
||||
{
|
||||
smr = null;
|
||||
bakedMesh = null;
|
||||
}
|
||||
~BakedBodyMesh()
|
||||
{
|
||||
this.smr = null;
|
||||
this.bakedMesh = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,196 +1,194 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BodyPoseMatchSetupUtil
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Eden.AutoMorpher;
|
||||
using Eden.AutoMorpher.profile;
|
||||
using UnityEngine;
|
||||
|
||||
public class BodyPoseMatchSetupUtil
|
||||
{
|
||||
public void AdjustAvatarScaleByNeck(Transform avatarRoot, Dictionary<HumanBodyBones, HashSet<Transform>> humanBoneMap, float targetHeight)
|
||||
{
|
||||
if (avatarRoot == null)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] NormalizeAvatarScaleByNeck: avatar == null");
|
||||
return;
|
||||
}
|
||||
Transform boneFromBoneMap = new BodyPoseMatch_CommonUtil().GetBoneFromBoneMap(humanBoneMap, HumanBodyBones.Neck);
|
||||
if (boneFromBoneMap == null)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] " + avatarRoot.name + " 에서 Neck 본을 찾지 못했습니다. 스케일 정규화를 건너뜁니다.");
|
||||
return;
|
||||
}
|
||||
Transform transform = avatarRoot.transform;
|
||||
float num = boneFromBoneMap.position.y - transform.position.y;
|
||||
if (Mathf.Approximately(num, 0f))
|
||||
{
|
||||
Debug.LogWarning($"[AvatarBodyMatchUtil] {avatarRoot.name} Neck Y가 0에 가까워 스케일 계산을 건너뜁니다. (neckY = {num})");
|
||||
return;
|
||||
}
|
||||
float num2 = targetHeight / num;
|
||||
Vector3 localScale = transform.localScale;
|
||||
localScale *= num2;
|
||||
transform.localScale = localScale;
|
||||
}
|
||||
public void AdjustAvatarScaleByNeck(Transform avatarRoot, Dictionary<HumanBodyBones, HashSet<Transform>> humanBoneMap, float targetHeight)
|
||||
{
|
||||
if (avatarRoot == null)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] NormalizeAvatarScaleByNeck: avatar == null");
|
||||
return;
|
||||
}
|
||||
Transform boneFromBoneMap = new BodyPoseMatch_CommonUtil().GetBoneFromBoneMap(humanBoneMap, HumanBodyBones.Neck);
|
||||
if (boneFromBoneMap == null)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] " + avatarRoot.name + " 에서 Neck 본을 찾지 못했습니다. 스케일 정규화를 건너뜁니다.");
|
||||
return;
|
||||
}
|
||||
Transform transform = avatarRoot.transform;
|
||||
float num = boneFromBoneMap.position.y - transform.position.y;
|
||||
if (Mathf.Approximately(num, 0f))
|
||||
{
|
||||
Debug.LogWarning($"[AvatarBodyMatchUtil] {avatarRoot.name} Neck Y가 0에 가까워 스케일 계산을 건너뜁니다. (neckY = {num})");
|
||||
return;
|
||||
}
|
||||
float num2 = targetHeight / num;
|
||||
Vector3 localScale = transform.localScale;
|
||||
localScale *= num2;
|
||||
transform.localScale = localScale;
|
||||
}
|
||||
|
||||
public GameObject CreateBodyProxy(Animator sourceAvatar, IReadOnlyList<SkinnedMeshRenderer> sourceBodyMeshes, out List<SkinnedMeshRenderer> proxyBodyMeshes, out Dictionary<Transform, Transform> sourceToProxy)
|
||||
{
|
||||
proxyBodyMeshes = null;
|
||||
if (sourceAvatar == null)
|
||||
{
|
||||
Debug.LogError("[AvatarBodyMatchUtil] CreateSourceBodyProxy: sourceAvatar == null");
|
||||
sourceToProxy = new Dictionary<Transform, Transform>();
|
||||
return null;
|
||||
}
|
||||
GameObject clone = Object.Instantiate(sourceAvatar.gameObject);
|
||||
clone.name = sourceAvatar.name + "_BodyProxy";
|
||||
HashSet<Transform> remainTransforms = new HashSet<Transform>();
|
||||
remainTransforms.Add(clone.transform);
|
||||
Animator component = clone.GetComponent<Animator>();
|
||||
if (component != null)
|
||||
{
|
||||
component.enabled = false;
|
||||
remainTransforms.Add(component.transform);
|
||||
}
|
||||
if (component != null && component.avatar != null && component.avatar.isHuman)
|
||||
{
|
||||
for (int i = 0; i < 55; i++)
|
||||
{
|
||||
HumanBodyBones humanBoneId = (HumanBodyBones)i;
|
||||
Transform boneTransform = component.GetBoneTransform(humanBoneId);
|
||||
if (boneTransform != null)
|
||||
{
|
||||
remainTransforms.Add(boneTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
HashSet<Mesh> hashSet = new HashSet<Mesh>();
|
||||
if (sourceBodyMeshes != null)
|
||||
{
|
||||
foreach (SkinnedMeshRenderer sourceBodyMesh in sourceBodyMeshes)
|
||||
{
|
||||
if (!(sourceBodyMesh == null) && !(sourceBodyMesh.sharedMesh == null))
|
||||
{
|
||||
hashSet.Add(sourceBodyMesh.sharedMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
SkinnedMeshRenderer[] componentsInChildren = clone.GetComponentsInChildren<SkinnedMeshRenderer>(includeInactive: true);
|
||||
List<SkinnedMeshRenderer> list = new List<SkinnedMeshRenderer>();
|
||||
SkinnedMeshRenderer[] array = componentsInChildren;
|
||||
foreach (SkinnedMeshRenderer skinnedMeshRenderer in array)
|
||||
{
|
||||
if (!(skinnedMeshRenderer == null))
|
||||
{
|
||||
Mesh sharedMesh = skinnedMeshRenderer.sharedMesh;
|
||||
if (!(sharedMesh == null) && hashSet.Contains(sharedMesh))
|
||||
{
|
||||
list.Add(skinnedMeshRenderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] CreateSourceBodyProxy: clone에서 동일 sharedMesh를 가진 BodyMesh를 찾지 못했습니다.");
|
||||
}
|
||||
if (list.Count > 0)
|
||||
{
|
||||
MeshClassifier meshClassifier = new MeshClassifier();
|
||||
foreach (SkinnedMeshRenderer item in list)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
remainTransforms.Add(item.transform);
|
||||
HashSet<Transform> activeBones = meshClassifier.GetActiveBones(item);
|
||||
if (activeBones == null)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] CreateSourceBodyProxy: clone smr '" + item.name + "' has null bones array (mesh='" + item.sharedMesh?.name + "')");
|
||||
continue;
|
||||
}
|
||||
foreach (Transform item2 in activeBones)
|
||||
{
|
||||
if (!(item2 == null))
|
||||
{
|
||||
remainTransforms.Add(item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Transform item3 in remainTransforms.ToList())
|
||||
{
|
||||
AddWithParents(item3);
|
||||
}
|
||||
Transform[] componentsInChildren2 = clone.GetComponentsInChildren<Transform>(includeInactive: true);
|
||||
for (int num = componentsInChildren2.Length - 1; num >= 0; num--)
|
||||
{
|
||||
Transform transform = componentsInChildren2[num];
|
||||
if (!(transform == null) && !(transform == clone.transform) && !remainTransforms.Contains(transform))
|
||||
{
|
||||
Object.DestroyImmediate(transform.gameObject);
|
||||
}
|
||||
}
|
||||
proxyBodyMeshes = list;
|
||||
new BoneMatchUtil().BuildSourceToProxyBoneMap(sourceAvatar, component, out sourceToProxy);
|
||||
return clone;
|
||||
void AddWithParents(Transform t)
|
||||
{
|
||||
while (t != null && t != clone.transform)
|
||||
{
|
||||
remainTransforms.Add(t);
|
||||
t = t.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
public GameObject CreateBodyProxy(Animator sourceAvatar, IReadOnlyList<SkinnedMeshRenderer> sourceBodyMeshes, out List<SkinnedMeshRenderer> proxyBodyMeshes, out Dictionary<Transform, Transform> sourceToProxy)
|
||||
{
|
||||
proxyBodyMeshes = null;
|
||||
if (sourceAvatar == null)
|
||||
{
|
||||
Debug.LogError("[AvatarBodyMatchUtil] CreateSourceBodyProxy: sourceAvatar == null");
|
||||
sourceToProxy = new Dictionary<Transform, Transform>();
|
||||
return null;
|
||||
}
|
||||
GameObject clone = Object.Instantiate(sourceAvatar.gameObject);
|
||||
clone.name = sourceAvatar.name + "_BodyProxy";
|
||||
HashSet<Transform> remainTransforms = new HashSet<Transform>();
|
||||
remainTransforms.Add(clone.transform);
|
||||
Animator component = clone.GetComponent<Animator>();
|
||||
if (component != null)
|
||||
{
|
||||
component.enabled = false;
|
||||
remainTransforms.Add(component.transform);
|
||||
}
|
||||
if (component != null && component.avatar != null && component.avatar.isHuman)
|
||||
{
|
||||
for (int i = 0; i < 55; i++)
|
||||
{
|
||||
HumanBodyBones humanBoneId = (HumanBodyBones)i;
|
||||
Transform boneTransform = component.GetBoneTransform(humanBoneId);
|
||||
if (boneTransform != null)
|
||||
{
|
||||
remainTransforms.Add(boneTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
HashSet<Mesh> hashSet = new HashSet<Mesh>();
|
||||
if (sourceBodyMeshes != null)
|
||||
{
|
||||
foreach (SkinnedMeshRenderer sourceBodyMesh in sourceBodyMeshes)
|
||||
{
|
||||
if (!(sourceBodyMesh == null) && !(sourceBodyMesh.sharedMesh == null))
|
||||
{
|
||||
hashSet.Add(sourceBodyMesh.sharedMesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
SkinnedMeshRenderer[] componentsInChildren = clone.GetComponentsInChildren<SkinnedMeshRenderer>(includeInactive: true);
|
||||
List<SkinnedMeshRenderer> list = new List<SkinnedMeshRenderer>();
|
||||
SkinnedMeshRenderer[] array = componentsInChildren;
|
||||
foreach (SkinnedMeshRenderer skinnedMeshRenderer in array)
|
||||
{
|
||||
if (!(skinnedMeshRenderer == null))
|
||||
{
|
||||
Mesh sharedMesh = skinnedMeshRenderer.sharedMesh;
|
||||
if (!(sharedMesh == null) && hashSet.Contains(sharedMesh))
|
||||
{
|
||||
list.Add(skinnedMeshRenderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] CreateSourceBodyProxy: clone에서 동일 sharedMesh를 가진 BodyMesh를 찾지 못했습니다.");
|
||||
}
|
||||
if (list.Count > 0)
|
||||
{
|
||||
MeshClassifier meshClassifier = new MeshClassifier();
|
||||
foreach (SkinnedMeshRenderer item in list)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
remainTransforms.Add(item.transform);
|
||||
HashSet<Transform> activeBones = meshClassifier.GetActiveBones(item);
|
||||
if (activeBones == null)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] CreateSourceBodyProxy: clone smr '" + item.name + "' has null bones array (mesh='" + item.sharedMesh?.name + "')");
|
||||
continue;
|
||||
}
|
||||
foreach (Transform item2 in activeBones)
|
||||
{
|
||||
if (!(item2 == null))
|
||||
{
|
||||
remainTransforms.Add(item2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Transform item3 in remainTransforms.ToList())
|
||||
{
|
||||
AddWithParents(item3);
|
||||
}
|
||||
Transform[] componentsInChildren2 = clone.GetComponentsInChildren<Transform>(includeInactive: true);
|
||||
for (int num = componentsInChildren2.Length - 1; num >= 0; num--)
|
||||
{
|
||||
Transform transform = componentsInChildren2[num];
|
||||
if (!(transform == null) && !(transform == clone.transform) && !remainTransforms.Contains(transform))
|
||||
{
|
||||
Object.DestroyImmediate(transform.gameObject);
|
||||
}
|
||||
}
|
||||
proxyBodyMeshes = list;
|
||||
new BoneMatchUtil().BuildSourceToProxyBoneMap(sourceAvatar, component, out sourceToProxy);
|
||||
return clone;
|
||||
void AddWithParents(Transform t)
|
||||
{
|
||||
while (t != null && t != clone.transform)
|
||||
{
|
||||
remainTransforms.Add(t);
|
||||
t = t.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetComprehensiveScale(Transform rootT, Dictionary<HumanBodyBones, HashSet<Transform>> clothHumanoidBoneMap, ProfileData profileData)
|
||||
{
|
||||
if (rootT == null)
|
||||
{
|
||||
throw new AutoMorpherException("Root Transform is Missing", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - rootT is null");
|
||||
}
|
||||
if (profileData.bones == null || profileData.bones.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Bones are Missing", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - profileData.bones is null or empty");
|
||||
}
|
||||
Transform transform = null;
|
||||
if (clothHumanoidBoneMap.TryGetValue(HumanBodyBones.Hips, out var value) && value != null && value.Count > 0)
|
||||
{
|
||||
foreach (Transform item in value)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
transform = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (transform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Hip Transform is Missing", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - failed to get [hip] transform from clothHumanoidBoneMap");
|
||||
}
|
||||
BoneData boneData = null;
|
||||
for (int i = 0; i < profileData.bones.Count; i++)
|
||||
{
|
||||
BoneData boneData2 = profileData.bones[i];
|
||||
if (boneData2 != null && boneData2.hBone == HumanBodyBones.Hips)
|
||||
{
|
||||
boneData = boneData2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (boneData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Hip Bone Data is Missing in Profile", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - profileData bones does not contain Hips");
|
||||
}
|
||||
Vector3 rootLocalScale = boneData.rootLocalScale;
|
||||
Vector3 lossyScale = rootT.lossyScale;
|
||||
Vector3 lossyScale2 = transform.lossyScale;
|
||||
Vector3 vector = new Vector3(lossyScale2.x / lossyScale.x, lossyScale2.y / lossyScale.y, lossyScale2.z / lossyScale.z);
|
||||
return new Vector3(vector.x / rootLocalScale.x, vector.y / rootLocalScale.y, vector.z / rootLocalScale.z);
|
||||
}
|
||||
public Vector3 GetComprehensiveScale(Transform rootT, Dictionary<HumanBodyBones, HashSet<Transform>> clothHumanoidBoneMap, ProfileData profileData)
|
||||
{
|
||||
if (rootT == null)
|
||||
{
|
||||
throw new AutoMorpherException("Root Transform is Missing", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - rootT is null");
|
||||
}
|
||||
if (profileData.bones == null || profileData.bones.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Bones are Missing", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - profileData.bones is null or empty");
|
||||
}
|
||||
Transform transform = null;
|
||||
if (clothHumanoidBoneMap.TryGetValue(HumanBodyBones.Hips, out var value) && value != null && value.Count > 0)
|
||||
{
|
||||
foreach (Transform item in value)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
transform = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (transform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Hip Transform is Missing", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - failed to get [hip] transform from clothHumanoidBoneMap");
|
||||
}
|
||||
BoneData boneData = null;
|
||||
for (int i = 0; i < profileData.bones.Count; i++)
|
||||
{
|
||||
BoneData boneData2 = profileData.bones[i];
|
||||
if (boneData2 != null && boneData2.hBone == HumanBodyBones.Hips)
|
||||
{
|
||||
boneData = boneData2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (boneData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Hip Bone Data is Missing in Profile", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - profileData bones does not contain Hips");
|
||||
}
|
||||
Vector3 rootLocalScale = boneData.rootLocalScale;
|
||||
Vector3 lossyScale = rootT.lossyScale;
|
||||
Vector3 lossyScale2 = transform.lossyScale;
|
||||
Vector3 vector = new Vector3(lossyScale2.x / lossyScale.x, lossyScale2.y / lossyScale.y, lossyScale2.z / lossyScale.z);
|
||||
return new Vector3(vector.x / rootLocalScale.x, vector.y / rootLocalScale.y, vector.z / rootLocalScale.z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,115 +1,114 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BodyPoseMatchUtil
|
||||
using System.Collections.Generic;
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public class BodyPoseMatchUtil
|
||||
{
|
||||
private WorldVertexUtil _worldVertexUtil;
|
||||
private WorldVertexUtil _worldVertexUtil;
|
||||
|
||||
private MeshClassifier meshClassifier;
|
||||
private MeshClassifier meshClassifier;
|
||||
|
||||
private BodyPoseMatch_CommonUtil poseMatchCommonUtil;
|
||||
private BodyPoseMatch_CommonUtil poseMatchCommonUtil;
|
||||
|
||||
private bool doDebug;
|
||||
private bool doDebug;
|
||||
|
||||
public BodyPoseMatchUtil()
|
||||
{
|
||||
_worldVertexUtil = new WorldVertexUtil();
|
||||
meshClassifier = new MeshClassifier();
|
||||
poseMatchCommonUtil = new BodyPoseMatch_CommonUtil();
|
||||
}
|
||||
public BodyPoseMatchUtil()
|
||||
{
|
||||
this._worldVertexUtil = new WorldVertexUtil();
|
||||
this.meshClassifier = new MeshClassifier();
|
||||
this.poseMatchCommonUtil = new BodyPoseMatch_CommonUtil();
|
||||
}
|
||||
|
||||
public GameObject AutoAdjustBodyPose(GameObject sourceAvatar, IReadOnlyList<SkinnedMeshRenderer> sourceBodyMeshes, GameObject targetAvatar, IReadOnlyList<SkinnedMeshRenderer> targetBodyMeshes, out Dictionary<Transform, Transform> sourceToProxy, float neckTargetHeight = 1.5f, bool onlyScaling = false)
|
||||
{
|
||||
Animator component = sourceAvatar.GetComponent<Animator>();
|
||||
Animator component2 = targetAvatar.GetComponent<Animator>();
|
||||
if (component == null || component2 == null)
|
||||
{
|
||||
Debug.LogError("[AvatarBodyMatchUtil] sourceAvatar 또는 targetAvatar가 null입니다.");
|
||||
sourceToProxy = new Dictionary<Transform, Transform>();
|
||||
return null;
|
||||
}
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanBoneMap = meshClassifier.MeshHumanoidBoneMatcher(component, sourceBodyMeshes);
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary = meshClassifier.MeshHumanoidBoneMatcher(component2, targetBodyMeshes);
|
||||
BodyPoseMatchSetupUtil bodyPoseMatchSetupUtil = new BodyPoseMatchSetupUtil();
|
||||
bodyPoseMatchSetupUtil.AdjustAvatarScaleByNeck(sourceAvatar.transform, humanBoneMap, neckTargetHeight);
|
||||
bodyPoseMatchSetupUtil.AdjustAvatarScaleByNeck(targetAvatar.transform, dictionary, neckTargetHeight);
|
||||
List<SkinnedMeshRenderer> proxyBodyMeshes;
|
||||
GameObject gameObject = bodyPoseMatchSetupUtil.CreateBodyProxy(component, sourceBodyMeshes, out proxyBodyMeshes, out sourceToProxy);
|
||||
Animator component3 = gameObject.GetComponent<Animator>();
|
||||
if (onlyScaling)
|
||||
{
|
||||
gameObject.transform.SetParent(targetAvatar.transform);
|
||||
gameObject.transform.localPosition = Vector3.zero;
|
||||
return gameObject;
|
||||
}
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary2 = meshClassifier.MeshHumanoidBoneMatcher(component3, proxyBodyMeshes);
|
||||
if (dictionary2 == null || dictionary2.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Proxy Bone Map is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - proxyBoneMap is null");
|
||||
}
|
||||
gameObject.transform.SetParent(targetAvatar.transform);
|
||||
gameObject.transform.localPosition = Vector3.zero;
|
||||
List<BakedBodyMesh> list = new List<BakedBodyMesh>();
|
||||
foreach (SkinnedMeshRenderer item in proxyBodyMeshes)
|
||||
{
|
||||
list.Add(new BakedBodyMesh(item));
|
||||
}
|
||||
List<BakedBodyMesh> list2 = new List<BakedBodyMesh>();
|
||||
foreach (SkinnedMeshRenderer targetBodyMesh in targetBodyMeshes)
|
||||
{
|
||||
list2.Add(new BakedBodyMesh(targetBodyMesh));
|
||||
}
|
||||
BodyPoseMatch_Torso bodyPoseMatch_Torso = new BodyPoseMatch_Torso();
|
||||
bodyPoseMatch_Torso.AlignTorsoByNeck(gameObject, list, dictionary2, targetAvatar, list2, dictionary);
|
||||
if (doDebug)
|
||||
{
|
||||
bodyPoseMatch_Torso.DrawTorsoPcaDebug(gameObject, list, dictionary2, Color.yellow, Color.cyan, 1f, 20f);
|
||||
bodyPoseMatch_Torso.DrawTorsoPcaDebug(targetAvatar, list2, dictionary, Color.red, Color.green, 1f, 20f);
|
||||
}
|
||||
foreach (BakedBodyMesh item2 in list)
|
||||
{
|
||||
item2.ReBakeMesh();
|
||||
}
|
||||
BodyPoseMatch_Arm bodyPoseMatch_Arm = new BodyPoseMatch_Arm();
|
||||
bodyPoseMatch_Arm.AlignUpperArmByArmPcaCenters(list, dictionary2, list2, dictionary);
|
||||
if (doDebug)
|
||||
{
|
||||
bodyPoseMatch_Arm.DrawArmPcaDebug(gameObject, list, dictionary2, isLeft: true, Color.yellow, Color.cyan, 1f, 20f);
|
||||
bodyPoseMatch_Arm.DrawArmPcaDebug(targetAvatar, list2, dictionary, isLeft: true, Color.red, Color.green, 1f, 20f);
|
||||
}
|
||||
foreach (BakedBodyMesh item3 in list)
|
||||
{
|
||||
item3.ReBakeMesh();
|
||||
}
|
||||
bodyPoseMatch_Arm.ScalingBothArmsLength(list, dictionary2, list2, dictionary);
|
||||
foreach (BakedBodyMesh item4 in list)
|
||||
{
|
||||
item4.ReBakeMesh();
|
||||
}
|
||||
BodyPoseMatch_Leg bodyPoseMatch_Leg = new BodyPoseMatch_Leg();
|
||||
bodyPoseMatch_Leg.AlignBothUpperLegs(gameObject, list, dictionary2, targetAvatar, list2, dictionary);
|
||||
foreach (BakedBodyMesh item5 in list)
|
||||
{
|
||||
item5.ReBakeMesh();
|
||||
}
|
||||
bodyPoseMatch_Leg.ScalingBothLegsAndFoots(gameObject, list, dictionary2, targetAvatar, list2, dictionary);
|
||||
if (doDebug)
|
||||
{
|
||||
foreach (BakedBodyMesh item6 in list)
|
||||
{
|
||||
item6.ReBakeMesh();
|
||||
}
|
||||
bodyPoseMatch_Leg.DrawLegPcaDebug(gameObject, list, dictionary2, isLeft: true, Color.yellow, Color.cyan, 1f, 5f);
|
||||
bodyPoseMatch_Leg.DrawLegPcaDebug(gameObject, list, dictionary2, isLeft: false, Color.yellow, Color.cyan, 1f, 5f);
|
||||
bodyPoseMatch_Leg.DrawLegPcaDebug(targetAvatar, list2, dictionary, isLeft: true, Color.magenta, Color.green, 1f, 5f);
|
||||
bodyPoseMatch_Leg.DrawLegPcaDebug(targetAvatar, list2, dictionary, isLeft: false, Color.magenta, Color.green, 1f, 5f);
|
||||
bodyPoseMatch_Arm.DrawForearmExtremeDebugPair(gameObject.gameObject, proxyBodyMeshes, targetAvatar, targetBodyMeshes, isLeft: true, 1f, 5f);
|
||||
}
|
||||
return gameObject;
|
||||
}
|
||||
public GameObject AutoAdjustBodyPose(GameObject sourceAvatar, IReadOnlyList<SkinnedMeshRenderer> sourceBodyMeshes, GameObject targetAvatar, IReadOnlyList<SkinnedMeshRenderer> targetBodyMeshes, out Dictionary<Transform, Transform> sourceToProxy, float neckTargetHeight = 1.5f, bool onlyScaling = false)
|
||||
{
|
||||
Animator component = sourceAvatar.GetComponent<Animator>();
|
||||
Animator component2 = targetAvatar.GetComponent<Animator>();
|
||||
if (component == null || component2 == null)
|
||||
{
|
||||
Debug.LogError("[AvatarBodyMatchUtil] sourceAvatar 또는 targetAvatar가 null입니다.");
|
||||
sourceToProxy = new Dictionary<Transform, Transform>();
|
||||
return null;
|
||||
}
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanBoneMap = this.meshClassifier.MeshHumanoidBoneMatcher(component, sourceBodyMeshes);
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary = this.meshClassifier.MeshHumanoidBoneMatcher(component2, targetBodyMeshes);
|
||||
BodyPoseMatchSetupUtil bodyPoseMatchSetupUtil = new BodyPoseMatchSetupUtil();
|
||||
bodyPoseMatchSetupUtil.AdjustAvatarScaleByNeck(sourceAvatar.transform, humanBoneMap, neckTargetHeight);
|
||||
bodyPoseMatchSetupUtil.AdjustAvatarScaleByNeck(targetAvatar.transform, dictionary, neckTargetHeight);
|
||||
List<SkinnedMeshRenderer> proxyBodyMeshes;
|
||||
GameObject gameObject = bodyPoseMatchSetupUtil.CreateBodyProxy(component, sourceBodyMeshes, out proxyBodyMeshes, out sourceToProxy);
|
||||
Animator component3 = gameObject.GetComponent<Animator>();
|
||||
if (onlyScaling)
|
||||
{
|
||||
gameObject.transform.SetParent(targetAvatar.transform);
|
||||
gameObject.transform.localPosition = Vector3.zero;
|
||||
return gameObject;
|
||||
}
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary2 = this.meshClassifier.MeshHumanoidBoneMatcher(component3, proxyBodyMeshes);
|
||||
if (dictionary2 == null || dictionary2.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Proxy Bone Map is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - proxyBoneMap is null");
|
||||
}
|
||||
gameObject.transform.SetParent(targetAvatar.transform);
|
||||
gameObject.transform.localPosition = Vector3.zero;
|
||||
List<BakedBodyMesh> list = new List<BakedBodyMesh>();
|
||||
foreach (SkinnedMeshRenderer item in proxyBodyMeshes)
|
||||
{
|
||||
list.Add(new BakedBodyMesh(item));
|
||||
}
|
||||
List<BakedBodyMesh> list2 = new List<BakedBodyMesh>();
|
||||
foreach (SkinnedMeshRenderer targetBodyMesh in targetBodyMeshes)
|
||||
{
|
||||
list2.Add(new BakedBodyMesh(targetBodyMesh));
|
||||
}
|
||||
BodyPoseMatch_Torso bodyPoseMatch_Torso = new BodyPoseMatch_Torso();
|
||||
bodyPoseMatch_Torso.AlignTorsoByNeck(gameObject, list, dictionary2, targetAvatar, list2, dictionary);
|
||||
if (this.doDebug)
|
||||
{
|
||||
bodyPoseMatch_Torso.DrawTorsoPcaDebug(gameObject, list, dictionary2, Color.yellow, Color.cyan, 1f, 20f);
|
||||
bodyPoseMatch_Torso.DrawTorsoPcaDebug(targetAvatar, list2, dictionary, Color.red, Color.green, 1f, 20f);
|
||||
}
|
||||
foreach (BakedBodyMesh item2 in list)
|
||||
{
|
||||
item2.ReBakeMesh();
|
||||
}
|
||||
BodyPoseMatch_Arm bodyPoseMatch_Arm = new BodyPoseMatch_Arm();
|
||||
bodyPoseMatch_Arm.AlignUpperArmByArmPcaCenters(list, dictionary2, list2, dictionary);
|
||||
if (this.doDebug)
|
||||
{
|
||||
bodyPoseMatch_Arm.DrawArmPcaDebug(gameObject, list, dictionary2, isLeft: true, Color.yellow, Color.cyan, 1f, 20f);
|
||||
bodyPoseMatch_Arm.DrawArmPcaDebug(targetAvatar, list2, dictionary, isLeft: true, Color.red, Color.green, 1f, 20f);
|
||||
}
|
||||
foreach (BakedBodyMesh item3 in list)
|
||||
{
|
||||
item3.ReBakeMesh();
|
||||
}
|
||||
bodyPoseMatch_Arm.ScalingBothArmsLength(list, dictionary2, list2, dictionary);
|
||||
foreach (BakedBodyMesh item4 in list)
|
||||
{
|
||||
item4.ReBakeMesh();
|
||||
}
|
||||
BodyPoseMatch_Leg bodyPoseMatch_Leg = new BodyPoseMatch_Leg();
|
||||
bodyPoseMatch_Leg.AlignBothUpperLegs(gameObject, list, dictionary2, targetAvatar, list2, dictionary);
|
||||
foreach (BakedBodyMesh item5 in list)
|
||||
{
|
||||
item5.ReBakeMesh();
|
||||
}
|
||||
bodyPoseMatch_Leg.ScalingBothLegsAndFoots(gameObject, list, dictionary2, targetAvatar, list2, dictionary);
|
||||
if (this.doDebug)
|
||||
{
|
||||
foreach (BakedBodyMesh item6 in list)
|
||||
{
|
||||
item6.ReBakeMesh();
|
||||
}
|
||||
bodyPoseMatch_Leg.DrawLegPcaDebug(gameObject, list, dictionary2, isLeft: true, Color.yellow, Color.cyan, 1f, 5f);
|
||||
bodyPoseMatch_Leg.DrawLegPcaDebug(gameObject, list, dictionary2, isLeft: false, Color.yellow, Color.cyan, 1f, 5f);
|
||||
bodyPoseMatch_Leg.DrawLegPcaDebug(targetAvatar, list2, dictionary, isLeft: true, Color.magenta, Color.green, 1f, 5f);
|
||||
bodyPoseMatch_Leg.DrawLegPcaDebug(targetAvatar, list2, dictionary, isLeft: false, Color.magenta, Color.green, 1f, 5f);
|
||||
bodyPoseMatch_Arm.DrawForearmExtremeDebugPair(gameObject.gameObject, proxyBodyMeshes, targetAvatar, targetBodyMeshes, isLeft: true, 1f, 5f);
|
||||
}
|
||||
return gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,248 +1,246 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BodyPoseMatch_CommonUtil
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Eden.AutoMorpher;
|
||||
using Eden.AutoMorpher.profile;
|
||||
using UnityEngine;
|
||||
|
||||
public class BodyPoseMatch_CommonUtil
|
||||
{
|
||||
public Transform GetBoneFromBoneMap(Dictionary<HumanBodyBones, HashSet<Transform>> boneMap, HumanBodyBones bone)
|
||||
{
|
||||
if (boneMap == null || !boneMap.TryGetValue(bone, out var value) || value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return value.FirstOrDefault();
|
||||
}
|
||||
public Transform GetBoneFromBoneMap(Dictionary<HumanBodyBones, HashSet<Transform>> boneMap, HumanBodyBones bone)
|
||||
{
|
||||
if (boneMap == null || !boneMap.TryGetValue(bone, out var value) || value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return value.FirstOrDefault();
|
||||
}
|
||||
|
||||
public Vector3 GetProfilePcaCenterWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData boneSpatialData, Vector3 comprehensiveScale, string errorContext = "")
|
||||
{
|
||||
if (clothBoneMap == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Bone Map is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - clothBoneMap is null (context=" + errorContext + ")");
|
||||
}
|
||||
if (boneSpatialData == null || boneSpatialData.pcaData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Bone Spatial Data is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - boneSpatialData or boneSpatialData.pcaData is null (context=" + errorContext + ")");
|
||||
}
|
||||
Transform boneFromBoneMap = GetBoneFromBoneMap(clothBoneMap, boneSpatialData.refBone);
|
||||
if (boneFromBoneMap == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Ref Bone Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld" + $"\n - refBone transform is null (refBone={boneSpatialData.refBone}, context={errorContext})");
|
||||
}
|
||||
if (GetBoneFromBoneMap(clothBoneMap, HumanBodyBones.Hips) == null)
|
||||
{
|
||||
throw new AutoMorpherException("Hip Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - hip transform is null (context=" + errorContext + ")");
|
||||
}
|
||||
Vector3 pcaCenter = boneSpatialData.pcaData.pcaCenter;
|
||||
Vector3 position = new Vector3(pcaCenter.x / comprehensiveScale.x, pcaCenter.y / comprehensiveScale.y, pcaCenter.z / comprehensiveScale.z);
|
||||
return boneFromBoneMap.TransformPoint(position);
|
||||
}
|
||||
public Vector3 GetProfilePcaCenterWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData boneSpatialData, Vector3 comprehensiveScale, string errorContext = "")
|
||||
{
|
||||
if (clothBoneMap == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Bone Map is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - clothBoneMap is null (context=" + errorContext + ")");
|
||||
}
|
||||
if (boneSpatialData == null || boneSpatialData.pcaData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Bone Spatial Data is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - boneSpatialData or boneSpatialData.pcaData is null (context=" + errorContext + ")");
|
||||
}
|
||||
Transform boneFromBoneMap = this.GetBoneFromBoneMap(clothBoneMap, boneSpatialData.refBone);
|
||||
if (boneFromBoneMap == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Ref Bone Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld" + $"\n - refBone transform is null (refBone={boneSpatialData.refBone}, context={errorContext})");
|
||||
}
|
||||
if (this.GetBoneFromBoneMap(clothBoneMap, HumanBodyBones.Hips) == null)
|
||||
{
|
||||
throw new AutoMorpherException("Hip Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - hip transform is null (context=" + errorContext + ")");
|
||||
}
|
||||
Vector3 pcaCenter = boneSpatialData.pcaData.pcaCenter;
|
||||
Vector3 position = new Vector3(pcaCenter.x / comprehensiveScale.x, pcaCenter.y / comprehensiveScale.y, pcaCenter.z / comprehensiveScale.z);
|
||||
return boneFromBoneMap.TransformPoint(position);
|
||||
}
|
||||
|
||||
public Vector3 GetProfileVolumeMinWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData spatialData, int axis, Vector3 comprehensiveScale)
|
||||
{
|
||||
return GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, isMin: true);
|
||||
}
|
||||
public Vector3 GetProfileVolumeMinWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData spatialData, int axis, Vector3 comprehensiveScale)
|
||||
{
|
||||
return this.GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, isMin: true);
|
||||
}
|
||||
|
||||
public Vector3 GetProfileVolumeMaxWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData spatialData, int axis, Vector3 comprehensiveScale)
|
||||
{
|
||||
return GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, isMin: false);
|
||||
}
|
||||
public Vector3 GetProfileVolumeMaxWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData spatialData, int axis, Vector3 comprehensiveScale)
|
||||
{
|
||||
return this.GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, isMin: false);
|
||||
}
|
||||
|
||||
public Vector3 GetProfileVolumeWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData spatialData, int axisIndex, Vector3 comprehensiveScale, bool isMin)
|
||||
{
|
||||
if (clothBoneMap == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Bone Map is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld\n - clothBoneMap is null");
|
||||
}
|
||||
if (spatialData == null || spatialData.volumeData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Volume Data is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld\n - spatialData or spatialData.volumeData is null");
|
||||
}
|
||||
Transform boneFromBoneMap = GetBoneFromBoneMap(clothBoneMap, spatialData.refBone);
|
||||
if (boneFromBoneMap == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Ref Bone Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld" + $"\n - refBone transform is null (refBone={spatialData.refBone})");
|
||||
}
|
||||
Vector3 vector = axisIndex switch
|
||||
{
|
||||
0 => isMin ? spatialData.volumeData.fMinLocalPos : spatialData.volumeData.fMaxLocalPos,
|
||||
1 => isMin ? spatialData.volumeData.rMinLocalPos : spatialData.volumeData.rMaxLocalPos,
|
||||
2 => isMin ? spatialData.volumeData.uMinLocalPos : spatialData.volumeData.uMaxLocalPos,
|
||||
_ => throw new AutoMorpherException("Unsupported Volume Axis Index", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld" + $"\n - axisIndex must be 0(Forward), 1(Right), 2(Up) (axisIndex={axisIndex})"),
|
||||
};
|
||||
Vector3 position = new Vector3(vector.x / comprehensiveScale.x, vector.y / comprehensiveScale.y, vector.z / comprehensiveScale.z);
|
||||
return boneFromBoneMap.TransformPoint(position);
|
||||
}
|
||||
public Vector3 GetProfileVolumeWorld(Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, BoneSpatialData spatialData, int axisIndex, Vector3 comprehensiveScale, bool isMin)
|
||||
{
|
||||
if (clothBoneMap == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Bone Map is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld\n - clothBoneMap is null");
|
||||
}
|
||||
if (spatialData == null || spatialData.volumeData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Volume Data is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld\n - spatialData or spatialData.volumeData is null");
|
||||
}
|
||||
Transform boneFromBoneMap = this.GetBoneFromBoneMap(clothBoneMap, spatialData.refBone);
|
||||
if (boneFromBoneMap == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Ref Bone Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld" + $"\n - refBone transform is null (refBone={spatialData.refBone})");
|
||||
}
|
||||
Vector3 vector = axisIndex switch
|
||||
{
|
||||
0 => isMin ? spatialData.volumeData.fMinLocalPos : spatialData.volumeData.fMaxLocalPos,
|
||||
1 => isMin ? spatialData.volumeData.rMinLocalPos : spatialData.volumeData.rMaxLocalPos,
|
||||
2 => isMin ? spatialData.volumeData.uMinLocalPos : spatialData.volumeData.uMaxLocalPos,
|
||||
_ => throw new AutoMorpherException("Unsupported Volume Axis Index", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld" + $"\n - axisIndex must be 0(Forward), 1(Right), 2(Up) (axisIndex={axisIndex})"),
|
||||
};
|
||||
Vector3 position = new Vector3(vector.x / comprehensiveScale.x, vector.y / comprehensiveScale.y, vector.z / comprehensiveScale.z);
|
||||
return boneFromBoneMap.TransformPoint(position);
|
||||
}
|
||||
|
||||
public List<Vector3> CollectWeightedVerticesWorld(IReadOnlyList<BakedBodyMesh> bakedBodyMeshes, HashSet<Transform> targetBoneSet, float weightThreshold = 0.15f, int sampleStep = 1)
|
||||
{
|
||||
List<Vector3> list = new List<Vector3>();
|
||||
if (bakedBodyMeshes == null || targetBoneSet == null || targetBoneSet.Count == 0)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshes)
|
||||
{
|
||||
if (bakedBodyMesh == null || bakedBodyMesh.smr == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Mesh sharedMesh = bakedBodyMesh.smr.sharedMesh;
|
||||
if (sharedMesh == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
BoneWeight[] boneWeights = sharedMesh.boneWeights;
|
||||
Transform[] bones = bakedBodyMesh.smr.bones;
|
||||
if (boneWeights == null || boneWeights.Length == 0 || bones == null || bones.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Vector3[] worldVerticesWithBakedMesh = new WorldVertexUtil().GetWorldVerticesWithBakedMesh(bakedBodyMesh.smr, bakedBodyMesh.bakedMesh);
|
||||
if (worldVerticesWithBakedMesh == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int num = Mathf.Min(worldVerticesWithBakedMesh.Length, boneWeights.Length);
|
||||
for (int i = 0; i < num; i += sampleStep)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[i];
|
||||
float wSum = 0f;
|
||||
Acc(boneWeight.boneIndex0, boneWeight.weight0);
|
||||
Acc(boneWeight.boneIndex1, boneWeight.weight1);
|
||||
Acc(boneWeight.boneIndex2, boneWeight.weight2);
|
||||
Acc(boneWeight.boneIndex3, boneWeight.weight3);
|
||||
if (!(wSum < weightThreshold))
|
||||
{
|
||||
list.Add(worldVerticesWithBakedMesh[i]);
|
||||
}
|
||||
void Acc(int index, float w)
|
||||
{
|
||||
if (index >= 0 && index < bones.Length && !(w <= 0f))
|
||||
{
|
||||
Transform transform = bones[index];
|
||||
if (transform != null && targetBoneSet.Contains(transform))
|
||||
{
|
||||
wSum += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
public List<Vector3> CollectWeightedVerticesWorld(IReadOnlyList<BakedBodyMesh> bakedBodyMeshes, HashSet<Transform> targetBoneSet, float weightThreshold = 0.15f, int sampleStep = 1)
|
||||
{
|
||||
List<Vector3> list = new List<Vector3>();
|
||||
if (bakedBodyMeshes == null || targetBoneSet == null || targetBoneSet.Count == 0)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshes)
|
||||
{
|
||||
if (bakedBodyMesh == null || bakedBodyMesh.smr == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Mesh sharedMesh = bakedBodyMesh.smr.sharedMesh;
|
||||
if (sharedMesh == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
BoneWeight[] boneWeights = sharedMesh.boneWeights;
|
||||
Transform[] bones = bakedBodyMesh.smr.bones;
|
||||
if (boneWeights == null || boneWeights.Length == 0 || bones == null || bones.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Vector3[] worldVerticesWithBakedMesh = new WorldVertexUtil().GetWorldVerticesWithBakedMesh(bakedBodyMesh.smr, bakedBodyMesh.bakedMesh);
|
||||
if (worldVerticesWithBakedMesh == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int num = Mathf.Min(worldVerticesWithBakedMesh.Length, boneWeights.Length);
|
||||
for (int i = 0; i < num; i += sampleStep)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[i];
|
||||
float wSum = 0f;
|
||||
Acc(boneWeight.boneIndex0, boneWeight.weight0);
|
||||
Acc(boneWeight.boneIndex1, boneWeight.weight1);
|
||||
Acc(boneWeight.boneIndex2, boneWeight.weight2);
|
||||
Acc(boneWeight.boneIndex3, boneWeight.weight3);
|
||||
if (!(wSum < weightThreshold))
|
||||
{
|
||||
list.Add(worldVerticesWithBakedMesh[i]);
|
||||
}
|
||||
void Acc(int index, float w)
|
||||
{
|
||||
if (index >= 0 && index < bones.Length && !(w <= 0f))
|
||||
{
|
||||
Transform transform = bones[index];
|
||||
if (transform != null && targetBoneSet.Contains(transform))
|
||||
{
|
||||
wSum += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<Vector3> CollectHumanoidVerticesWorld(IReadOnlyList<HumanBodyBones> targetHumanBones, IReadOnlyList<BakedBodyMesh> bakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> boneMap, float weightThreshold = 0.15f, int sampleStep = 1)
|
||||
{
|
||||
List<Vector3> result = new List<Vector3>();
|
||||
if (bakedBodyMeshes == null || boneMap == null || boneMap.Count == 0 || targetHumanBones == null)
|
||||
{
|
||||
throw new AutoMorpherException("Invalid Arguments for CollectHumanoidVerticesWorld", "[BodyPoseMatchCommonUtil] CollectHumanoidVerticesWorld\n - bakedBodyMeshes is null OR boneMap is null/empty OR targetHumanBones is null");
|
||||
}
|
||||
HashSet<Transform> hashSet = new HashSet<Transform>();
|
||||
foreach (HumanBodyBones targetHumanBone in targetHumanBones)
|
||||
{
|
||||
if (!boneMap.TryGetValue(targetHumanBone, out var value) || value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (Transform item in value)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
hashSet.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hashSet.Count == 0)
|
||||
{
|
||||
Debug.Log("[AvatarBodyMatchUtil] CollectBodyPartVerticesWorld: targetBoneSet is empty.");
|
||||
return result;
|
||||
}
|
||||
return CollectWeightedVerticesWorld(bakedBodyMeshes, hashSet, weightThreshold, sampleStep);
|
||||
}
|
||||
public List<Vector3> CollectHumanoidVerticesWorld(IReadOnlyList<HumanBodyBones> targetHumanBones, IReadOnlyList<BakedBodyMesh> bakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> boneMap, float weightThreshold = 0.15f, int sampleStep = 1)
|
||||
{
|
||||
List<Vector3> result = new List<Vector3>();
|
||||
if (bakedBodyMeshes == null || boneMap == null || boneMap.Count == 0 || targetHumanBones == null)
|
||||
{
|
||||
throw new AutoMorpherException("Invalid Arguments for CollectHumanoidVerticesWorld", "[BodyPoseMatchCommonUtil] CollectHumanoidVerticesWorld\n - bakedBodyMeshes is null OR boneMap is null/empty OR targetHumanBones is null");
|
||||
}
|
||||
HashSet<Transform> hashSet = new HashSet<Transform>();
|
||||
foreach (HumanBodyBones targetHumanBone in targetHumanBones)
|
||||
{
|
||||
if (!boneMap.TryGetValue(targetHumanBone, out var value) || value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
foreach (Transform item in value)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
hashSet.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hashSet.Count == 0)
|
||||
{
|
||||
Debug.Log("[AvatarBodyMatchUtil] CollectBodyPartVerticesWorld: targetBoneSet is empty.");
|
||||
return result;
|
||||
}
|
||||
return this.CollectWeightedVerticesWorld(bakedBodyMeshes, hashSet, weightThreshold, sampleStep);
|
||||
}
|
||||
|
||||
public void BoneLengthAdjust(Transform proxyParent, Transform proxyChild, Transform targetParent, Transform targetChild, HashSet<Transform> proxyParentSet, bool autoDetectAxis = true, int forceAxisIndex = 1)
|
||||
{
|
||||
if (proxyParent == null || proxyChild == null || targetParent == null || targetChild == null)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] MatchBoneSegmentLength: bone null");
|
||||
return;
|
||||
}
|
||||
float num = Vector3.Distance(proxyParent.position, proxyChild.position);
|
||||
float num2 = Vector3.Distance(targetParent.position, targetChild.position);
|
||||
if (num < 1E-06f || num2 < 1E-06f)
|
||||
{
|
||||
Debug.LogWarning($"[AvatarBodyMatchUtil] MatchBoneSegmentLength: too small length. proxy={num}, target={num2}");
|
||||
return;
|
||||
}
|
||||
float num3 = num2 / num;
|
||||
int num7;
|
||||
if (autoDetectAxis)
|
||||
{
|
||||
Vector3 direction = proxyChild.position - proxyParent.position;
|
||||
Vector3 vector = proxyParent.InverseTransformDirection(direction);
|
||||
float num4 = Mathf.Abs(vector.x);
|
||||
float num5 = Mathf.Abs(vector.y);
|
||||
float num6 = Mathf.Abs(vector.z);
|
||||
num7 = ((num5 >= num4 && num5 >= num6) ? 1 : ((!(num4 >= num6)) ? 2 : 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
num7 = Mathf.Clamp(forceAxisIndex, 0, 2);
|
||||
}
|
||||
Vector3 localScale = proxyParent.localScale;
|
||||
switch (num7)
|
||||
{
|
||||
case 0:
|
||||
localScale.x *= num3;
|
||||
break;
|
||||
case 1:
|
||||
localScale.y *= num3;
|
||||
break;
|
||||
case 2:
|
||||
localScale.z *= num3;
|
||||
break;
|
||||
}
|
||||
foreach (Transform item in proxyParentSet)
|
||||
{
|
||||
item.localScale = localScale;
|
||||
}
|
||||
}
|
||||
public void BoneLengthAdjust(Transform proxyParent, Transform proxyChild, Transform targetParent, Transform targetChild, HashSet<Transform> proxyParentSet, bool autoDetectAxis = true, int forceAxisIndex = 1)
|
||||
{
|
||||
if (proxyParent == null || proxyChild == null || targetParent == null || targetChild == null)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] MatchBoneSegmentLength: bone null");
|
||||
return;
|
||||
}
|
||||
float num = Vector3.Distance(proxyParent.position, proxyChild.position);
|
||||
float num2 = Vector3.Distance(targetParent.position, targetChild.position);
|
||||
if (num < 1E-06f || num2 < 1E-06f)
|
||||
{
|
||||
Debug.LogWarning($"[AvatarBodyMatchUtil] MatchBoneSegmentLength: too small length. proxy={num}, target={num2}");
|
||||
return;
|
||||
}
|
||||
float num3 = num2 / num;
|
||||
int num7;
|
||||
if (autoDetectAxis)
|
||||
{
|
||||
Vector3 direction = proxyChild.position - proxyParent.position;
|
||||
Vector3 vector = proxyParent.InverseTransformDirection(direction);
|
||||
float num4 = Mathf.Abs(vector.x);
|
||||
float num5 = Mathf.Abs(vector.y);
|
||||
float num6 = Mathf.Abs(vector.z);
|
||||
num7 = ((num5 >= num4 && num5 >= num6) ? 1 : ((!(num4 >= num6)) ? 2 : 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
num7 = Mathf.Clamp(forceAxisIndex, 0, 2);
|
||||
}
|
||||
Vector3 localScale = proxyParent.localScale;
|
||||
switch (num7)
|
||||
{
|
||||
case 0:
|
||||
localScale.x *= num3;
|
||||
break;
|
||||
case 1:
|
||||
localScale.y *= num3;
|
||||
break;
|
||||
case 2:
|
||||
localScale.z *= num3;
|
||||
break;
|
||||
}
|
||||
foreach (Transform item in proxyParentSet)
|
||||
{
|
||||
item.localScale = localScale;
|
||||
}
|
||||
}
|
||||
|
||||
public Transform CreateTempMarker(string markerObjectName, Transform parentTransform, IReadOnlyList<Transform> childTransforms, Vector3 markerWorldPosition, Quaternion markerWorldRotation, Vector3 markerLocalScale, out TempBoneMarker tempBoneMarker)
|
||||
{
|
||||
if (parentTransform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Marker Parent Transform is Missing", "[BodyPoseMatch_CommonUtil] CreateTempMarker\n - parentTransform is null");
|
||||
}
|
||||
if (childTransforms == null || childTransforms.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Child Transforms are Missing", "[BodyPoseMatch_CommonUtil] CreateTempMarker\n - childTransforms is null or empty");
|
||||
}
|
||||
Transform transform = new GameObject(string.IsNullOrEmpty(markerObjectName) ? "scaleSupportBone" : markerObjectName).transform;
|
||||
transform.SetParent(parentTransform, worldPositionStays: true);
|
||||
transform.position = markerWorldPosition;
|
||||
transform.rotation = markerWorldRotation;
|
||||
transform.localScale = markerLocalScale;
|
||||
tempBoneMarker = transform.gameObject.AddComponent<TempBoneMarker>();
|
||||
tempBoneMarker.originalParent = parentTransform;
|
||||
tempBoneMarker.additionalInfo = "";
|
||||
tempBoneMarker.wrappedChildNames = new List<string>();
|
||||
for (int i = 0; i < childTransforms.Count; i++)
|
||||
{
|
||||
Transform transform2 = childTransforms[i];
|
||||
if (!(transform2 == null))
|
||||
{
|
||||
tempBoneMarker.wrappedChildNames.Add(transform2.name);
|
||||
transform2.SetParent(transform, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
public Transform CreateTempMarker(string markerObjectName, Transform parentTransform, IReadOnlyList<Transform> childTransforms, Vector3 markerWorldPosition, Quaternion markerWorldRotation, Vector3 markerLocalScale, out TempBoneMarker tempBoneMarker)
|
||||
{
|
||||
if (parentTransform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Marker Parent Transform is Missing", "[BodyPoseMatch_CommonUtil] CreateTempMarker\n - parentTransform is null");
|
||||
}
|
||||
if (childTransforms == null || childTransforms.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Child Transforms are Missing", "[BodyPoseMatch_CommonUtil] CreateTempMarker\n - childTransforms is null or empty");
|
||||
}
|
||||
Transform transform = new GameObject(string.IsNullOrEmpty(markerObjectName) ? "scaleSupportBone" : markerObjectName).transform;
|
||||
transform.SetParent(parentTransform, worldPositionStays: true);
|
||||
transform.position = markerWorldPosition;
|
||||
transform.rotation = markerWorldRotation;
|
||||
transform.localScale = markerLocalScale;
|
||||
tempBoneMarker = transform.gameObject.AddComponent<TempBoneMarker>();
|
||||
tempBoneMarker.originalParent = parentTransform;
|
||||
tempBoneMarker.additionalInfo = "";
|
||||
tempBoneMarker.wrappedChildNames = new List<string>();
|
||||
for (int i = 0; i < childTransforms.Count; i++)
|
||||
{
|
||||
Transform transform2 = childTransforms[i];
|
||||
if (!(transform2 == null))
|
||||
{
|
||||
tempBoneMarker.wrappedChildNames.Add(transform2.name);
|
||||
transform2.SetParent(transform, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,145 +1,143 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BodyPoseMatch_Torso
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Eden.AutoMorpher;
|
||||
using Eden.AutoMorpher.profile;
|
||||
using UnityEngine;
|
||||
|
||||
public class BodyPoseMatch_Torso
|
||||
{
|
||||
private readonly BodyPoseMatch_CommonUtil poseMatchCommonUtil;
|
||||
private readonly BodyPoseMatch_CommonUtil poseMatchCommonUtil;
|
||||
|
||||
public BodyPoseMatch_Torso()
|
||||
{
|
||||
poseMatchCommonUtil = new BodyPoseMatch_CommonUtil();
|
||||
}
|
||||
public BodyPoseMatch_Torso()
|
||||
{
|
||||
this.poseMatchCommonUtil = new BodyPoseMatch_CommonUtil();
|
||||
}
|
||||
|
||||
public void AlignTorsoByNeck(IReadOnlyCollection<Transform> sourceHipSet, Vector3 sourceNeckCenterWorld, Vector3 targetNeckCenterWorld)
|
||||
{
|
||||
if (sourceHipSet == null || sourceHipSet.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Source Hip Set is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - sourceHipSet is null or empty");
|
||||
}
|
||||
Transform transform = sourceHipSet.FirstOrDefault((Transform t) => t != null);
|
||||
if (transform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Source Hip Transform is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - sourceHipSet has no valid Transform");
|
||||
}
|
||||
Vector3 lhs = targetNeckCenterWorld - sourceNeckCenterWorld;
|
||||
Vector3 forward = transform.forward;
|
||||
float num = Vector3.Dot(lhs, forward);
|
||||
Vector3 vector = forward * num;
|
||||
foreach (Transform item in sourceHipSet)
|
||||
{
|
||||
if (!(item == null))
|
||||
{
|
||||
item.position += vector;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void AlignTorsoByNeck(IReadOnlyCollection<Transform> sourceHipSet, Vector3 sourceNeckCenterWorld, Vector3 targetNeckCenterWorld)
|
||||
{
|
||||
if (sourceHipSet == null || sourceHipSet.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Source Hip Set is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - sourceHipSet is null or empty");
|
||||
}
|
||||
Transform transform = sourceHipSet.FirstOrDefault((Transform t) => t != null);
|
||||
if (transform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Source Hip Transform is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - sourceHipSet has no valid Transform");
|
||||
}
|
||||
Vector3 lhs = targetNeckCenterWorld - sourceNeckCenterWorld;
|
||||
Vector3 forward = transform.forward;
|
||||
float num = Vector3.Dot(lhs, forward);
|
||||
Vector3 vector = forward * num;
|
||||
foreach (Transform item in sourceHipSet)
|
||||
{
|
||||
if (!(item == null))
|
||||
{
|
||||
item.position += vector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AlignTorsoByNeck(GameObject proxyObject, IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap, GameObject targetObject, IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap)
|
||||
{
|
||||
if (proxyObject == null || targetObject == null)
|
||||
{
|
||||
throw new AutoMorpherException("Proxy/Target Object is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - proxyObject or targetObject is null");
|
||||
}
|
||||
RegionStats regionStats = ComputeNeckRegionStats(proxyObject.transform, proxyBakedBodyMeshes, proxyBoneMap);
|
||||
RegionStats regionStats2 = ComputeNeckRegionStats(targetObject.transform, targetBakedBodyMeshes, targetBoneMap);
|
||||
if (regionStats.length < 0.0001f || regionStats2.length < 0.0001f)
|
||||
{
|
||||
Debug.LogWarning("[BodyPoseMatch_Torso] AlignTorsoByNeck: Neck PCA 통계가 비정상입니다.");
|
||||
return;
|
||||
}
|
||||
if (proxyBoneMap == null || !proxyBoneMap.TryGetValue(HumanBodyBones.Hips, out var value) || value == null || value.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Proxy Hip Set is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - proxyBoneMap has no Hips bone set");
|
||||
}
|
||||
AlignTorsoByNeck(value, regionStats.center, regionStats2.center);
|
||||
}
|
||||
public void AlignTorsoByNeck(GameObject proxyObject, IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap, GameObject targetObject, IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap)
|
||||
{
|
||||
if (proxyObject == null || targetObject == null)
|
||||
{
|
||||
throw new AutoMorpherException("Proxy/Target Object is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - proxyObject or targetObject is null");
|
||||
}
|
||||
RegionStats regionStats = this.ComputeNeckRegionStats(proxyObject.transform, proxyBakedBodyMeshes, proxyBoneMap);
|
||||
RegionStats regionStats2 = this.ComputeNeckRegionStats(targetObject.transform, targetBakedBodyMeshes, targetBoneMap);
|
||||
if (regionStats.length < 0.0001f || regionStats2.length < 0.0001f)
|
||||
{
|
||||
Debug.LogWarning("[BodyPoseMatch_Torso] AlignTorsoByNeck: Neck PCA 통계가 비정상입니다.");
|
||||
return;
|
||||
}
|
||||
if (proxyBoneMap == null || !proxyBoneMap.TryGetValue(HumanBodyBones.Hips, out var value) || value == null || value.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Proxy Hip Set is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - proxyBoneMap has no Hips bone set");
|
||||
}
|
||||
this.AlignTorsoByNeck(value, regionStats.center, regionStats2.center);
|
||||
}
|
||||
|
||||
public void AlignTorsoByNeck(Transform targetTransform, IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap, Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, Transform clothesTransform, ProfileData profileData, Vector3 comprehensiveScale)
|
||||
{
|
||||
if (targetTransform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Target Transform is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - targetTransform is null");
|
||||
}
|
||||
if (profileData == null || profileData.NeckSpatialData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Neck Data is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - profileData or profileData.NeckSpatialData is null");
|
||||
}
|
||||
RegionStats regionStats = ComputeNeckRegionStats(targetTransform, targetBakedBodyMeshes, targetBoneMap);
|
||||
if (regionStats.length < 0.0001f)
|
||||
{
|
||||
Debug.LogWarning("[BodyPoseMatch_Torso] AlignTorsoByNeck: Neck PCA 통계가 비정상입니다.");
|
||||
return;
|
||||
}
|
||||
if (clothBoneMap == null || !clothBoneMap.TryGetValue(HumanBodyBones.Hips, out var value) || value == null || value.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Hip Set is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - clothBoneMap has no Hips bone set");
|
||||
}
|
||||
Vector3 profilePcaCenterWorld = poseMatchCommonUtil.GetProfilePcaCenterWorld(clothBoneMap, profileData.NeckSpatialData, comprehensiveScale);
|
||||
AlignTorsoByNeck(value, profilePcaCenterWorld, regionStats.center);
|
||||
}
|
||||
public void AlignTorsoByNeck(Transform targetTransform, IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap, Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap, Transform clothesTransform, ProfileData profileData, Vector3 comprehensiveScale)
|
||||
{
|
||||
if (targetTransform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Target Transform is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - targetTransform is null");
|
||||
}
|
||||
if (profileData == null || profileData.NeckSpatialData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Neck Data is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - profileData or profileData.NeckSpatialData is null");
|
||||
}
|
||||
RegionStats regionStats = this.ComputeNeckRegionStats(targetTransform, targetBakedBodyMeshes, targetBoneMap);
|
||||
if (regionStats.length < 0.0001f)
|
||||
{
|
||||
Debug.LogWarning("[BodyPoseMatch_Torso] AlignTorsoByNeck: Neck PCA 통계가 비정상입니다.");
|
||||
return;
|
||||
}
|
||||
if (clothBoneMap == null || !clothBoneMap.TryGetValue(HumanBodyBones.Hips, out var value) || value == null || value.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Hip Set is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - clothBoneMap has no Hips bone set");
|
||||
}
|
||||
Vector3 profilePcaCenterWorld = this.poseMatchCommonUtil.GetProfilePcaCenterWorld(clothBoneMap, profileData.NeckSpatialData, comprehensiveScale);
|
||||
this.AlignTorsoByNeck(value, profilePcaCenterWorld, regionStats.center);
|
||||
}
|
||||
|
||||
public RegionStats ComputeNeckRegionStats(Transform avatarTransform, IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap)
|
||||
{
|
||||
HumanBodyBones[] targetHumanBones = new HumanBodyBones[1] { HumanBodyBones.Neck };
|
||||
List<Vector3> list = poseMatchCommonUtil.CollectHumanoidVerticesWorld(targetHumanBones, avatarBakedBodyMeshes, avatarBoneMap);
|
||||
if (list == null || list.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] ComputeNeckRegionStats: neck vertices 0개. avatar=" + avatarTransform?.name);
|
||||
return default(RegionStats);
|
||||
}
|
||||
RegionStats result = new PcaUtil().ComputeRegionStats(list);
|
||||
Vector3 vector = avatarTransform.up;
|
||||
Transform boneFromBoneMap = poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, HumanBodyBones.Head);
|
||||
Transform boneFromBoneMap2 = poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, HumanBodyBones.UpperChest);
|
||||
Transform boneFromBoneMap3 = poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, HumanBodyBones.Chest);
|
||||
Transform boneFromBoneMap4 = poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, HumanBodyBones.Hips);
|
||||
Transform transform = ((boneFromBoneMap2 != null) ? boneFromBoneMap2 : boneFromBoneMap3);
|
||||
if (boneFromBoneMap != null && transform != null)
|
||||
{
|
||||
vector = boneFromBoneMap.position - transform.position;
|
||||
}
|
||||
else if (boneFromBoneMap != null && boneFromBoneMap4 != null)
|
||||
{
|
||||
vector = boneFromBoneMap.position - boneFromBoneMap4.position;
|
||||
}
|
||||
if (vector.sqrMagnitude > 1E-08f)
|
||||
{
|
||||
vector.Normalize();
|
||||
}
|
||||
if (Vector3.Dot(vector, avatarTransform.transform.up) < 0f)
|
||||
{
|
||||
vector = -vector;
|
||||
}
|
||||
result.principalAxis = vector;
|
||||
return result;
|
||||
}
|
||||
public RegionStats ComputeNeckRegionStats(Transform avatarTransform, IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap)
|
||||
{
|
||||
HumanBodyBones[] targetHumanBones = new HumanBodyBones[1] { HumanBodyBones.Neck };
|
||||
List<Vector3> list = this.poseMatchCommonUtil.CollectHumanoidVerticesWorld(targetHumanBones, avatarBakedBodyMeshes, avatarBoneMap);
|
||||
if (list == null || list.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[AvatarBodyMatchUtil] ComputeNeckRegionStats: neck vertices 0개. avatar=" + avatarTransform?.name);
|
||||
return default(RegionStats);
|
||||
}
|
||||
RegionStats result = new PcaUtil().ComputeRegionStats(list);
|
||||
Vector3 vector = avatarTransform.up;
|
||||
Transform boneFromBoneMap = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, HumanBodyBones.Head);
|
||||
Transform boneFromBoneMap2 = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, HumanBodyBones.UpperChest);
|
||||
Transform boneFromBoneMap3 = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, HumanBodyBones.Chest);
|
||||
Transform boneFromBoneMap4 = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, HumanBodyBones.Hips);
|
||||
Transform transform = ((boneFromBoneMap2 != null) ? boneFromBoneMap2 : boneFromBoneMap3);
|
||||
if (boneFromBoneMap != null && transform != null)
|
||||
{
|
||||
vector = boneFromBoneMap.position - transform.position;
|
||||
}
|
||||
else if (boneFromBoneMap != null && boneFromBoneMap4 != null)
|
||||
{
|
||||
vector = boneFromBoneMap.position - boneFromBoneMap4.position;
|
||||
}
|
||||
if (vector.sqrMagnitude > 1E-08f)
|
||||
{
|
||||
vector.Normalize();
|
||||
}
|
||||
if (Vector3.Dot(vector, avatarTransform.transform.up) < 0f)
|
||||
{
|
||||
vector = -vector;
|
||||
}
|
||||
result.principalAxis = vector;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void DrawTorsoPcaDebug(GameObject avatarObject, IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap, Color centerColor, Color axisColor, float axisScale = 1f, float duration = 0.1f)
|
||||
{
|
||||
if (!(avatarObject == null))
|
||||
{
|
||||
RegionStats regionStats = ComputeNeckRegionStats(avatarObject.transform, avatarBakedBodyMeshes, avatarBoneMap);
|
||||
if (regionStats.length < 0.0001f)
|
||||
{
|
||||
Debug.LogWarning($"[AvatarBodyMatchUtil] DrawNeckPcaDebug: neck.length가 너무 작음. avatar={avatarObject.name}, length={regionStats.length}");
|
||||
return;
|
||||
}
|
||||
Vector3 center = regionStats.center;
|
||||
Vector3 normalized = regionStats.principalAxis.normalized;
|
||||
float num = 0.02f * axisScale;
|
||||
Debug.DrawLine(center + Vector3.up * num, center - Vector3.up * num, centerColor, duration);
|
||||
Debug.DrawLine(center + Vector3.right * num, center - Vector3.right * num, centerColor, duration);
|
||||
float num2 = regionStats.length * 0.5f * axisScale;
|
||||
Vector3 end = center + normalized * num2;
|
||||
Debug.DrawLine(center, end, axisColor, duration);
|
||||
Debug.Log($"[AvatarBodyMatchUtil] DrawNeckPcaDebug: avatar={avatarObject.name}, center={center}, axis={normalized}, halfLen={num2}");
|
||||
}
|
||||
}
|
||||
public void DrawTorsoPcaDebug(GameObject avatarObject, IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes, Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap, Color centerColor, Color axisColor, float axisScale = 1f, float duration = 0.1f)
|
||||
{
|
||||
if (!(avatarObject == null))
|
||||
{
|
||||
RegionStats regionStats = this.ComputeNeckRegionStats(avatarObject.transform, avatarBakedBodyMeshes, avatarBoneMap);
|
||||
if (regionStats.length < 0.0001f)
|
||||
{
|
||||
Debug.LogWarning($"[AvatarBodyMatchUtil] DrawNeckPcaDebug: neck.length가 너무 작음. avatar={avatarObject.name}, length={regionStats.length}");
|
||||
return;
|
||||
}
|
||||
Vector3 center = regionStats.center;
|
||||
Vector3 normalized = regionStats.principalAxis.normalized;
|
||||
float num = 0.02f * axisScale;
|
||||
Debug.DrawLine(center + Vector3.up * num, center - Vector3.up * num, centerColor, duration);
|
||||
Debug.DrawLine(center + Vector3.right * num, center - Vector3.right * num, centerColor, duration);
|
||||
float num2 = regionStats.length * 0.5f * axisScale;
|
||||
Vector3 end = center + normalized * num2;
|
||||
Debug.DrawLine(center, end, axisColor, duration);
|
||||
Debug.Log($"[AvatarBodyMatchUtil] DrawNeckPcaDebug: avatar={avatarObject.name}, center={center}, axis={normalized}, halfLen={num2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,251 +1,250 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BodyPoseToClothApplier
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public class BodyPoseToClothApplier
|
||||
{
|
||||
private class BoneMapping
|
||||
{
|
||||
public Transform proxyBone;
|
||||
private class BoneMapping
|
||||
{
|
||||
public Transform proxyBone;
|
||||
|
||||
public Transform clothBone;
|
||||
public Transform clothBone;
|
||||
|
||||
public int depth;
|
||||
public int depth;
|
||||
|
||||
public HumanBodyBones? humanBone;
|
||||
}
|
||||
public HumanBodyBones? humanBone;
|
||||
}
|
||||
|
||||
public void ApplyBodyPoseToClothes(Transform bodyProxyRoot, Transform clothesRoot, Dictionary<Transform, BoneMatchUtil.BoneRootLocalData> clothToBodyMatched, Dictionary<Transform, Transform> sourceToProxy, bool copyPosition = true, bool copyRotation = false, bool copyScale = true)
|
||||
{
|
||||
if (bodyProxyRoot == null)
|
||||
{
|
||||
throw new AutoMorpherException("Body Proxy Root is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - bodyProxyRoot is null");
|
||||
}
|
||||
if (clothesRoot == null)
|
||||
{
|
||||
throw new AutoMorpherException("Clothes Root is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - clothesRoot is null");
|
||||
}
|
||||
if (clothToBodyMatched == null || clothToBodyMatched.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth To Body Matched Map is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - clothToBodyMatched is null or empty");
|
||||
}
|
||||
if (sourceToProxy == null)
|
||||
{
|
||||
throw new AutoMorpherException("Source To Proxy Map is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - sourceToProxy is null");
|
||||
}
|
||||
clothesRoot.localScale = bodyProxyRoot.localScale;
|
||||
Animator component = bodyProxyRoot.GetComponent<Animator>();
|
||||
if (component == null)
|
||||
{
|
||||
throw new AutoMorpherException("Body Proxy Animator is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - bodyProxyRoot has no Animator");
|
||||
}
|
||||
Transform transform = component.transform;
|
||||
Dictionary<Transform, int> dictionary = BuildDepthMap(transform);
|
||||
Dictionary<Transform, Transform> dictionary2 = new Dictionary<Transform, Transform>();
|
||||
List<BoneMapping> list = new List<BoneMapping>();
|
||||
HashSet<Transform> hashSet = new HashSet<Transform>();
|
||||
foreach (KeyValuePair<Transform, BoneMatchUtil.BoneRootLocalData> item in clothToBodyMatched)
|
||||
{
|
||||
Transform key = item.Key;
|
||||
BoneMatchUtil.BoneRootLocalData value = item.Value;
|
||||
if (key == null || value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform t = value.t;
|
||||
if (t == null || !sourceToProxy.TryGetValue(t, out var value2) || value2 == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
HumanBodyBones hBone = value.hBone;
|
||||
if (hashSet.Add(key))
|
||||
{
|
||||
int depth = 999;
|
||||
if (dictionary != null && dictionary.TryGetValue(value2, out var value3))
|
||||
{
|
||||
depth = value3;
|
||||
}
|
||||
list.Add(new BoneMapping
|
||||
{
|
||||
proxyBone = value2,
|
||||
clothBone = key,
|
||||
depth = depth,
|
||||
humanBone = ((hBone != HumanBodyBones.LastBone) ? new HumanBodyBones?(hBone) : ((HumanBodyBones?)null))
|
||||
});
|
||||
}
|
||||
if (!dictionary2.ContainsKey(value2))
|
||||
{
|
||||
dictionary2.Add(value2, key);
|
||||
}
|
||||
}
|
||||
MirrorBoneMarkers(transform, dictionary2, dictionary, list);
|
||||
foreach (BoneMapping item2 in (from m in list
|
||||
where m != null && m.proxyBone != null && m.clothBone != null
|
||||
orderby m.depth
|
||||
select m).ToList())
|
||||
{
|
||||
if (!(item2.proxyBone == null) && !(item2.clothBone == null))
|
||||
{
|
||||
if (copyPosition)
|
||||
{
|
||||
item2.clothBone.position = item2.proxyBone.position;
|
||||
}
|
||||
if (copyRotation)
|
||||
{
|
||||
item2.clothBone.rotation = item2.proxyBone.rotation;
|
||||
}
|
||||
if (copyScale)
|
||||
{
|
||||
item2.clothBone.localScale = item2.proxyBone.localScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void ApplyBodyPoseToClothes(Transform bodyProxyRoot, Transform clothesRoot, Dictionary<Transform, BoneMatchUtil.BoneRootLocalData> clothToBodyMatched, Dictionary<Transform, Transform> sourceToProxy, bool copyPosition = true, bool copyRotation = false, bool copyScale = true)
|
||||
{
|
||||
if (bodyProxyRoot == null)
|
||||
{
|
||||
throw new AutoMorpherException("Body Proxy Root is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - bodyProxyRoot is null");
|
||||
}
|
||||
if (clothesRoot == null)
|
||||
{
|
||||
throw new AutoMorpherException("Clothes Root is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - clothesRoot is null");
|
||||
}
|
||||
if (clothToBodyMatched == null || clothToBodyMatched.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth To Body Matched Map is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - clothToBodyMatched is null or empty");
|
||||
}
|
||||
if (sourceToProxy == null)
|
||||
{
|
||||
throw new AutoMorpherException("Source To Proxy Map is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - sourceToProxy is null");
|
||||
}
|
||||
clothesRoot.localScale = bodyProxyRoot.localScale;
|
||||
Animator component = bodyProxyRoot.GetComponent<Animator>();
|
||||
if (component == null)
|
||||
{
|
||||
throw new AutoMorpherException("Body Proxy Animator is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - bodyProxyRoot has no Animator");
|
||||
}
|
||||
Transform transform = component.transform;
|
||||
Dictionary<Transform, int> dictionary = this.BuildDepthMap(transform);
|
||||
Dictionary<Transform, Transform> dictionary2 = new Dictionary<Transform, Transform>();
|
||||
List<BoneMapping> list = new List<BoneMapping>();
|
||||
HashSet<Transform> hashSet = new HashSet<Transform>();
|
||||
foreach (KeyValuePair<Transform, BoneMatchUtil.BoneRootLocalData> item in clothToBodyMatched)
|
||||
{
|
||||
Transform key = item.Key;
|
||||
BoneMatchUtil.BoneRootLocalData value = item.Value;
|
||||
if (key == null || value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform t = value.t;
|
||||
if (t == null || !sourceToProxy.TryGetValue(t, out var value2) || value2 == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
HumanBodyBones hBone = value.hBone;
|
||||
if (hashSet.Add(key))
|
||||
{
|
||||
int depth = 999;
|
||||
if (dictionary != null && dictionary.TryGetValue(value2, out var value3))
|
||||
{
|
||||
depth = value3;
|
||||
}
|
||||
list.Add(new BoneMapping
|
||||
{
|
||||
proxyBone = value2,
|
||||
clothBone = key,
|
||||
depth = depth,
|
||||
humanBone = ((hBone != HumanBodyBones.LastBone) ? new HumanBodyBones?(hBone) : ((HumanBodyBones?)null))
|
||||
});
|
||||
}
|
||||
if (!dictionary2.ContainsKey(value2))
|
||||
{
|
||||
dictionary2.Add(value2, key);
|
||||
}
|
||||
}
|
||||
this.MirrorBoneMarkers(transform, dictionary2, dictionary, list);
|
||||
foreach (BoneMapping item2 in (from m in list
|
||||
where m != null && m.proxyBone != null && m.clothBone != null
|
||||
orderby m.depth
|
||||
select m).ToList())
|
||||
{
|
||||
if (!(item2.proxyBone == null) && !(item2.clothBone == null))
|
||||
{
|
||||
if (copyPosition)
|
||||
{
|
||||
item2.clothBone.position = item2.proxyBone.position;
|
||||
}
|
||||
if (copyRotation)
|
||||
{
|
||||
item2.clothBone.rotation = item2.proxyBone.rotation;
|
||||
}
|
||||
if (copyScale)
|
||||
{
|
||||
item2.clothBone.localScale = item2.proxyBone.localScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<Transform, int> BuildDepthMap(Transform root)
|
||||
{
|
||||
Dictionary<Transform, int> dictionary = new Dictionary<Transform, int>();
|
||||
if (root == null)
|
||||
{
|
||||
return dictionary;
|
||||
}
|
||||
Transform[] componentsInChildren = root.GetComponentsInChildren<Transform>(includeInactive: true);
|
||||
foreach (Transform transform in componentsInChildren)
|
||||
{
|
||||
if (!(transform == null))
|
||||
{
|
||||
dictionary[transform] = GetDepthFromRoot(transform, root);
|
||||
}
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
private Dictionary<Transform, int> BuildDepthMap(Transform root)
|
||||
{
|
||||
Dictionary<Transform, int> dictionary = new Dictionary<Transform, int>();
|
||||
if (root == null)
|
||||
{
|
||||
return dictionary;
|
||||
}
|
||||
Transform[] componentsInChildren = root.GetComponentsInChildren<Transform>(includeInactive: true);
|
||||
foreach (Transform transform in componentsInChildren)
|
||||
{
|
||||
if (!(transform == null))
|
||||
{
|
||||
dictionary[transform] = this.GetDepthFromRoot(transform, root);
|
||||
}
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
private int GetDepthFromRoot(Transform t, Transform root)
|
||||
{
|
||||
int num = 0;
|
||||
Transform transform = t;
|
||||
while (transform != null && transform != root)
|
||||
{
|
||||
num++;
|
||||
transform = transform.parent;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
private int GetDepthFromRoot(Transform t, Transform root)
|
||||
{
|
||||
int num = 0;
|
||||
Transform transform = t;
|
||||
while (transform != null && transform != root)
|
||||
{
|
||||
num++;
|
||||
transform = transform.parent;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
private void MirrorBoneMarkers(Transform proxyArmature, Dictionary<Transform, Transform> proxyToCloth, Dictionary<Transform, int> proxyDepthMap, List<BoneMapping> mappings)
|
||||
{
|
||||
if (proxyArmature == null || proxyToCloth == null || mappings == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TempBoneMarker[] componentsInChildren = proxyArmature.GetComponentsInChildren<TempBoneMarker>(includeInactive: true);
|
||||
if (componentsInChildren == null || componentsInChildren.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
HashSet<Transform> hashSet = new HashSet<Transform>();
|
||||
for (int i = 0; i < mappings.Count; i++)
|
||||
{
|
||||
BoneMapping boneMapping = mappings[i];
|
||||
if (boneMapping != null && boneMapping.proxyBone != null)
|
||||
{
|
||||
hashSet.Add(boneMapping.proxyBone);
|
||||
}
|
||||
}
|
||||
foreach (TempBoneMarker item in (from bm in componentsInChildren
|
||||
where bm != null && bm.transform != null
|
||||
orderby (proxyDepthMap != null && proxyDepthMap.TryGetValue(bm.transform, out var value3)) ? value3 : int.MaxValue
|
||||
select bm).ToList())
|
||||
{
|
||||
Transform transform = item.transform;
|
||||
if (transform == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform originalParent = item.originalParent;
|
||||
if (originalParent == null || !proxyToCloth.TryGetValue(originalParent, out var value) || value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
List<Transform> list = CollectDirectChilds(value);
|
||||
Transform transform2 = FindMarkerInChild(value);
|
||||
TempBoneMarker tempBoneMarker = null;
|
||||
if (transform2 == null)
|
||||
{
|
||||
transform2 = new GameObject(transform.name).transform;
|
||||
transform2.SetParent(value, worldPositionStays: true);
|
||||
tempBoneMarker = transform2.gameObject.AddComponent<TempBoneMarker>();
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBoneMarker = transform2.GetComponent<TempBoneMarker>();
|
||||
}
|
||||
transform2.position = transform.position;
|
||||
transform2.rotation = transform.rotation;
|
||||
transform2.localScale = transform.localScale;
|
||||
tempBoneMarker.originalParent = value;
|
||||
tempBoneMarker.additionalInfo = item.additionalInfo;
|
||||
tempBoneMarker.wrappedChildNames = item.wrappedChildNames;
|
||||
for (int num = 0; num < list.Count; num++)
|
||||
{
|
||||
Transform transform3 = list[num];
|
||||
if (!(transform3 == null) && !(transform3 == transform2))
|
||||
{
|
||||
transform3.SetParent(transform2, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
if (!proxyToCloth.ContainsKey(transform))
|
||||
{
|
||||
proxyToCloth.Add(transform, transform2);
|
||||
}
|
||||
if (hashSet.Add(transform))
|
||||
{
|
||||
int depth = 999;
|
||||
if (proxyDepthMap != null && proxyDepthMap.TryGetValue(transform, out var value2))
|
||||
{
|
||||
depth = value2;
|
||||
}
|
||||
mappings.Add(new BoneMapping
|
||||
{
|
||||
proxyBone = transform,
|
||||
clothBone = transform2,
|
||||
depth = depth,
|
||||
humanBone = null
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
private void MirrorBoneMarkers(Transform proxyArmature, Dictionary<Transform, Transform> proxyToCloth, Dictionary<Transform, int> proxyDepthMap, List<BoneMapping> mappings)
|
||||
{
|
||||
if (proxyArmature == null || proxyToCloth == null || mappings == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TempBoneMarker[] componentsInChildren = proxyArmature.GetComponentsInChildren<TempBoneMarker>(includeInactive: true);
|
||||
if (componentsInChildren == null || componentsInChildren.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
HashSet<Transform> hashSet = new HashSet<Transform>();
|
||||
for (int i = 0; i < mappings.Count; i++)
|
||||
{
|
||||
BoneMapping boneMapping = mappings[i];
|
||||
if (boneMapping != null && boneMapping.proxyBone != null)
|
||||
{
|
||||
hashSet.Add(boneMapping.proxyBone);
|
||||
}
|
||||
}
|
||||
foreach (TempBoneMarker item in (from bm in componentsInChildren
|
||||
where bm != null && bm.transform != null
|
||||
orderby (proxyDepthMap != null && proxyDepthMap.TryGetValue(bm.transform, out var value3)) ? value3 : int.MaxValue
|
||||
select bm).ToList())
|
||||
{
|
||||
Transform transform = item.transform;
|
||||
if (transform == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform originalParent = item.originalParent;
|
||||
if (originalParent == null || !proxyToCloth.TryGetValue(originalParent, out var value) || value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
List<Transform> list = this.CollectDirectChilds(value);
|
||||
Transform transform2 = this.FindMarkerInChild(value);
|
||||
TempBoneMarker tempBoneMarker = null;
|
||||
if (transform2 == null)
|
||||
{
|
||||
transform2 = new GameObject(transform.name).transform;
|
||||
transform2.SetParent(value, worldPositionStays: true);
|
||||
tempBoneMarker = transform2.gameObject.AddComponent<TempBoneMarker>();
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBoneMarker = transform2.GetComponent<TempBoneMarker>();
|
||||
}
|
||||
transform2.position = transform.position;
|
||||
transform2.rotation = transform.rotation;
|
||||
transform2.localScale = transform.localScale;
|
||||
tempBoneMarker.originalParent = value;
|
||||
tempBoneMarker.additionalInfo = item.additionalInfo;
|
||||
tempBoneMarker.wrappedChildNames = item.wrappedChildNames;
|
||||
for (int num = 0; num < list.Count; num++)
|
||||
{
|
||||
Transform transform3 = list[num];
|
||||
if (!(transform3 == null) && !(transform3 == transform2))
|
||||
{
|
||||
transform3.SetParent(transform2, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
if (!proxyToCloth.ContainsKey(transform))
|
||||
{
|
||||
proxyToCloth.Add(transform, transform2);
|
||||
}
|
||||
if (hashSet.Add(transform))
|
||||
{
|
||||
int depth = 999;
|
||||
if (proxyDepthMap != null && proxyDepthMap.TryGetValue(transform, out var value2))
|
||||
{
|
||||
depth = value2;
|
||||
}
|
||||
mappings.Add(new BoneMapping
|
||||
{
|
||||
proxyBone = transform,
|
||||
clothBone = transform2,
|
||||
depth = depth,
|
||||
humanBone = null
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Transform FindMarkerInChild(Transform parent)
|
||||
{
|
||||
if (parent == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < parent.childCount; i++)
|
||||
{
|
||||
Transform child = parent.GetChild(i);
|
||||
if (!(child == null) && child.GetComponent<TempBoneMarker>() != null)
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private Transform FindMarkerInChild(Transform parent)
|
||||
{
|
||||
if (parent == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < parent.childCount; i++)
|
||||
{
|
||||
Transform child = parent.GetChild(i);
|
||||
if (!(child == null) && child.GetComponent<TempBoneMarker>() != null)
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<Transform> CollectDirectChilds(Transform parentTransform)
|
||||
{
|
||||
int childCount = parentTransform.childCount;
|
||||
List<Transform> list = new List<Transform>(childCount);
|
||||
for (int i = 0; i < childCount; i++)
|
||||
{
|
||||
list.Add(parentTransform.GetChild(i));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
private List<Transform> CollectDirectChilds(Transform parentTransform)
|
||||
{
|
||||
int childCount = parentTransform.childCount;
|
||||
List<Transform> list = new List<Transform>(childCount);
|
||||
for (int i = 0; i < childCount; i++)
|
||||
{
|
||||
list.Add(parentTransform.GetChild(i));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +1,168 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BoneAlignmentUtil
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public class BoneAlignmentUtil
|
||||
{
|
||||
public void AlignClothBonesToAvatar(ClothInstance cloth, Animator targetAvatarAnimator)
|
||||
{
|
||||
if (cloth == null || targetAvatarAnimator == null)
|
||||
{
|
||||
Debug.LogWarning("[BoneAlignmentUtil] cloth 또는 targetAvatarAnimator 가 null.");
|
||||
return;
|
||||
}
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> humanoidMatchedBone in cloth.humanoidMatchedBones)
|
||||
{
|
||||
HumanBodyBones key = humanoidMatchedBone.Key;
|
||||
foreach (Transform item in humanoidMatchedBone.Value)
|
||||
{
|
||||
if (!(item == null))
|
||||
{
|
||||
Transform boneTransform = targetAvatarAnimator.GetBoneTransform(key);
|
||||
if (!(boneTransform == null))
|
||||
{
|
||||
item.position = boneTransform.position;
|
||||
item.localScale = Vector3.one;
|
||||
item.name = boneTransform.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void AlignClothBonesToAvatar(ClothInstance cloth, Animator targetAvatarAnimator)
|
||||
{
|
||||
if (cloth == null || targetAvatarAnimator == null)
|
||||
{
|
||||
Debug.LogWarning("[BoneAlignmentUtil] cloth 또는 targetAvatarAnimator 가 null.");
|
||||
return;
|
||||
}
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> humanoidMatchedBone in cloth.humanoidMatchedBones)
|
||||
{
|
||||
HumanBodyBones key = humanoidMatchedBone.Key;
|
||||
foreach (Transform item in humanoidMatchedBone.Value)
|
||||
{
|
||||
if (!(item == null))
|
||||
{
|
||||
Transform boneTransform = targetAvatarAnimator.GetBoneTransform(key);
|
||||
if (!(boneTransform == null))
|
||||
{
|
||||
item.position = boneTransform.position;
|
||||
item.localScale = Vector3.one;
|
||||
item.name = boneTransform.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ReparentAccessoryBonesToAvatar(EdenAutoMorpherConfig config)
|
||||
{
|
||||
if (config.clothBoneTypeMap == null || config.targetAvatarObject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Animator component = config.targetAvatarObject.GetComponent<Animator>();
|
||||
if (component == null || !component.isHuman)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Dictionary<Transform, Transform> dictionary = new Dictionary<Transform, Transform>();
|
||||
if (config.clothesHumanoidMatchedBones != null)
|
||||
{
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBone in config.clothesHumanoidMatchedBones)
|
||||
{
|
||||
HumanBodyBones key = clothesHumanoidMatchedBone.Key;
|
||||
foreach (Transform item2 in clothesHumanoidMatchedBone.Value)
|
||||
{
|
||||
Transform boneTransform = component.GetBoneTransform(key);
|
||||
if (item2 != null && boneTransform != null)
|
||||
{
|
||||
dictionary[item2] = boneTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<Transform, ClothBoneType> item3 in config.clothBoneTypeMap)
|
||||
{
|
||||
if (item3.Value != ClothBoneType.Accessory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform key2 = item3.Key;
|
||||
if (key2 == null || !key2.IsChildOf(config.targetClothesObject.transform))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform parent = key2.parent;
|
||||
Transform transform = null;
|
||||
while (parent != null)
|
||||
{
|
||||
if (config.clothBoneTypeMap.TryGetValue(parent, out var value) && value == ClothBoneType.Body)
|
||||
{
|
||||
transform = parent;
|
||||
break;
|
||||
}
|
||||
parent = parent.parent;
|
||||
}
|
||||
if (!(transform == null) && dictionary.TryGetValue(transform, out var value2))
|
||||
{
|
||||
key2.SetParent(value2, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<Transform, Transform> item4 in dictionary)
|
||||
{
|
||||
Transform key3 = item4.Key;
|
||||
Transform value3 = item4.Value;
|
||||
if (key3 == null || value3 == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
List<Transform> list = new List<Transform>();
|
||||
foreach (Transform item5 in key3)
|
||||
{
|
||||
list.Add(item5);
|
||||
}
|
||||
foreach (Transform item6 in list)
|
||||
{
|
||||
if (!(item6 == null) && !config.clothBoneTypeMap.ContainsKey(item6))
|
||||
{
|
||||
item6.SetParent(value3, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void ReparentAccessoryBonesToAvatar(EdenAutoMorpherConfig config)
|
||||
{
|
||||
if (config.clothBoneTypeMap == null || config.targetAvatarObject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Animator component = config.targetAvatarObject.GetComponent<Animator>();
|
||||
if (component == null || !component.isHuman)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Dictionary<Transform, Transform> dictionary = new Dictionary<Transform, Transform>();
|
||||
if (config.clothesHumanoidMatchedBones != null)
|
||||
{
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBone in config.clothesHumanoidMatchedBones)
|
||||
{
|
||||
HumanBodyBones key = clothesHumanoidMatchedBone.Key;
|
||||
foreach (Transform item2 in clothesHumanoidMatchedBone.Value)
|
||||
{
|
||||
Transform boneTransform = component.GetBoneTransform(key);
|
||||
if (item2 != null && boneTransform != null)
|
||||
{
|
||||
dictionary[item2] = boneTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<Transform, ClothBoneType> item3 in config.clothBoneTypeMap)
|
||||
{
|
||||
if (item3.Value != ClothBoneType.Accessory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform key2 = item3.Key;
|
||||
if (key2 == null || !key2.IsChildOf(config.targetClothesObject.transform))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform parent = key2.parent;
|
||||
Transform transform = null;
|
||||
while (parent != null)
|
||||
{
|
||||
if (config.clothBoneTypeMap.TryGetValue(parent, out var value) && value == ClothBoneType.Body)
|
||||
{
|
||||
transform = parent;
|
||||
break;
|
||||
}
|
||||
parent = parent.parent;
|
||||
}
|
||||
if (!(transform == null) && dictionary.TryGetValue(transform, out var value2))
|
||||
{
|
||||
key2.SetParent(value2, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<Transform, Transform> item4 in dictionary)
|
||||
{
|
||||
Transform key3 = item4.Key;
|
||||
Transform value3 = item4.Value;
|
||||
if (key3 == null || value3 == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
List<Transform> list = new List<Transform>();
|
||||
foreach (Transform item5 in key3)
|
||||
{
|
||||
list.Add(item5);
|
||||
}
|
||||
foreach (Transform item6 in list)
|
||||
{
|
||||
if (!(item6 == null) && !config.clothBoneTypeMap.ContainsKey(item6))
|
||||
{
|
||||
item6.SetParent(value3, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CleanupTempBones(Transform root)
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TempBoneMarker[] componentsInChildren = root.GetComponentsInChildren<TempBoneMarker>(includeInactive: true);
|
||||
if (componentsInChildren == null || componentsInChildren.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TempBoneMarker[] array = (from m in componentsInChildren
|
||||
where m != null
|
||||
orderby GetDepth(m.transform) descending
|
||||
select m).ToArray();
|
||||
foreach (TempBoneMarker tempBoneMarker in array)
|
||||
{
|
||||
if (tempBoneMarker == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform transform = tempBoneMarker.transform;
|
||||
Transform transform2 = tempBoneMarker.originalParent;
|
||||
if (transform2 == null)
|
||||
{
|
||||
transform2 = transform.parent;
|
||||
}
|
||||
if (transform2 != null)
|
||||
{
|
||||
while (transform.childCount > 0)
|
||||
{
|
||||
transform.GetChild(0).SetParent(transform2, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(transform.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(transform.gameObject);
|
||||
}
|
||||
}
|
||||
static int GetDepth(Transform t)
|
||||
{
|
||||
int num2 = 0;
|
||||
while (t != null)
|
||||
{
|
||||
num2++;
|
||||
t = t.parent;
|
||||
}
|
||||
return num2;
|
||||
}
|
||||
}
|
||||
public void CleanupTempBones(Transform root)
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TempBoneMarker[] componentsInChildren = root.GetComponentsInChildren<TempBoneMarker>(includeInactive: true);
|
||||
if (componentsInChildren == null || componentsInChildren.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TempBoneMarker[] array = (from m in componentsInChildren
|
||||
where m != null
|
||||
orderby GetDepth(m.transform) descending
|
||||
select m).ToArray();
|
||||
foreach (TempBoneMarker tempBoneMarker in array)
|
||||
{
|
||||
if (tempBoneMarker == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Transform transform = tempBoneMarker.transform;
|
||||
Transform transform2 = tempBoneMarker.originalParent;
|
||||
if (transform2 == null)
|
||||
{
|
||||
transform2 = transform.parent;
|
||||
}
|
||||
if (transform2 != null)
|
||||
{
|
||||
while (transform.childCount > 0)
|
||||
{
|
||||
transform.GetChild(0).SetParent(transform2, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(transform.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
Object.Destroy(transform.gameObject);
|
||||
}
|
||||
}
|
||||
static int GetDepth(Transform t)
|
||||
{
|
||||
int num2 = 0;
|
||||
while (t != null)
|
||||
{
|
||||
num2++;
|
||||
t = t.parent;
|
||||
}
|
||||
return num2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BoneCorrespondenceUtil
|
||||
@@ -9,187 +9,187 @@ using UnityEngine;
|
||||
|
||||
public class BoneCorrespondenceUtil
|
||||
{
|
||||
private char[] nameDelims = new char[8] { ' ', '-', '_', ':', '.', '|', '\\', '/' };
|
||||
private char[] nameDelims = new char[8] { ' ', '-', '_', ':', '.', '|', '\\', '/' };
|
||||
|
||||
public float ComputeDistanceScore(float d, float near, float mid, float far)
|
||||
{
|
||||
if (d < near)
|
||||
{
|
||||
return 120f;
|
||||
}
|
||||
if (d < mid)
|
||||
{
|
||||
return 90f;
|
||||
}
|
||||
if (d < far)
|
||||
{
|
||||
return 50f;
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
public float ComputeDistanceScore(float d, float near, float mid, float far)
|
||||
{
|
||||
if (d < near)
|
||||
{
|
||||
return 120f;
|
||||
}
|
||||
if (d < mid)
|
||||
{
|
||||
return 90f;
|
||||
}
|
||||
if (d < far)
|
||||
{
|
||||
return 50f;
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
|
||||
public float ComputeRotationScore(float ang, float RotTolDeg)
|
||||
{
|
||||
return Mathf.Clamp01(1f - ang / RotTolDeg);
|
||||
}
|
||||
public float ComputeRotationScore(float ang, float RotTolDeg)
|
||||
{
|
||||
return Mathf.Clamp01(1f - ang / RotTolDeg);
|
||||
}
|
||||
|
||||
public float ComputeNameScore(string bodyName, string bodyPath, string clothesName, string clothesPath)
|
||||
{
|
||||
string text = StripDigits(NormalizeName(bodyName));
|
||||
string text2 = StripDigits(NormalizeName(clothesName));
|
||||
string text3 = StripDigits(NormalizePath(bodyPath));
|
||||
string text4 = StripDigits(NormalizePath(clothesPath));
|
||||
if (!string.IsNullOrEmpty(text3) && text3 == text4)
|
||||
{
|
||||
return 80f;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(text) && text == text2)
|
||||
{
|
||||
return 70f;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text2) && (text.Contains(text2) || text2.Contains(text)))
|
||||
{
|
||||
return 40f;
|
||||
}
|
||||
return SubsequenceCoverage(bodyName, clothesName) * 10f;
|
||||
}
|
||||
public float ComputeNameScore(string bodyName, string bodyPath, string clothesName, string clothesPath)
|
||||
{
|
||||
string text = this.StripDigits(this.NormalizeName(bodyName));
|
||||
string text2 = this.StripDigits(this.NormalizeName(clothesName));
|
||||
string text3 = this.StripDigits(this.NormalizePath(bodyPath));
|
||||
string text4 = this.StripDigits(this.NormalizePath(clothesPath));
|
||||
if (!string.IsNullOrEmpty(text3) && text3 == text4)
|
||||
{
|
||||
return 80f;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(text) && text == text2)
|
||||
{
|
||||
return 70f;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(text2) && (text.Contains(text2) || text2.Contains(text)))
|
||||
{
|
||||
return 40f;
|
||||
}
|
||||
return this.SubsequenceCoverage(bodyName, clothesName) * 10f;
|
||||
}
|
||||
|
||||
private float SubsequenceCoverage(string bodyRaw, string clothesRaw)
|
||||
{
|
||||
string text = StripDigits(NormalizeName(bodyRaw));
|
||||
string text2 = StripDigits(NormalizeName(clothesRaw));
|
||||
if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2))
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
return (float)SubNameMatchBest(text, text2) / (float)text.Length;
|
||||
}
|
||||
private float SubsequenceCoverage(string bodyRaw, string clothesRaw)
|
||||
{
|
||||
string text = this.StripDigits(this.NormalizeName(bodyRaw));
|
||||
string text2 = this.StripDigits(this.NormalizeName(clothesRaw));
|
||||
if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2))
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
return (float)this.SubNameMatchBest(text, text2) / (float)text.Length;
|
||||
}
|
||||
|
||||
private int SubNameMatchBest(string a, string b, int minMatchCount = 3)
|
||||
{
|
||||
if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (a.Length < minMatchCount || b.Length < minMatchCount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int num = 0;
|
||||
for (int i = 0; i <= a.Length - minMatchCount; i++)
|
||||
{
|
||||
int num2 = SubNameMatch(a, i, b, minMatchCount);
|
||||
if (num2 > num)
|
||||
{
|
||||
num = num2;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
private int SubNameMatchBest(string a, string b, int minMatchCount = 3)
|
||||
{
|
||||
if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (a.Length < minMatchCount || b.Length < minMatchCount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int num = 0;
|
||||
for (int i = 0; i <= a.Length - minMatchCount; i++)
|
||||
{
|
||||
int num2 = this.SubNameMatch(a, i, b, minMatchCount);
|
||||
if (num2 > num)
|
||||
{
|
||||
num = num2;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
private int SubNameMatch(string a, int startA, string b, int minMatchCount = 3)
|
||||
{
|
||||
int length = a.Length;
|
||||
int length2 = b.Length;
|
||||
int num = 0;
|
||||
int num2 = 0;
|
||||
int num3 = 0;
|
||||
int num4 = 0;
|
||||
for (int i = startA; i < length; i++)
|
||||
{
|
||||
for (int j = num3; j < length2; j++)
|
||||
{
|
||||
num3 = j + 1;
|
||||
if (a[i] == b[j])
|
||||
{
|
||||
num4 = i + 1;
|
||||
num2++;
|
||||
if (num2 > num)
|
||||
{
|
||||
num = num2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (num2 > num)
|
||||
{
|
||||
num = num2;
|
||||
}
|
||||
num2 = 0;
|
||||
}
|
||||
if (num3 >= length2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (num2 > num)
|
||||
{
|
||||
num = num2;
|
||||
}
|
||||
if (num < minMatchCount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return num4 - startA;
|
||||
}
|
||||
private int SubNameMatch(string a, int startA, string b, int minMatchCount = 3)
|
||||
{
|
||||
int length = a.Length;
|
||||
int length2 = b.Length;
|
||||
int num = 0;
|
||||
int num2 = 0;
|
||||
int num3 = 0;
|
||||
int num4 = 0;
|
||||
for (int i = startA; i < length; i++)
|
||||
{
|
||||
for (int j = num3; j < length2; j++)
|
||||
{
|
||||
num3 = j + 1;
|
||||
if (a[i] == b[j])
|
||||
{
|
||||
num4 = i + 1;
|
||||
num2++;
|
||||
if (num2 > num)
|
||||
{
|
||||
num = num2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (num2 > num)
|
||||
{
|
||||
num = num2;
|
||||
}
|
||||
num2 = 0;
|
||||
}
|
||||
if (num3 >= length2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (num2 > num)
|
||||
{
|
||||
num = num2;
|
||||
}
|
||||
if (num < minMatchCount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return num4 - startA;
|
||||
}
|
||||
|
||||
public string GetHierarchyPath(Transform root, Transform t)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
Stack<string> stack = new Stack<string>();
|
||||
Transform transform = t;
|
||||
while (transform != null && transform != root)
|
||||
{
|
||||
stack.Push(transform.name);
|
||||
transform = transform.parent;
|
||||
}
|
||||
return string.Join("/", stack);
|
||||
}
|
||||
public string GetHierarchyPath(Transform root, Transform t)
|
||||
{
|
||||
if (t == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
Stack<string> stack = new Stack<string>();
|
||||
Transform transform = t;
|
||||
while (transform != null && transform != root)
|
||||
{
|
||||
stack.Push(transform.name);
|
||||
transform = transform.parent;
|
||||
}
|
||||
return string.Join("/", stack);
|
||||
}
|
||||
|
||||
public string NormalizeName(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
s = s.ToLowerInvariant();
|
||||
s = s.Replace("left", "l").Replace("right", "r");
|
||||
char[] array = nameDelims;
|
||||
foreach (char c in array)
|
||||
{
|
||||
s = s.Replace(c.ToString(), "");
|
||||
}
|
||||
s = StripDigits(s);
|
||||
return s;
|
||||
}
|
||||
public string NormalizeName(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
s = s.ToLowerInvariant();
|
||||
s = s.Replace("left", "l").Replace("right", "r");
|
||||
char[] array = this.nameDelims;
|
||||
foreach (char c in array)
|
||||
{
|
||||
s = s.Replace(c.ToString(), "");
|
||||
}
|
||||
s = this.StripDigits(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
public string NormalizePath(string p)
|
||||
{
|
||||
if (string.IsNullOrEmpty(p))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return string.Join("/", (from x in p.Split('/')
|
||||
where !string.IsNullOrEmpty(x)
|
||||
select x).Select(NormalizeName));
|
||||
}
|
||||
public string NormalizePath(string p)
|
||||
{
|
||||
if (string.IsNullOrEmpty(p))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return string.Join("/", (from x in p.Split('/')
|
||||
where !string.IsNullOrEmpty(x)
|
||||
select x).Select(this.NormalizeName));
|
||||
}
|
||||
|
||||
public string StripDigits(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
StringBuilder stringBuilder = new StringBuilder(s.Length);
|
||||
foreach (char c in s)
|
||||
{
|
||||
if (!char.IsDigit(c))
|
||||
{
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
public string StripDigits(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
StringBuilder stringBuilder = new StringBuilder(s.Length);
|
||||
foreach (char c in s)
|
||||
{
|
||||
if (!char.IsDigit(c))
|
||||
{
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BvhNode
|
||||
@@ -6,15 +6,15 @@ using UnityEngine;
|
||||
|
||||
public struct BvhNode
|
||||
{
|
||||
public Bounds bounds;
|
||||
public Bounds bounds;
|
||||
|
||||
public int leftChild;
|
||||
public int leftChild;
|
||||
|
||||
public int rightChild;
|
||||
public int rightChild;
|
||||
|
||||
public int start;
|
||||
public int start;
|
||||
|
||||
public int count;
|
||||
public int count;
|
||||
|
||||
public bool isLeaf;
|
||||
public bool isLeaf;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.BvhTriangle
|
||||
@@ -6,13 +6,13 @@ using UnityEngine;
|
||||
|
||||
public struct BvhTriangle
|
||||
{
|
||||
public Vector3 a;
|
||||
public Vector3 a;
|
||||
|
||||
public Vector3 b;
|
||||
public Vector3 b;
|
||||
|
||||
public Vector3 c;
|
||||
public Vector3 c;
|
||||
|
||||
public Vector3 normal;
|
||||
public Vector3 normal;
|
||||
|
||||
public HumanBodyBones mainHumanBone;
|
||||
public HumanBodyBones mainHumanBone;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.ClothBoneType
|
||||
public enum ClothBoneType
|
||||
{
|
||||
Body,
|
||||
Accessory
|
||||
Body,
|
||||
Accessory
|
||||
}
|
||||
|
||||
@@ -1,302 +1,301 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.ClothHumanoidMaskUtil
|
||||
using System.Collections.Generic;
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public class ClothHumanoidMaskUtil
|
||||
{
|
||||
public void BuildExcludedVertexMaskForHandsAndHead(ClothInstance clothInstance, bool excludeHandRoot = false, bool excludeThumbRoot = false)
|
||||
{
|
||||
if (clothInstance == null || clothInstance.smr == null)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] clothInstance / smr 가 null");
|
||||
return;
|
||||
}
|
||||
SkinnedMeshRenderer smr = clothInstance.smr;
|
||||
Mesh mesh = clothInstance.editableMesh ?? smr.sharedMesh;
|
||||
if (mesh == null)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] mesh 가 null");
|
||||
return;
|
||||
}
|
||||
BoneWeight[] boneWeights = mesh.boneWeights;
|
||||
Transform[] bones = smr.bones;
|
||||
if (boneWeights == null || boneWeights.Length == 0 || bones == null || bones.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] boneWeights 또는 bones 비어있음");
|
||||
return;
|
||||
}
|
||||
if (clothInstance.humanoidMatchedBones == null || clothInstance.humanoidMatchedBones.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] humanoidMatchedBones 가 비어있음 (BodyToClothPoseApplier에서 매칭 안 되었을 가능성)");
|
||||
return;
|
||||
}
|
||||
int num = mesh.vertexCount;
|
||||
if (boneWeights.Length != num)
|
||||
{
|
||||
num = Mathf.Min(num, boneWeights.Length);
|
||||
}
|
||||
HashSet<Transform> excludedBones = new HashSet<Transform>();
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanoidMatchedBones = clothInstance.humanoidMatchedBones;
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.Head, out var value) && value != null)
|
||||
{
|
||||
foreach (Transform item in value)
|
||||
{
|
||||
if (!(item == null))
|
||||
{
|
||||
AddHierarchy(item, includeRoot: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.LeftHand, out var value2) && value2 != null)
|
||||
{
|
||||
foreach (Transform item2 in value2)
|
||||
{
|
||||
if (!(item2 == null))
|
||||
{
|
||||
AddHierarchy(item2, excludeHandRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.RightHand, out var value3) && value3 != null)
|
||||
{
|
||||
foreach (Transform item3 in value3)
|
||||
{
|
||||
if (!(item3 == null))
|
||||
{
|
||||
AddHierarchy(item3, excludeHandRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.LeftThumbProximal, out var value4) && value4 != null)
|
||||
{
|
||||
foreach (Transform item4 in value4)
|
||||
{
|
||||
if (!(item4 == null))
|
||||
{
|
||||
if (excludeThumbRoot)
|
||||
{
|
||||
excludedBones.Add(item4);
|
||||
}
|
||||
else
|
||||
{
|
||||
excludedBones.Remove(item4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.RightThumbProximal, out var value5) && value5 != null)
|
||||
{
|
||||
foreach (Transform item5 in value5)
|
||||
{
|
||||
if (!(item5 == null))
|
||||
{
|
||||
if (excludeThumbRoot)
|
||||
{
|
||||
excludedBones.Add(item5);
|
||||
}
|
||||
else
|
||||
{
|
||||
excludedBones.Remove(item5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool[] boneIndexExcluded = new bool[bones.Length];
|
||||
for (int i = 0; i < bones.Length; i++)
|
||||
{
|
||||
Transform transform = bones[i];
|
||||
if (transform != null && excludedBones.Contains(transform))
|
||||
{
|
||||
boneIndexExcluded[i] = true;
|
||||
}
|
||||
}
|
||||
bool[] array = new bool[num];
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[j];
|
||||
float excludedWeightSum = 0f;
|
||||
AddExcludedWeight(boneWeight.weight0, boneWeight.boneIndex0);
|
||||
AddExcludedWeight(boneWeight.weight1, boneWeight.boneIndex1);
|
||||
AddExcludedWeight(boneWeight.weight2, boneWeight.boneIndex2);
|
||||
AddExcludedWeight(boneWeight.weight3, boneWeight.boneIndex3);
|
||||
array[j] = excludedWeightSum >= 0.8f;
|
||||
void AddExcludedWeight(float w, int bi)
|
||||
{
|
||||
if (!(w <= 0f) && bi >= 0 && bi < boneIndexExcluded.Length && boneIndexExcluded[bi])
|
||||
{
|
||||
excludedWeightSum += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
clothInstance.excludedVertices = array;
|
||||
BuildLegVertexMasks(clothInstance);
|
||||
void AddHierarchy(Transform root, bool includeRoot)
|
||||
{
|
||||
if (!(root == null))
|
||||
{
|
||||
Stack<Transform> stack = new Stack<Transform>();
|
||||
if (includeRoot)
|
||||
{
|
||||
stack.Push(root);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int k = 0; k < root.childCount; k++)
|
||||
{
|
||||
stack.Push(root.GetChild(k));
|
||||
}
|
||||
}
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
Transform transform2 = stack.Pop();
|
||||
if (!(transform2 == null) && excludedBones.Add(transform2))
|
||||
{
|
||||
for (int l = 0; l < transform2.childCount; l++)
|
||||
{
|
||||
stack.Push(transform2.GetChild(l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void BuildExcludedVertexMaskForHandsAndHead(ClothInstance clothInstance, bool excludeHandRoot = false, bool excludeThumbRoot = false)
|
||||
{
|
||||
if (clothInstance == null || clothInstance.smr == null)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] clothInstance / smr 가 null");
|
||||
return;
|
||||
}
|
||||
SkinnedMeshRenderer smr = clothInstance.smr;
|
||||
Mesh mesh = clothInstance.editableMesh ?? smr.sharedMesh;
|
||||
if (mesh == null)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] mesh 가 null");
|
||||
return;
|
||||
}
|
||||
BoneWeight[] boneWeights = mesh.boneWeights;
|
||||
Transform[] bones = smr.bones;
|
||||
if (boneWeights == null || boneWeights.Length == 0 || bones == null || bones.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] boneWeights 또는 bones 비어있음");
|
||||
return;
|
||||
}
|
||||
if (clothInstance.humanoidMatchedBones == null || clothInstance.humanoidMatchedBones.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] humanoidMatchedBones 가 비어있음 (BodyToClothPoseApplier에서 매칭 안 되었을 가능성)");
|
||||
return;
|
||||
}
|
||||
int num = mesh.vertexCount;
|
||||
if (boneWeights.Length != num)
|
||||
{
|
||||
num = Mathf.Min(num, boneWeights.Length);
|
||||
}
|
||||
HashSet<Transform> excludedBones = new HashSet<Transform>();
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanoidMatchedBones = clothInstance.humanoidMatchedBones;
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.Head, out var value) && value != null)
|
||||
{
|
||||
foreach (Transform item in value)
|
||||
{
|
||||
if (!(item == null))
|
||||
{
|
||||
AddHierarchy(item, includeRoot: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.LeftHand, out var value2) && value2 != null)
|
||||
{
|
||||
foreach (Transform item2 in value2)
|
||||
{
|
||||
if (!(item2 == null))
|
||||
{
|
||||
AddHierarchy(item2, excludeHandRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.RightHand, out var value3) && value3 != null)
|
||||
{
|
||||
foreach (Transform item3 in value3)
|
||||
{
|
||||
if (!(item3 == null))
|
||||
{
|
||||
AddHierarchy(item3, excludeHandRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.LeftThumbProximal, out var value4) && value4 != null)
|
||||
{
|
||||
foreach (Transform item4 in value4)
|
||||
{
|
||||
if (!(item4 == null))
|
||||
{
|
||||
if (excludeThumbRoot)
|
||||
{
|
||||
excludedBones.Add(item4);
|
||||
}
|
||||
else
|
||||
{
|
||||
excludedBones.Remove(item4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.RightThumbProximal, out var value5) && value5 != null)
|
||||
{
|
||||
foreach (Transform item5 in value5)
|
||||
{
|
||||
if (!(item5 == null))
|
||||
{
|
||||
if (excludeThumbRoot)
|
||||
{
|
||||
excludedBones.Add(item5);
|
||||
}
|
||||
else
|
||||
{
|
||||
excludedBones.Remove(item5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool[] boneIndexExcluded = new bool[bones.Length];
|
||||
for (int i = 0; i < bones.Length; i++)
|
||||
{
|
||||
Transform transform = bones[i];
|
||||
if (transform != null && excludedBones.Contains(transform))
|
||||
{
|
||||
boneIndexExcluded[i] = true;
|
||||
}
|
||||
}
|
||||
bool[] array = new bool[num];
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[j];
|
||||
float excludedWeightSum = 0f;
|
||||
AddExcludedWeight(boneWeight.weight0, boneWeight.boneIndex0);
|
||||
AddExcludedWeight(boneWeight.weight1, boneWeight.boneIndex1);
|
||||
AddExcludedWeight(boneWeight.weight2, boneWeight.boneIndex2);
|
||||
AddExcludedWeight(boneWeight.weight3, boneWeight.boneIndex3);
|
||||
array[j] = excludedWeightSum >= 0.8f;
|
||||
void AddExcludedWeight(float w, int bi)
|
||||
{
|
||||
if (!(w <= 0f) && bi >= 0 && bi < boneIndexExcluded.Length && boneIndexExcluded[bi])
|
||||
{
|
||||
excludedWeightSum += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
clothInstance.excludedVertices = array;
|
||||
this.BuildLegVertexMasks(clothInstance);
|
||||
void AddHierarchy(Transform root, bool includeRoot)
|
||||
{
|
||||
if (!(root == null))
|
||||
{
|
||||
Stack<Transform> stack = new Stack<Transform>();
|
||||
if (includeRoot)
|
||||
{
|
||||
stack.Push(root);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int k = 0; k < root.childCount; k++)
|
||||
{
|
||||
stack.Push(root.GetChild(k));
|
||||
}
|
||||
}
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
Transform transform2 = stack.Pop();
|
||||
if (!(transform2 == null) && excludedBones.Add(transform2))
|
||||
{
|
||||
for (int l = 0; l < transform2.childCount; l++)
|
||||
{
|
||||
stack.Push(transform2.GetChild(l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BuildLegVertexMasks(ClothInstance clothInstance)
|
||||
{
|
||||
if (clothInstance == null || clothInstance.smr == null)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] clothInstance / smr 가 null");
|
||||
return;
|
||||
}
|
||||
SkinnedMeshRenderer smr = clothInstance.smr;
|
||||
Mesh mesh = clothInstance.editableMesh ?? smr.sharedMesh;
|
||||
if (mesh == null)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] mesh 가 null");
|
||||
return;
|
||||
}
|
||||
BoneWeight[] boneWeights = mesh.boneWeights;
|
||||
Transform[] bones = smr.bones;
|
||||
if (boneWeights == null || boneWeights.Length == 0 || bones == null || bones.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] boneWeights 또는 bones 비어있음");
|
||||
return;
|
||||
}
|
||||
if (clothInstance.humanoidMatchedBones == null || clothInstance.humanoidMatchedBones.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] humanoidMatchedBones 가 비어있음 (BodyToClothPoseApplier에서 매칭 필요)");
|
||||
return;
|
||||
}
|
||||
int num = mesh.vertexCount;
|
||||
if (boneWeights.Length != num)
|
||||
{
|
||||
num = Mathf.Min(num, boneWeights.Length);
|
||||
}
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanoidMatchedBones = clothInstance.humanoidMatchedBones;
|
||||
HashSet<Transform> hashSet = new HashSet<Transform>();
|
||||
HashSet<Transform> hashSet2 = new HashSet<Transform>();
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.LeftUpperLeg, out var value) && value != null)
|
||||
{
|
||||
foreach (Transform item in value)
|
||||
{
|
||||
if (!(item == null))
|
||||
{
|
||||
CollectHierarchy(item, hashSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.RightUpperLeg, out var value2) && value2 != null)
|
||||
{
|
||||
foreach (Transform item2 in value2)
|
||||
{
|
||||
if (!(item2 == null))
|
||||
{
|
||||
CollectHierarchy(item2, hashSet2);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool[] boneIsLeftLeg = new bool[bones.Length];
|
||||
bool[] boneIsRightLeg = new bool[bones.Length];
|
||||
for (int i = 0; i < bones.Length; i++)
|
||||
{
|
||||
Transform transform = bones[i];
|
||||
if (!(transform == null))
|
||||
{
|
||||
if (hashSet.Contains(transform))
|
||||
{
|
||||
boneIsLeftLeg[i] = true;
|
||||
}
|
||||
if (hashSet2.Contains(transform))
|
||||
{
|
||||
boneIsRightLeg[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool[] array = new bool[num];
|
||||
bool[] array2 = new bool[num];
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[j];
|
||||
float leftWeight = 0f;
|
||||
float rightWeight = 0f;
|
||||
Check(boneWeight.boneIndex0, boneWeight.weight0);
|
||||
Check(boneWeight.boneIndex1, boneWeight.weight1);
|
||||
Check(boneWeight.boneIndex2, boneWeight.weight2);
|
||||
Check(boneWeight.boneIndex3, boneWeight.weight3);
|
||||
if (leftWeight > 0.8f)
|
||||
{
|
||||
array[j] = true;
|
||||
array2[j] = false;
|
||||
}
|
||||
else if (rightWeight > 0.8f)
|
||||
{
|
||||
array[j] = false;
|
||||
array2[j] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
array[j] = false;
|
||||
array2[j] = false;
|
||||
}
|
||||
void Check(int bi, float w)
|
||||
{
|
||||
if (bi >= 0 && bi < bones.Length && !(w <= 0f))
|
||||
{
|
||||
if (boneIsLeftLeg[bi])
|
||||
{
|
||||
leftWeight += w;
|
||||
}
|
||||
if (boneIsRightLeg[bi])
|
||||
{
|
||||
rightWeight += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clothInstance.isLeftLegVertex = array;
|
||||
clothInstance.isRightLegVertex = array2;
|
||||
static void CollectHierarchy(Transform root, HashSet<Transform> set)
|
||||
{
|
||||
if (!(root == null))
|
||||
{
|
||||
Stack<Transform> stack = new Stack<Transform>();
|
||||
stack.Push(root);
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
Transform transform2 = stack.Pop();
|
||||
if (!(transform2 == null) && set.Add(transform2))
|
||||
{
|
||||
for (int k = 0; k < transform2.childCount; k++)
|
||||
{
|
||||
stack.Push(transform2.GetChild(k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void BuildLegVertexMasks(ClothInstance clothInstance)
|
||||
{
|
||||
if (clothInstance == null || clothInstance.smr == null)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] clothInstance / smr 가 null");
|
||||
return;
|
||||
}
|
||||
SkinnedMeshRenderer smr = clothInstance.smr;
|
||||
Mesh mesh = clothInstance.editableMesh ?? smr.sharedMesh;
|
||||
if (mesh == null)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] mesh 가 null");
|
||||
return;
|
||||
}
|
||||
BoneWeight[] boneWeights = mesh.boneWeights;
|
||||
Transform[] bones = smr.bones;
|
||||
if (boneWeights == null || boneWeights.Length == 0 || bones == null || bones.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] boneWeights 또는 bones 비어있음");
|
||||
return;
|
||||
}
|
||||
if (clothInstance.humanoidMatchedBones == null || clothInstance.humanoidMatchedBones.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[ClothHumanoidMaskUtil] humanoidMatchedBones 가 비어있음 (BodyToClothPoseApplier에서 매칭 필요)");
|
||||
return;
|
||||
}
|
||||
int num = mesh.vertexCount;
|
||||
if (boneWeights.Length != num)
|
||||
{
|
||||
num = Mathf.Min(num, boneWeights.Length);
|
||||
}
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanoidMatchedBones = clothInstance.humanoidMatchedBones;
|
||||
HashSet<Transform> hashSet = new HashSet<Transform>();
|
||||
HashSet<Transform> hashSet2 = new HashSet<Transform>();
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.LeftUpperLeg, out var value) && value != null)
|
||||
{
|
||||
foreach (Transform item in value)
|
||||
{
|
||||
if (!(item == null))
|
||||
{
|
||||
CollectHierarchy(item, hashSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (humanoidMatchedBones.TryGetValue(HumanBodyBones.RightUpperLeg, out var value2) && value2 != null)
|
||||
{
|
||||
foreach (Transform item2 in value2)
|
||||
{
|
||||
if (!(item2 == null))
|
||||
{
|
||||
CollectHierarchy(item2, hashSet2);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool[] boneIsLeftLeg = new bool[bones.Length];
|
||||
bool[] boneIsRightLeg = new bool[bones.Length];
|
||||
for (int i = 0; i < bones.Length; i++)
|
||||
{
|
||||
Transform transform = bones[i];
|
||||
if (!(transform == null))
|
||||
{
|
||||
if (hashSet.Contains(transform))
|
||||
{
|
||||
boneIsLeftLeg[i] = true;
|
||||
}
|
||||
if (hashSet2.Contains(transform))
|
||||
{
|
||||
boneIsRightLeg[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool[] array = new bool[num];
|
||||
bool[] array2 = new bool[num];
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[j];
|
||||
float leftWeight = 0f;
|
||||
float rightWeight = 0f;
|
||||
Check(boneWeight.boneIndex0, boneWeight.weight0);
|
||||
Check(boneWeight.boneIndex1, boneWeight.weight1);
|
||||
Check(boneWeight.boneIndex2, boneWeight.weight2);
|
||||
Check(boneWeight.boneIndex3, boneWeight.weight3);
|
||||
if (leftWeight > 0.8f)
|
||||
{
|
||||
array[j] = true;
|
||||
array2[j] = false;
|
||||
}
|
||||
else if (rightWeight > 0.8f)
|
||||
{
|
||||
array[j] = false;
|
||||
array2[j] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
array[j] = false;
|
||||
array2[j] = false;
|
||||
}
|
||||
void Check(int bi, float w)
|
||||
{
|
||||
if (bi >= 0 && bi < bones.Length && !(w <= 0f))
|
||||
{
|
||||
if (boneIsLeftLeg[bi])
|
||||
{
|
||||
leftWeight += w;
|
||||
}
|
||||
if (boneIsRightLeg[bi])
|
||||
{
|
||||
rightWeight += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clothInstance.isLeftLegVertex = array;
|
||||
clothInstance.isRightLegVertex = array2;
|
||||
static void CollectHierarchy(Transform root, HashSet<Transform> set)
|
||||
{
|
||||
if (!(root == null))
|
||||
{
|
||||
Stack<Transform> stack = new Stack<Transform>();
|
||||
stack.Push(root);
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
Transform transform2 = stack.Pop();
|
||||
if (!(transform2 == null) && set.Add(transform2))
|
||||
{
|
||||
for (int k = 0; k < transform2.childCount; k++)
|
||||
{
|
||||
stack.Push(transform2.GetChild(k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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
|
||||
|
||||
@@ -1,307 +1,306 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.ClothInstanceTotal
|
||||
using System.Collections.Generic;
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public class ClothInstanceTotal
|
||||
{
|
||||
private readonly List<ClothInstance> clothInstances;
|
||||
private readonly List<ClothInstance> clothInstances;
|
||||
|
||||
public int TotalVertexCount { get; private set; }
|
||||
public int TotalVertexCount { get; private set; }
|
||||
|
||||
public Vector3[] GlobalPositions { get; private set; }
|
||||
public Vector3[] GlobalPositions { get; private set; }
|
||||
|
||||
public Vector3[] GlobalDeltas { get; private set; }
|
||||
public Vector3[] GlobalDeltas { get; private set; }
|
||||
|
||||
public List<int>[] GlobalAdjacencyTopology { get; private set; }
|
||||
public List<int>[] GlobalAdjacencyTopology { get; private set; }
|
||||
|
||||
public List<int>[] GlobalAdjacencyDistance { get; private set; }
|
||||
public List<int>[] GlobalAdjacencyDistance { get; private set; }
|
||||
|
||||
public List<int>[] GlobalAdjacencyMerged { get; private set; }
|
||||
public List<int>[] GlobalAdjacencyMerged { get; private set; }
|
||||
|
||||
public int[] VertexOffsets { get; private set; }
|
||||
public int[] VertexOffsets { get; private set; }
|
||||
|
||||
public ClothInstanceTotal(List<ClothInstance> clothInstances, float distanceBuildRadius, int maxNeighborsPerVertex = 0)
|
||||
{
|
||||
if (clothInstances == null || clothInstances.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instances are Missing", "[ClothInstanceTotal] ClothInstanceTotal\n - clothInstances is null or empty");
|
||||
}
|
||||
if (distanceBuildRadius <= 0f)
|
||||
{
|
||||
throw new AutoMorpherException("Distance Build Radius is Invalid", "[ClothInstanceTotal] ClothInstanceTotal\n - distanceBuildRadius must be > 0");
|
||||
}
|
||||
this.clothInstances = clothInstances;
|
||||
BuildTopologyCache();
|
||||
BuildDistanceAdjacencyCandidates(distanceBuildRadius, maxNeighborsPerVertex);
|
||||
BuildMergedAdjacency();
|
||||
}
|
||||
public ClothInstanceTotal(List<ClothInstance> clothInstances, float distanceBuildRadius, int maxNeighborsPerVertex = 0)
|
||||
{
|
||||
if (clothInstances == null || clothInstances.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instances are Missing", "[ClothInstanceTotal] ClothInstanceTotal\n - clothInstances is null or empty");
|
||||
}
|
||||
if (distanceBuildRadius <= 0f)
|
||||
{
|
||||
throw new AutoMorpherException("Distance Build Radius is Invalid", "[ClothInstanceTotal] ClothInstanceTotal\n - distanceBuildRadius must be > 0");
|
||||
}
|
||||
this.clothInstances = clothInstances;
|
||||
this.BuildTopologyCache();
|
||||
this.BuildDistanceAdjacencyCandidates(distanceBuildRadius, maxNeighborsPerVertex);
|
||||
this.BuildMergedAdjacency();
|
||||
}
|
||||
|
||||
public void SetGlobalDeltas(Vector3[] globalDeltas)
|
||||
{
|
||||
if (globalDeltas == null || globalDeltas.Length != TotalVertexCount)
|
||||
{
|
||||
throw new AutoMorpherException("Global Deltas are Invalid", "[ClothInstanceTotal] SetGlobalDeltas\n - globalDeltas is null or length mismatch");
|
||||
}
|
||||
GlobalDeltas = globalDeltas;
|
||||
}
|
||||
public void SetGlobalDeltas(Vector3[] globalDeltas)
|
||||
{
|
||||
if (globalDeltas == null || globalDeltas.Length != this.TotalVertexCount)
|
||||
{
|
||||
throw new AutoMorpherException("Global Deltas are Invalid", "[ClothInstanceTotal] SetGlobalDeltas\n - globalDeltas is null or length mismatch");
|
||||
}
|
||||
this.GlobalDeltas = globalDeltas;
|
||||
}
|
||||
|
||||
public void UpdateGlobalBuffersFromClothInstances()
|
||||
{
|
||||
ValidateGlobalBufferReady("[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances");
|
||||
for (int i = 0; i < clothInstances.Count; i++)
|
||||
{
|
||||
ClothInstance clothInstance = clothInstances[i];
|
||||
if (clothInstance != null)
|
||||
{
|
||||
if (clothInstance.worldVertices == null || clothInstance.deltasLocal == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Data is Missing", "[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances\n - worldVertices or deltasLocal is null");
|
||||
}
|
||||
int num = VertexOffsets[i];
|
||||
int num2 = clothInstance.worldVertices.Length;
|
||||
if (num2 != clothInstance.deltasLocal.Length)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Array Length Mismatch", "[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances\n - worldVertices.Length != deltasLocal.Length");
|
||||
}
|
||||
for (int j = 0; j < num2; j++)
|
||||
{
|
||||
GlobalPositions[num + j] = clothInstance.worldVertices[j];
|
||||
GlobalDeltas[num + j] = clothInstance.deltasLocal[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void UpdateGlobalBuffersFromClothInstances()
|
||||
{
|
||||
this.ValidateGlobalBufferReady("[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances");
|
||||
for (int i = 0; i < this.clothInstances.Count; i++)
|
||||
{
|
||||
ClothInstance clothInstance = this.clothInstances[i];
|
||||
if (clothInstance != null)
|
||||
{
|
||||
if (clothInstance.worldVertices == null || clothInstance.deltasLocal == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Data is Missing", "[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances\n - worldVertices or deltasLocal is null");
|
||||
}
|
||||
int num = this.VertexOffsets[i];
|
||||
int num2 = clothInstance.worldVertices.Length;
|
||||
if (num2 != clothInstance.deltasLocal.Length)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Array Length Mismatch", "[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances\n - worldVertices.Length != deltasLocal.Length");
|
||||
}
|
||||
for (int j = 0; j < num2; j++)
|
||||
{
|
||||
this.GlobalPositions[num + j] = clothInstance.worldVertices[j];
|
||||
this.GlobalDeltas[num + j] = clothInstance.deltasLocal[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyGlobalDeltasToClothInstances()
|
||||
{
|
||||
ValidateGlobalBufferReady("[ClothInstanceTotal] ApplyGlobalDeltasToClothInstances");
|
||||
for (int i = 0; i < clothInstances.Count; i++)
|
||||
{
|
||||
ClothInstance clothInstance = clothInstances[i];
|
||||
if (clothInstance != null)
|
||||
{
|
||||
if (clothInstance.deltasLocal == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Deltas are Missing", "[ClothInstanceTotal] ApplyGlobalDeltasToClothInstances\n - deltasLocal is null");
|
||||
}
|
||||
int num = VertexOffsets[i];
|
||||
int num2 = clothInstance.deltasLocal.Length;
|
||||
for (int j = 0; j < num2; j++)
|
||||
{
|
||||
clothInstance.deltasLocal[j] = GlobalDeltas[num + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void ApplyGlobalDeltasToClothInstances()
|
||||
{
|
||||
this.ValidateGlobalBufferReady("[ClothInstanceTotal] ApplyGlobalDeltasToClothInstances");
|
||||
for (int i = 0; i < this.clothInstances.Count; i++)
|
||||
{
|
||||
ClothInstance clothInstance = this.clothInstances[i];
|
||||
if (clothInstance != null)
|
||||
{
|
||||
if (clothInstance.deltasLocal == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Deltas are Missing", "[ClothInstanceTotal] ApplyGlobalDeltasToClothInstances\n - deltasLocal is null");
|
||||
}
|
||||
int num = this.VertexOffsets[i];
|
||||
int num2 = clothInstance.deltasLocal.Length;
|
||||
for (int j = 0; j < num2; j++)
|
||||
{
|
||||
clothInstance.deltasLocal[j] = this.GlobalDeltas[num + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateGlobalBufferReady(string functionContext)
|
||||
{
|
||||
if (clothInstances == null || clothInstances.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instances are Missing", functionContext + "\n - clothInstances is null or empty");
|
||||
}
|
||||
if (TotalVertexCount <= 0 || GlobalPositions == null || GlobalDeltas == null || VertexOffsets == null || GlobalAdjacencyMerged == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Total Cache is Not Ready", functionContext + "\n - total/global buffers/merged adjacency are not initialized");
|
||||
}
|
||||
}
|
||||
private void ValidateGlobalBufferReady(string functionContext)
|
||||
{
|
||||
if (this.clothInstances == null || this.clothInstances.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instances are Missing", functionContext + "\n - clothInstances is null or empty");
|
||||
}
|
||||
if (this.TotalVertexCount <= 0 || this.GlobalPositions == null || this.GlobalDeltas == null || this.VertexOffsets == null || this.GlobalAdjacencyMerged == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Total Cache is Not Ready", functionContext + "\n - total/global buffers/merged adjacency are not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildTopologyCache()
|
||||
{
|
||||
TotalVertexCount = CalculateTotalVertexCount(clothInstances);
|
||||
if (TotalVertexCount <= 0)
|
||||
{
|
||||
throw new AutoMorpherException("Total Vertex Count is Zero", "[ClothInstanceTotal] BuildTopologyCache\n - TotalVertexCount <= 0");
|
||||
}
|
||||
GlobalPositions = new Vector3[TotalVertexCount];
|
||||
GlobalDeltas = new Vector3[TotalVertexCount];
|
||||
GlobalAdjacencyTopology = new List<int>[TotalVertexCount];
|
||||
VertexOffsets = new int[clothInstances.Count];
|
||||
int num = 0;
|
||||
for (int i = 0; i < clothInstances.Count; i++)
|
||||
{
|
||||
ClothInstance clothInstance = clothInstances[i];
|
||||
VertexOffsets[i] = num;
|
||||
if (clothInstance == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (clothInstance.worldVertices == null || clothInstance.deltasLocal == null || clothInstance.vertexAdjacency == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Data is Missing", "[ClothInstanceTotal] BuildTopologyCache\n - worldVertices/deltasLocal/vertexAdjacency is null");
|
||||
}
|
||||
int num2 = clothInstance.worldVertices.Length;
|
||||
if (num2 != clothInstance.deltasLocal.Length || num2 != clothInstance.vertexAdjacency.Length)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Array Length Mismatch", "[ClothInstanceTotal] BuildTopologyCache\n - worldVertices/deltasLocal/vertexAdjacency lengths differ");
|
||||
}
|
||||
for (int j = 0; j < num2; j++)
|
||||
{
|
||||
GlobalPositions[num + j] = clothInstance.worldVertices[j];
|
||||
GlobalDeltas[num + j] = clothInstance.deltasLocal[j];
|
||||
int capacity = clothInstance.vertexAdjacency[j]?.Count ?? 0;
|
||||
GlobalAdjacencyTopology[num + j] = new List<int>(capacity);
|
||||
}
|
||||
for (int k = 0; k < num2; k++)
|
||||
{
|
||||
List<int> list = clothInstance.vertexAdjacency[k];
|
||||
if (list == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int num3 = num + k;
|
||||
List<int> list2 = GlobalAdjacencyTopology[num3];
|
||||
for (int l = 0; l < list.Count; l++)
|
||||
{
|
||||
int num4 = list[l];
|
||||
if ((uint)num4 >= (uint)num2)
|
||||
{
|
||||
throw new AutoMorpherException("Vertex Adjacency Index is Out of Range", "[ClothInstanceTotal] BuildTopologyCache\n - vertexAdjacency contains invalid neighbor index");
|
||||
}
|
||||
list2.Add(num + num4);
|
||||
}
|
||||
}
|
||||
num += num2;
|
||||
}
|
||||
}
|
||||
private void BuildTopologyCache()
|
||||
{
|
||||
this.TotalVertexCount = this.CalculateTotalVertexCount(this.clothInstances);
|
||||
if (this.TotalVertexCount <= 0)
|
||||
{
|
||||
throw new AutoMorpherException("Total Vertex Count is Zero", "[ClothInstanceTotal] BuildTopologyCache\n - TotalVertexCount <= 0");
|
||||
}
|
||||
this.GlobalPositions = new Vector3[this.TotalVertexCount];
|
||||
this.GlobalDeltas = new Vector3[this.TotalVertexCount];
|
||||
this.GlobalAdjacencyTopology = new List<int>[this.TotalVertexCount];
|
||||
this.VertexOffsets = new int[this.clothInstances.Count];
|
||||
int num = 0;
|
||||
for (int i = 0; i < this.clothInstances.Count; i++)
|
||||
{
|
||||
ClothInstance clothInstance = this.clothInstances[i];
|
||||
this.VertexOffsets[i] = num;
|
||||
if (clothInstance == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (clothInstance.worldVertices == null || clothInstance.deltasLocal == null || clothInstance.vertexAdjacency == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Data is Missing", "[ClothInstanceTotal] BuildTopologyCache\n - worldVertices/deltasLocal/vertexAdjacency is null");
|
||||
}
|
||||
int num2 = clothInstance.worldVertices.Length;
|
||||
if (num2 != clothInstance.deltasLocal.Length || num2 != clothInstance.vertexAdjacency.Length)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth Instance Array Length Mismatch", "[ClothInstanceTotal] BuildTopologyCache\n - worldVertices/deltasLocal/vertexAdjacency lengths differ");
|
||||
}
|
||||
for (int j = 0; j < num2; j++)
|
||||
{
|
||||
this.GlobalPositions[num + j] = clothInstance.worldVertices[j];
|
||||
this.GlobalDeltas[num + j] = clothInstance.deltasLocal[j];
|
||||
int capacity = clothInstance.vertexAdjacency[j]?.Count ?? 0;
|
||||
this.GlobalAdjacencyTopology[num + j] = new List<int>(capacity);
|
||||
}
|
||||
for (int k = 0; k < num2; k++)
|
||||
{
|
||||
List<int> list = clothInstance.vertexAdjacency[k];
|
||||
if (list == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int num3 = num + k;
|
||||
List<int> list2 = this.GlobalAdjacencyTopology[num3];
|
||||
for (int l = 0; l < list.Count; l++)
|
||||
{
|
||||
int num4 = list[l];
|
||||
if ((uint)num4 >= (uint)num2)
|
||||
{
|
||||
throw new AutoMorpherException("Vertex Adjacency Index is Out of Range", "[ClothInstanceTotal] BuildTopologyCache\n - vertexAdjacency contains invalid neighbor index");
|
||||
}
|
||||
list2.Add(num + num4);
|
||||
}
|
||||
}
|
||||
num += num2;
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildDistanceAdjacencyCandidates(float radius, int maxNeighborsPerVertex)
|
||||
{
|
||||
if (GlobalPositions == null || GlobalPositions.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Reference Positions are Missing", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidates\n - GlobalPositions is null or empty");
|
||||
}
|
||||
GlobalAdjacencyDistance = BuildDistanceAdjacencyCandidatesInternal(GlobalPositions, radius, maxNeighborsPerVertex);
|
||||
}
|
||||
private void BuildDistanceAdjacencyCandidates(float radius, int maxNeighborsPerVertex)
|
||||
{
|
||||
if (this.GlobalPositions == null || this.GlobalPositions.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Reference Positions are Missing", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidates\n - GlobalPositions is null or empty");
|
||||
}
|
||||
this.GlobalAdjacencyDistance = this.BuildDistanceAdjacencyCandidatesInternal(this.GlobalPositions, radius, maxNeighborsPerVertex);
|
||||
}
|
||||
|
||||
private void BuildMergedAdjacency()
|
||||
{
|
||||
if (GlobalAdjacencyTopology == null || GlobalAdjacencyDistance == null)
|
||||
{
|
||||
throw new AutoMorpherException("Adjacency Inputs are Missing", "[ClothInstanceTotal] BuildMergedAdjacency\n - GlobalAdjacencyTopology or GlobalAdjacencyDistance is null");
|
||||
}
|
||||
if (GlobalAdjacencyTopology.Length != GlobalAdjacencyDistance.Length)
|
||||
{
|
||||
throw new AutoMorpherException("Adjacency Length Mismatch", "[ClothInstanceTotal] BuildMergedAdjacency\n - topology and distance adjacency length differ");
|
||||
}
|
||||
int num = GlobalAdjacencyTopology.Length;
|
||||
GlobalAdjacencyMerged = new List<int>[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
List<int> list = new List<int>((GlobalAdjacencyTopology[i]?.Count ?? 0) + (GlobalAdjacencyDistance[i]?.Count ?? 0));
|
||||
HashSet<int> hashSet = new HashSet<int>();
|
||||
List<int> list2 = GlobalAdjacencyTopology[i];
|
||||
if (list2 != null)
|
||||
{
|
||||
for (int j = 0; j < list2.Count; j++)
|
||||
{
|
||||
int num2 = list2[j];
|
||||
if (num2 != i && hashSet.Add(num2))
|
||||
{
|
||||
list.Add(num2);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<int> list3 = GlobalAdjacencyDistance[i];
|
||||
if (list3 != null)
|
||||
{
|
||||
for (int k = 0; k < list3.Count; k++)
|
||||
{
|
||||
int num3 = list3[k];
|
||||
if (num3 != i && hashSet.Add(num3))
|
||||
{
|
||||
list.Add(num3);
|
||||
}
|
||||
}
|
||||
}
|
||||
GlobalAdjacencyMerged[i] = list;
|
||||
}
|
||||
}
|
||||
private void BuildMergedAdjacency()
|
||||
{
|
||||
if (this.GlobalAdjacencyTopology == null || this.GlobalAdjacencyDistance == null)
|
||||
{
|
||||
throw new AutoMorpherException("Adjacency Inputs are Missing", "[ClothInstanceTotal] BuildMergedAdjacency\n - GlobalAdjacencyTopology or GlobalAdjacencyDistance is null");
|
||||
}
|
||||
if (this.GlobalAdjacencyTopology.Length != this.GlobalAdjacencyDistance.Length)
|
||||
{
|
||||
throw new AutoMorpherException("Adjacency Length Mismatch", "[ClothInstanceTotal] BuildMergedAdjacency\n - topology and distance adjacency length differ");
|
||||
}
|
||||
int num = this.GlobalAdjacencyTopology.Length;
|
||||
this.GlobalAdjacencyMerged = new List<int>[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
List<int> list = new List<int>((this.GlobalAdjacencyTopology[i]?.Count ?? 0) + (this.GlobalAdjacencyDistance[i]?.Count ?? 0));
|
||||
HashSet<int> hashSet = new HashSet<int>();
|
||||
List<int> list2 = this.GlobalAdjacencyTopology[i];
|
||||
if (list2 != null)
|
||||
{
|
||||
for (int j = 0; j < list2.Count; j++)
|
||||
{
|
||||
int num2 = list2[j];
|
||||
if (num2 != i && hashSet.Add(num2))
|
||||
{
|
||||
list.Add(num2);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<int> list3 = this.GlobalAdjacencyDistance[i];
|
||||
if (list3 != null)
|
||||
{
|
||||
for (int k = 0; k < list3.Count; k++)
|
||||
{
|
||||
int num3 = list3[k];
|
||||
if (num3 != i && hashSet.Add(num3))
|
||||
{
|
||||
list.Add(num3);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.GlobalAdjacencyMerged[i] = list;
|
||||
}
|
||||
}
|
||||
|
||||
private int CalculateTotalVertexCount(List<ClothInstance> clothInstances)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i < clothInstances.Count; i++)
|
||||
{
|
||||
ClothInstance clothInstance = clothInstances[i];
|
||||
if (clothInstance != null && clothInstance.worldVertices != null)
|
||||
{
|
||||
num += clothInstance.worldVertices.Length;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
private int CalculateTotalVertexCount(List<ClothInstance> clothInstances)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i < clothInstances.Count; i++)
|
||||
{
|
||||
ClothInstance clothInstance = clothInstances[i];
|
||||
if (clothInstance != null && clothInstance.worldVertices != null)
|
||||
{
|
||||
num += clothInstance.worldVertices.Length;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
private List<int>[] BuildDistanceAdjacencyCandidatesInternal(Vector3[] referencePositions, float radius, int maxNeighborsPerVertex)
|
||||
{
|
||||
if (referencePositions == null || referencePositions.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Reference Positions are Missing", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidatesInternal\n - referencePositions is null or empty");
|
||||
}
|
||||
if (radius <= 0f)
|
||||
{
|
||||
throw new AutoMorpherException("Radius is Invalid", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidatesInternal\n - radius must be > 0");
|
||||
}
|
||||
int num = referencePositions.Length;
|
||||
List<int>[] array = new List<int>[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
array[i] = new List<int>(8);
|
||||
}
|
||||
float num2 = 1f / Mathf.Max(radius, 1E-12f);
|
||||
float num3 = radius * radius;
|
||||
Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>(num);
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
Vector3 vector = referencePositions[j];
|
||||
Vector3Int key = new Vector3Int(Mathf.FloorToInt(vector.x * num2), Mathf.FloorToInt(vector.y * num2), Mathf.FloorToInt(vector.z * num2));
|
||||
if (!dictionary.TryGetValue(key, out var value))
|
||||
{
|
||||
value = new List<int>(16);
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
value.Add(j);
|
||||
}
|
||||
for (int k = 0; k < num; k++)
|
||||
{
|
||||
Vector3 vector2 = referencePositions[k];
|
||||
Vector3Int vector3Int = new Vector3Int(Mathf.FloorToInt(vector2.x * num2), Mathf.FloorToInt(vector2.y * num2), Mathf.FloorToInt(vector2.z * num2));
|
||||
List<int> list = array[k];
|
||||
for (int l = -1; l <= 1; l++)
|
||||
{
|
||||
for (int m = -1; m <= 1; m++)
|
||||
{
|
||||
for (int n = -1; n <= 1; n++)
|
||||
{
|
||||
Vector3Int key2 = new Vector3Int(vector3Int.x + l, vector3Int.y + m, vector3Int.z + n);
|
||||
if (!dictionary.TryGetValue(key2, out var value2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int num4 = 0; num4 < value2.Count; num4++)
|
||||
{
|
||||
int num5 = value2[num4];
|
||||
if (num5 != k && !((referencePositions[num5] - vector2).sqrMagnitude > num3))
|
||||
{
|
||||
list.Add(num5);
|
||||
if (maxNeighborsPerVertex > 0 && list.Count >= maxNeighborsPerVertex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxNeighborsPerVertex > 0 && list.Count >= maxNeighborsPerVertex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
private List<int>[] BuildDistanceAdjacencyCandidatesInternal(Vector3[] referencePositions, float radius, int maxNeighborsPerVertex)
|
||||
{
|
||||
if (referencePositions == null || referencePositions.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Reference Positions are Missing", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidatesInternal\n - referencePositions is null or empty");
|
||||
}
|
||||
if (radius <= 0f)
|
||||
{
|
||||
throw new AutoMorpherException("Radius is Invalid", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidatesInternal\n - radius must be > 0");
|
||||
}
|
||||
int num = referencePositions.Length;
|
||||
List<int>[] array = new List<int>[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
array[i] = new List<int>(8);
|
||||
}
|
||||
float num2 = 1f / Mathf.Max(radius, 1E-12f);
|
||||
float num3 = radius * radius;
|
||||
Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>(num);
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
Vector3 vector = referencePositions[j];
|
||||
Vector3Int key = new Vector3Int(Mathf.FloorToInt(vector.x * num2), Mathf.FloorToInt(vector.y * num2), Mathf.FloorToInt(vector.z * num2));
|
||||
if (!dictionary.TryGetValue(key, out var value))
|
||||
{
|
||||
value = new List<int>(16);
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
value.Add(j);
|
||||
}
|
||||
for (int k = 0; k < num; k++)
|
||||
{
|
||||
Vector3 vector2 = referencePositions[k];
|
||||
Vector3Int vector3Int = new Vector3Int(Mathf.FloorToInt(vector2.x * num2), Mathf.FloorToInt(vector2.y * num2), Mathf.FloorToInt(vector2.z * num2));
|
||||
List<int> list = array[k];
|
||||
for (int l = -1; l <= 1; l++)
|
||||
{
|
||||
for (int m = -1; m <= 1; m++)
|
||||
{
|
||||
for (int n = -1; n <= 1; n++)
|
||||
{
|
||||
Vector3Int key2 = new Vector3Int(vector3Int.x + l, vector3Int.y + m, vector3Int.z + n);
|
||||
if (!dictionary.TryGetValue(key2, out var value2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int num4 = 0; num4 < value2.Count; num4++)
|
||||
{
|
||||
int num5 = value2[num4];
|
||||
if (num5 != k && !((referencePositions[num5] - vector2).sqrMagnitude > num3))
|
||||
{
|
||||
list.Add(num5);
|
||||
if (maxNeighborsPerVertex > 0 && list.Count >= maxNeighborsPerVertex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxNeighborsPerVertex > 0 && list.Count >= maxNeighborsPerVertex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,56 +1,55 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.EdenAutoMorpherConfig
|
||||
using System.Collections.Generic;
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public struct EdenAutoMorpherConfig
|
||||
{
|
||||
public GameObject sourceAvatarObject;
|
||||
public GameObject sourceAvatarObject;
|
||||
|
||||
public GameObject sourceClothesObject;
|
||||
public GameObject sourceClothesObject;
|
||||
|
||||
public IReadOnlyList<SkinnedMeshRenderer> sourceBodyMeshes;
|
||||
public IReadOnlyList<SkinnedMeshRenderer> sourceBodyMeshes;
|
||||
|
||||
public GameObject targetAvatarObject;
|
||||
public GameObject targetAvatarObject;
|
||||
|
||||
public GameObject targetClothesObject;
|
||||
public GameObject targetClothesObject;
|
||||
|
||||
public IReadOnlyList<SkinnedMeshRenderer> targetBodyMeshes;
|
||||
public IReadOnlyList<SkinnedMeshRenderer> targetBodyMeshes;
|
||||
|
||||
public string profileName;
|
||||
public string profileName;
|
||||
|
||||
public float minMargin;
|
||||
public float minMargin;
|
||||
|
||||
public float worldRadius;
|
||||
public float worldRadius;
|
||||
|
||||
public float sigma;
|
||||
public float sigma;
|
||||
|
||||
public int smoothingIteration;
|
||||
public int smoothingIteration;
|
||||
|
||||
public int fittingExpandIteration;
|
||||
public int fittingExpandIteration;
|
||||
|
||||
public int fittingShrinkIteration;
|
||||
public int fittingShrinkIteration;
|
||||
|
||||
public bool isBodyAutoSetup;
|
||||
public bool isBodyAutoSetup;
|
||||
|
||||
public bool isReparentAccessoryBonesToTargetAvatar;
|
||||
public bool isReparentAccessoryBonesToTargetAvatar;
|
||||
|
||||
public bool skipFootFitting;
|
||||
public bool skipFootFitting;
|
||||
|
||||
public bool isRemoveAutoMorphedClothes;
|
||||
public bool isRemoveAutoMorphedClothes;
|
||||
|
||||
public bool transferWeightToAvatar;
|
||||
public bool transferWeightToAvatar;
|
||||
|
||||
public bool addAnchorBone;
|
||||
public bool addAnchorBone;
|
||||
|
||||
public bool armatureBoneScaleCopy;
|
||||
public bool armatureBoneScaleCopy;
|
||||
|
||||
public Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones;
|
||||
public Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones;
|
||||
|
||||
public Dictionary<Transform, ClothBoneType> clothBoneTypeMap;
|
||||
public Dictionary<Transform, ClothBoneType> clothBoneTypeMap;
|
||||
|
||||
public string tagEdenMorpehrCloth;
|
||||
public string tagEdenMorpehrCloth;
|
||||
}
|
||||
|
||||
@@ -1,396 +1,395 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.EdenAutoMorpherManager
|
||||
using Eden.AutoMorpher;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Eden.AutoMorpher;
|
||||
using Eden.AutoMorpher.profile;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class EdenAutoMorpherManager : IDisposable
|
||||
{
|
||||
private string displayTitle;
|
||||
private string displayTitle;
|
||||
|
||||
private string displayText;
|
||||
private string displayText;
|
||||
|
||||
private float displayProgress;
|
||||
private float displayProgress;
|
||||
|
||||
private List<ClothInstance> clothInstances;
|
||||
private List<ClothInstance> clothInstances;
|
||||
|
||||
public (string, string, float) GetProgressInfo()
|
||||
{
|
||||
return (displayTitle, displayText, displayProgress);
|
||||
}
|
||||
public (string, string, float) GetProgressInfo()
|
||||
{
|
||||
return (this.displayTitle, this.displayText, this.displayProgress);
|
||||
}
|
||||
|
||||
private void SetupProgress(string title, string text, float progress)
|
||||
{
|
||||
displayTitle = title;
|
||||
displayText = text;
|
||||
displayProgress = progress;
|
||||
}
|
||||
private void SetupProgress(string title, string text, float progress)
|
||||
{
|
||||
this.displayTitle = title;
|
||||
this.displayText = text;
|
||||
this.displayProgress = progress;
|
||||
}
|
||||
|
||||
private IEnumerator SetupClothInstances(GameObject targetClothesObject, Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones, bool duplicateMesh = true)
|
||||
{
|
||||
clothInstances = new List<ClothInstance>();
|
||||
SkinnedMeshRenderer[] targetClothesSMRs = targetClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(includeInactive: false);
|
||||
if (targetClothesSMRs.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("There is NO Skinned Mesh Renderer in Clothes", "[EdenAutoMorpherManager] SetupClothInstance\n - There is NO Skinned Mesh Renderer in Clothes");
|
||||
}
|
||||
EdenAutoMorpher_SetUpUtil setupUtil = new EdenAutoMorpher_SetUpUtil();
|
||||
for (int rendereri = 0; rendereri < targetClothesSMRs.Length; rendereri++)
|
||||
{
|
||||
SetupProgress("Set Up", $"Setup Clothes Info [{rendereri}/{targetClothesSMRs.Length}] - ({targetClothesSMRs[rendereri].name})", Mathf.Lerp(0.05f, 0.1f, rendereri / targetClothesSMRs.Length));
|
||||
yield return null;
|
||||
ClothInstance clothInstance = setupUtil.SetupClothInstance(targetClothesSMRs[rendereri], clothesHumanoidMatchedBones, duplicateMesh);
|
||||
if (clothInstance != null)
|
||||
{
|
||||
clothInstances.Add(clothInstance);
|
||||
}
|
||||
}
|
||||
if (clothInstances.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.ClothInstanceAllocateFail"), LanguageManager.Get("UI.Exception.message.ClothInstanceAllocateFail"));
|
||||
}
|
||||
}
|
||||
private IEnumerator SetupClothInstances(GameObject targetClothesObject, Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones, bool duplicateMesh = true)
|
||||
{
|
||||
this.clothInstances = new List<ClothInstance>();
|
||||
SkinnedMeshRenderer[] targetClothesSMRs = targetClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(includeInactive: false);
|
||||
if (targetClothesSMRs.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("There is NO Skinned Mesh Renderer in Clothes", "[EdenAutoMorpherManager] SetupClothInstance\n - There is NO Skinned Mesh Renderer in Clothes");
|
||||
}
|
||||
EdenAutoMorpher_SetUpUtil setupUtil = new EdenAutoMorpher_SetUpUtil();
|
||||
for (int rendereri = 0; rendereri < targetClothesSMRs.Length; rendereri++)
|
||||
{
|
||||
this.SetupProgress("Set Up", $"Setup Clothes Info [{rendereri}/{targetClothesSMRs.Length}] - ({targetClothesSMRs[rendereri].name})", Mathf.Lerp(0.05f, 0.1f, rendereri / targetClothesSMRs.Length));
|
||||
yield return null;
|
||||
ClothInstance clothInstance = setupUtil.SetupClothInstance(targetClothesSMRs[rendereri], clothesHumanoidMatchedBones, duplicateMesh);
|
||||
if (clothInstance != null)
|
||||
{
|
||||
this.clothInstances.Add(clothInstance);
|
||||
}
|
||||
}
|
||||
if (this.clothInstances.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.ClothInstanceAllocateFail"), LanguageManager.Get("UI.Exception.message.ClothInstanceAllocateFail"));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator SetupClothInstances(GameObject targetClothesObject, Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones, GameObject sourceClothesObject, MeshMatcher meshMatcher)
|
||||
{
|
||||
clothInstances = new List<ClothInstance>();
|
||||
SkinnedMeshRenderer[] targetClothesSMRs = targetClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(includeInactive: false);
|
||||
if (targetClothesSMRs.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("There is NO Skinned Mesh Renderer in Clothes", "[EdenAutoMorpherManager] SetupClothInstance\n - There is NO Skinned Mesh Renderer in Clothes");
|
||||
}
|
||||
SkinnedMeshRenderer[] sourceClothesSMRs = sourceClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(includeInactive: false);
|
||||
if (sourceClothesSMRs.Length == 0 || targetClothesSMRs.Length != sourceClothesSMRs.Length)
|
||||
{
|
||||
throw new AutoMorpherException("Clothes Skinned Mesh Renderer is Not Matched", "[EdenAutoMorpherManager] SetupClothInstance\n - Skinned Mesh Renderer of Source Clothes and Target Clothes is Not Matched");
|
||||
}
|
||||
EdenAutoMorpher_SetUpUtil setupUtil = new EdenAutoMorpher_SetUpUtil();
|
||||
for (int rendereri = 0; rendereri < targetClothesSMRs.Length; rendereri++)
|
||||
{
|
||||
SetupProgress("Set Up", $"Setup Clothes Info [{rendereri}/{targetClothesSMRs.Length}] - ({targetClothesSMRs[rendereri].name})", Mathf.Lerp(0.07f, 0.1f, rendereri / targetClothesSMRs.Length));
|
||||
yield return null;
|
||||
ClothInstance clothInstance = setupUtil.SetupClothInstance(targetClothesSMRs[rendereri], sourceClothesSMRs[rendereri], meshMatcher, clothesHumanoidMatchedBones, duplicateMesh: true);
|
||||
if (clothInstance != null)
|
||||
{
|
||||
clothInstances.Add(clothInstance);
|
||||
}
|
||||
}
|
||||
if (clothInstances.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.ClothInstanceAllocateFail"), LanguageManager.Get("UI.Exception.message.ClothInstanceAllocateFail"));
|
||||
}
|
||||
}
|
||||
private IEnumerator SetupClothInstances(GameObject targetClothesObject, Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones, GameObject sourceClothesObject, MeshMatcher meshMatcher)
|
||||
{
|
||||
this.clothInstances = new List<ClothInstance>();
|
||||
SkinnedMeshRenderer[] targetClothesSMRs = targetClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(includeInactive: false);
|
||||
if (targetClothesSMRs.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("There is NO Skinned Mesh Renderer in Clothes", "[EdenAutoMorpherManager] SetupClothInstance\n - There is NO Skinned Mesh Renderer in Clothes");
|
||||
}
|
||||
SkinnedMeshRenderer[] sourceClothesSMRs = sourceClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(includeInactive: false);
|
||||
if (sourceClothesSMRs.Length == 0 || targetClothesSMRs.Length != sourceClothesSMRs.Length)
|
||||
{
|
||||
throw new AutoMorpherException("Clothes Skinned Mesh Renderer is Not Matched", "[EdenAutoMorpherManager] SetupClothInstance\n - Skinned Mesh Renderer of Source Clothes and Target Clothes is Not Matched");
|
||||
}
|
||||
EdenAutoMorpher_SetUpUtil setupUtil = new EdenAutoMorpher_SetUpUtil();
|
||||
for (int rendereri = 0; rendereri < targetClothesSMRs.Length; rendereri++)
|
||||
{
|
||||
this.SetupProgress("Set Up", $"Setup Clothes Info [{rendereri}/{targetClothesSMRs.Length}] - ({targetClothesSMRs[rendereri].name})", Mathf.Lerp(0.07f, 0.1f, rendereri / targetClothesSMRs.Length));
|
||||
yield return null;
|
||||
ClothInstance clothInstance = setupUtil.SetupClothInstance(targetClothesSMRs[rendereri], sourceClothesSMRs[rendereri], meshMatcher, clothesHumanoidMatchedBones, duplicateMesh: true);
|
||||
if (clothInstance != null)
|
||||
{
|
||||
this.clothInstances.Add(clothInstance);
|
||||
}
|
||||
}
|
||||
if (this.clothInstances.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.ClothInstanceAllocateFail"), LanguageManager.Get("UI.Exception.message.ClothInstanceAllocateFail"));
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator FittingIteration(EdenAutoMorpherConfig config, MorpherMode morpherMode)
|
||||
{
|
||||
SetupProgress("Set Up", "Setup Target Avatar Info", 0.03f);
|
||||
yield return null;
|
||||
MeshMatcher meshMatcher = new MeshMatcher();
|
||||
BvhTriangleMesh targetBodyBVH = meshMatcher.BuildBvhMulti(config.targetBodyMeshes, config.targetAvatarObject.GetComponent<Animator>());
|
||||
if (targetBodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("targetBodyBVH is Null", "[EdenAutoMorpherManater] FittingIteration\n - targetBodyBVH is null");
|
||||
}
|
||||
yield return null;
|
||||
SetupProgress("Set Up", "Setup Source Avatar Info", 0.05f);
|
||||
yield return null;
|
||||
BvhTriangleMesh sourceBodyBVH = null;
|
||||
switch (morpherMode)
|
||||
{
|
||||
case MorpherMode.AutoMorpher:
|
||||
case MorpherMode.ManualMorpher:
|
||||
sourceBodyBVH = meshMatcher.BuildBvhMulti(config.sourceBodyMeshes, config.sourceAvatarObject.GetComponent<Animator>());
|
||||
break;
|
||||
case MorpherMode.ProfileMorpher:
|
||||
{
|
||||
ProfileLoader profileLoader = new ProfileLoader();
|
||||
sourceBodyBVH = profileLoader.LoadBvhWithRootTransform(config.sourceClothesObject.transform, config.profileName);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Debug.LogError("Unknown MorpherMode");
|
||||
break;
|
||||
}
|
||||
yield return null;
|
||||
if (sourceBodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("sourceBodyBVH is Null", "[EdenAutoMorpherManater] FittingIteration\n - sourceBodyBVH is null");
|
||||
}
|
||||
meshMatcher.bodyBVH = sourceBodyBVH;
|
||||
SetupProgress("Set Up", "Setup Clothes Info", 0.07f);
|
||||
yield return null;
|
||||
IEnumerator setupClothEnum = SetupClothInstances(config.targetClothesObject, config.clothesHumanoidMatchedBones, config.sourceClothesObject, meshMatcher);
|
||||
while (setupClothEnum.MoveNext())
|
||||
{
|
||||
yield return setupClothEnum.Current;
|
||||
}
|
||||
yield return null;
|
||||
float fittingRadius = config.worldRadius;
|
||||
meshMatcher.bodyBVH = targetBodyBVH;
|
||||
VertexFittingUtil vertexFittingUtil = new VertexFittingUtil();
|
||||
int fittingI;
|
||||
for (fittingI = 0; fittingI < config.fittingExpandIteration; fittingI++)
|
||||
{
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
{
|
||||
SetupProgress("Fitting", $"Phase 1 Expanding [{fittingI + 1}/{config.fittingExpandIteration}] - {clothInstance.smr.transform.name}", Mathf.Lerp(0.1f, 0.4f, (float)fittingI / (float)config.fittingExpandIteration));
|
||||
yield return null;
|
||||
vertexFittingUtil.ExpandClothes_World(clothInstance, clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return null;
|
||||
}
|
||||
if (fittingI % 2 == 0)
|
||||
{
|
||||
fittingRadius *= 0.97f;
|
||||
}
|
||||
}
|
||||
fittingRadius = config.worldRadius;
|
||||
for (fittingI = 0; fittingI < config.fittingShrinkIteration; fittingI++)
|
||||
{
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
{
|
||||
SetupProgress("Fitting", $"Phase 2 Fitting [{fittingI + 1}/{config.fittingShrinkIteration}] - {clothInstance.smr.transform.name}", Mathf.Lerp(0.4f, 0.8f, (float)fittingI / (float)config.fittingShrinkIteration));
|
||||
yield return null;
|
||||
vertexFittingUtil.ShrinkClothes_World(clothInstance, clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return null;
|
||||
vertexFittingUtil.ExpandClothes_World(clothInstance, clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return null;
|
||||
}
|
||||
if (fittingI % 2 == 0)
|
||||
{
|
||||
fittingRadius *= 0.97f;
|
||||
}
|
||||
}
|
||||
fittingRadius = config.worldRadius / 2f;
|
||||
for (fittingI = 0; fittingI < config.fittingExpandIteration; fittingI++)
|
||||
{
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
{
|
||||
SetupProgress("Fitting", $"Phase 3 Fine-tuning [{fittingI + 1}/{config.fittingExpandIteration}] - {clothInstance.smr.transform.name}", Mathf.Lerp(0.8f, 0.9f, (float)fittingI / (float)config.fittingExpandIteration));
|
||||
yield return null;
|
||||
vertexFittingUtil.ExpandClothes_World(clothInstance, clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return null;
|
||||
}
|
||||
if (fittingI % 2 == 0)
|
||||
{
|
||||
fittingRadius *= 0.97f;
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
SetupProgress("Fitting", "Apply Transform Bone", 0.93f);
|
||||
yield return null;
|
||||
BoneAlignmentUtil boneAlignmentUtil = new BoneAlignmentUtil();
|
||||
boneAlignmentUtil.CleanupTempBones(config.targetClothesObject.transform);
|
||||
MorpherMode morpherMode2 = morpherMode;
|
||||
if (morpherMode2 == MorpherMode.AutoMorpher || morpherMode2 == MorpherMode.ProfileMorpher)
|
||||
{
|
||||
config.targetClothesObject.transform.localScale = Vector3.one;
|
||||
boneAlignmentUtil.AlignClothBonesToAvatar(clothInstances[0], config.targetAvatarObject.GetComponent<Animator>());
|
||||
}
|
||||
yield return null;
|
||||
SetupProgress("Fitting", "Apply Transform Mesh", 0.99f);
|
||||
yield return null;
|
||||
fittingI = 0;
|
||||
while (fittingI < clothInstances.Count)
|
||||
{
|
||||
ClothInstance clothInstance = clothInstances[fittingI];
|
||||
SetupProgress("Fitting", $"Apply to Mesh [{fittingI + 1}/{clothInstances.Count}] - {clothInstance.smr.transform.name}", Mathf.Lerp(0.93f, 0.98f, (float)fittingI / (float)clothInstances.Count));
|
||||
yield return null;
|
||||
clothInstance.ApplyWorldVerticesToMesh();
|
||||
clothInstance.smr.localBounds = new Bounds(Vector3.zero, Vector3.one * 2f);
|
||||
EditorUtility.SetDirty(clothInstance.smr.sharedMesh);
|
||||
EditorUtility.SetDirty(clothInstance.smr);
|
||||
yield return null;
|
||||
int num = fittingI + 1;
|
||||
fittingI = num;
|
||||
}
|
||||
yield return null;
|
||||
SetupProgress("Saving", "Saving Mesh Data", 0.99f);
|
||||
yield return null;
|
||||
SaveEditedMeshesToAssets(clothInstances, config);
|
||||
yield return null;
|
||||
SetupProgress("Finishing", "Finishing", 1f);
|
||||
foreach (ClothInstance clothInstance2 in clothInstances)
|
||||
{
|
||||
clothInstance2.Dispose();
|
||||
}
|
||||
clothInstances = null;
|
||||
yield return null;
|
||||
}
|
||||
public IEnumerator FittingIteration(EdenAutoMorpherConfig config, MorpherMode morpherMode)
|
||||
{
|
||||
this.SetupProgress("Set Up", "Setup Target Avatar Info", 0.03f);
|
||||
yield return null;
|
||||
MeshMatcher meshMatcher = new MeshMatcher();
|
||||
BvhTriangleMesh targetBodyBVH = meshMatcher.BuildBvhMulti(config.targetBodyMeshes, config.targetAvatarObject.GetComponent<Animator>());
|
||||
if (targetBodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("targetBodyBVH is Null", "[EdenAutoMorpherManater] FittingIteration\n - targetBodyBVH is null");
|
||||
}
|
||||
yield return null;
|
||||
this.SetupProgress("Set Up", "Setup Source Avatar Info", 0.05f);
|
||||
yield return null;
|
||||
BvhTriangleMesh sourceBodyBVH = null;
|
||||
switch (morpherMode)
|
||||
{
|
||||
case MorpherMode.AutoMorpher:
|
||||
case MorpherMode.ManualMorpher:
|
||||
sourceBodyBVH = meshMatcher.BuildBvhMulti(config.sourceBodyMeshes, config.sourceAvatarObject.GetComponent<Animator>());
|
||||
break;
|
||||
case MorpherMode.ProfileMorpher:
|
||||
{
|
||||
ProfileLoader profileLoader = new ProfileLoader();
|
||||
sourceBodyBVH = profileLoader.LoadBvhWithRootTransform(config.sourceClothesObject.transform, config.profileName);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Debug.LogError("Unknown MorpherMode");
|
||||
break;
|
||||
}
|
||||
yield return null;
|
||||
if (sourceBodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("sourceBodyBVH is Null", "[EdenAutoMorpherManater] FittingIteration\n - sourceBodyBVH is null");
|
||||
}
|
||||
meshMatcher.bodyBVH = sourceBodyBVH;
|
||||
this.SetupProgress("Set Up", "Setup Clothes Info", 0.07f);
|
||||
yield return null;
|
||||
IEnumerator setupClothEnum = this.SetupClothInstances(config.targetClothesObject, config.clothesHumanoidMatchedBones, config.sourceClothesObject, meshMatcher);
|
||||
while (setupClothEnum.MoveNext())
|
||||
{
|
||||
yield return setupClothEnum.Current;
|
||||
}
|
||||
yield return null;
|
||||
float fittingRadius = config.worldRadius;
|
||||
meshMatcher.bodyBVH = targetBodyBVH;
|
||||
VertexFittingUtil vertexFittingUtil = new VertexFittingUtil();
|
||||
int fittingI;
|
||||
for (fittingI = 0; fittingI < config.fittingExpandIteration; fittingI++)
|
||||
{
|
||||
foreach (ClothInstance clothInstance in this.clothInstances)
|
||||
{
|
||||
this.SetupProgress("Fitting", $"Phase 1 Expanding [{fittingI + 1}/{config.fittingExpandIteration}] - {clothInstance.smr.transform.name}", Mathf.Lerp(0.1f, 0.4f, (float)fittingI / (float)config.fittingExpandIteration));
|
||||
yield return null;
|
||||
vertexFittingUtil.ExpandClothes_World(clothInstance, this.clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return null;
|
||||
}
|
||||
if (fittingI % 2 == 0)
|
||||
{
|
||||
fittingRadius *= 0.97f;
|
||||
}
|
||||
}
|
||||
fittingRadius = config.worldRadius;
|
||||
for (fittingI = 0; fittingI < config.fittingShrinkIteration; fittingI++)
|
||||
{
|
||||
foreach (ClothInstance clothInstance in this.clothInstances)
|
||||
{
|
||||
this.SetupProgress("Fitting", $"Phase 2 Fitting [{fittingI + 1}/{config.fittingShrinkIteration}] - {clothInstance.smr.transform.name}", Mathf.Lerp(0.4f, 0.8f, (float)fittingI / (float)config.fittingShrinkIteration));
|
||||
yield return null;
|
||||
vertexFittingUtil.ShrinkClothes_World(clothInstance, this.clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return null;
|
||||
vertexFittingUtil.ExpandClothes_World(clothInstance, this.clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return null;
|
||||
}
|
||||
if (fittingI % 2 == 0)
|
||||
{
|
||||
fittingRadius *= 0.97f;
|
||||
}
|
||||
}
|
||||
fittingRadius = config.worldRadius / 2f;
|
||||
for (fittingI = 0; fittingI < config.fittingExpandIteration; fittingI++)
|
||||
{
|
||||
foreach (ClothInstance clothInstance in this.clothInstances)
|
||||
{
|
||||
this.SetupProgress("Fitting", $"Phase 3 Fine-tuning [{fittingI + 1}/{config.fittingExpandIteration}] - {clothInstance.smr.transform.name}", Mathf.Lerp(0.8f, 0.9f, (float)fittingI / (float)config.fittingExpandIteration));
|
||||
yield return null;
|
||||
vertexFittingUtil.ExpandClothes_World(clothInstance, this.clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return null;
|
||||
}
|
||||
if (fittingI % 2 == 0)
|
||||
{
|
||||
fittingRadius *= 0.97f;
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
this.SetupProgress("Fitting", "Apply Transform Bone", 0.93f);
|
||||
yield return null;
|
||||
BoneAlignmentUtil boneAlignmentUtil = new BoneAlignmentUtil();
|
||||
boneAlignmentUtil.CleanupTempBones(config.targetClothesObject.transform);
|
||||
MorpherMode morpherMode2 = morpherMode;
|
||||
if (morpherMode2 == MorpherMode.AutoMorpher || morpherMode2 == MorpherMode.ProfileMorpher)
|
||||
{
|
||||
config.targetClothesObject.transform.localScale = Vector3.one;
|
||||
boneAlignmentUtil.AlignClothBonesToAvatar(this.clothInstances[0], config.targetAvatarObject.GetComponent<Animator>());
|
||||
}
|
||||
yield return null;
|
||||
this.SetupProgress("Fitting", "Apply Transform Mesh", 0.99f);
|
||||
yield return null;
|
||||
fittingI = 0;
|
||||
while (fittingI < this.clothInstances.Count)
|
||||
{
|
||||
ClothInstance clothInstance = this.clothInstances[fittingI];
|
||||
this.SetupProgress("Fitting", $"Apply to Mesh [{fittingI + 1}/{this.clothInstances.Count}] - {clothInstance.smr.transform.name}", Mathf.Lerp(0.93f, 0.98f, (float)fittingI / (float)this.clothInstances.Count));
|
||||
yield return null;
|
||||
clothInstance.ApplyWorldVerticesToMesh();
|
||||
clothInstance.smr.localBounds = new Bounds(Vector3.zero, Vector3.one * 2f);
|
||||
EditorUtility.SetDirty(clothInstance.smr.sharedMesh);
|
||||
EditorUtility.SetDirty(clothInstance.smr);
|
||||
yield return null;
|
||||
int num = fittingI + 1;
|
||||
fittingI = num;
|
||||
}
|
||||
yield return null;
|
||||
this.SetupProgress("Saving", "Saving Mesh Data", 0.99f);
|
||||
yield return null;
|
||||
this.SaveEditedMeshesToAssets(this.clothInstances, config);
|
||||
yield return null;
|
||||
this.SetupProgress("Finishing", "Finishing", 1f);
|
||||
foreach (ClothInstance clothInstance2 in this.clothInstances)
|
||||
{
|
||||
clothInstance2.Dispose();
|
||||
}
|
||||
this.clothInstances = null;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
public IEnumerator WeightingEnumerator(EdenAutoMorpherConfig config)
|
||||
{
|
||||
SetupProgress("Set Up", "Setup Target Avatar Info", 0f);
|
||||
yield return null;
|
||||
if (new MeshMatcher().BuildBvhMulti(config.targetBodyMeshes, config.targetAvatarObject.GetComponent<Animator>()) == null)
|
||||
{
|
||||
throw new AutoMorpherException("targetBodyBVH is Null", "[EdenAutoMorpherManater] FittingIteration\n - targetBodyBVH is null");
|
||||
}
|
||||
yield return null;
|
||||
List<Mesh> bakedTargetBodyMeshes = new List<Mesh>();
|
||||
foreach (SkinnedMeshRenderer bodyMesh in config.targetBodyMeshes)
|
||||
{
|
||||
SetupProgress("Set Up", "Setup Target Avatar BodyMesh Info", Mathf.Lerp(0.02f, 0.05f, bakedTargetBodyMeshes.Count / config.targetBodyMeshes.Count));
|
||||
yield return null;
|
||||
Mesh mesh = new Mesh();
|
||||
bodyMesh.BakeMesh(mesh);
|
||||
mesh.triangles = bodyMesh.sharedMesh.triangles;
|
||||
mesh.boneWeights = bodyMesh.sharedMesh.boneWeights;
|
||||
bakedTargetBodyMeshes.Add(mesh);
|
||||
}
|
||||
yield return null;
|
||||
IEnumerator setupClothEnum = SetupClothInstances(config.targetClothesObject, config.clothesHumanoidMatchedBones, duplicateMesh: false);
|
||||
while (setupClothEnum.MoveNext())
|
||||
{
|
||||
yield return setupClothEnum.Current;
|
||||
}
|
||||
yield return null;
|
||||
Dictionary<Transform, Transform> clonedBoneMap = null;
|
||||
if (!config.transferWeightToAvatar)
|
||||
{
|
||||
new EdenAutoMorpher_SetUpUtil().CreateClothesArmature(config, out clonedBoneMap);
|
||||
}
|
||||
yield return null;
|
||||
WeightTransferUtil weightTransferUtil = new WeightTransferUtil();
|
||||
WeightTransferUtil.Settings wtSettings = new WeightTransferUtil.Settings
|
||||
{
|
||||
maxDistance = 0.07f,
|
||||
maxNormalAngleDeg = 35f,
|
||||
allowFlippedNormal = true,
|
||||
enableSmoothing = true,
|
||||
smoothingIterations = 4,
|
||||
smoothingAlpha = 0.25f,
|
||||
enforceFourBoneLimit = true,
|
||||
weightInClothes = !config.transferWeightToAvatar
|
||||
};
|
||||
yield return null;
|
||||
int weightingI = 0;
|
||||
while (weightingI < clothInstances.Count)
|
||||
{
|
||||
ClothInstance clothInstance = clothInstances[weightingI];
|
||||
float num = 0.1f;
|
||||
float num2 = (0.95f - num) / (float)Mathf.Max(1, clothInstances.Count);
|
||||
float num3 = num + num2 * (float)weightingI;
|
||||
float num4 = 0.8f;
|
||||
float weightingStart = num3;
|
||||
float weightingEnd = num3 + num2 * num4;
|
||||
float applyStart = num3 + num2 * num4;
|
||||
int step = 1;
|
||||
SetupProgress("Weighting", $"Weighting | Step {step} [{weightingI + 1}/{clothInstances.Count}] - {clothInstance.smr.transform.name}", weightingStart);
|
||||
yield return null;
|
||||
IEnumerator weightingEnum = weightTransferUtil.RetargetAndTransfer(clothInstance, config.targetAvatarObject.GetComponent<Animator>(), config.targetBodyMeshes, bakedTargetBodyMeshes, 0, wtSettings, config.clothBoneTypeMap, clonedBoneMap);
|
||||
while (weightingEnum.MoveNext())
|
||||
{
|
||||
yield return null;
|
||||
step++;
|
||||
float t = 1f - 1f / ((float)step + 1f);
|
||||
float progress = Mathf.Lerp(weightingStart, weightingEnd, t);
|
||||
SetupProgress("Weighting", $"Weighting | Step {step} [{weightingI + 1}/{clothInstances.Count}] - {clothInstance.smr.transform.name}", progress);
|
||||
yield return weightingEnum.Current;
|
||||
}
|
||||
yield return null;
|
||||
step++;
|
||||
SetupProgress("Weighting", $"Weighting | Step {step} - Apply to Mesh [{weightingI + 1}/{clothInstances.Count}] - {clothInstance.smr.transform.name}", applyStart);
|
||||
yield return null;
|
||||
clothInstance.ApplyWorldVerticesToMesh();
|
||||
clothInstance.smr.localBounds = new Bounds(Vector3.zero, Vector3.one * 2f);
|
||||
EditorUtility.SetDirty(clothInstance.smr.sharedMesh);
|
||||
EditorUtility.SetDirty(clothInstance.smr);
|
||||
yield return null;
|
||||
int num5 = weightingI + 1;
|
||||
weightingI = num5;
|
||||
}
|
||||
SetupProgress("Weighting", "Allocate Bones", 0.95f);
|
||||
yield return null;
|
||||
if (config.transferWeightToAvatar && config.isReparentAccessoryBonesToTargetAvatar)
|
||||
{
|
||||
new BoneAlignmentUtil().ReparentAccessoryBonesToAvatar(config);
|
||||
}
|
||||
SetupProgress("Finishing", "Finishing", 1f);
|
||||
yield return null;
|
||||
foreach (ClothInstance clothInstance2 in clothInstances)
|
||||
{
|
||||
clothInstance2.Dispose();
|
||||
}
|
||||
clothInstances = null;
|
||||
yield return null;
|
||||
}
|
||||
public IEnumerator WeightingEnumerator(EdenAutoMorpherConfig config)
|
||||
{
|
||||
this.SetupProgress("Set Up", "Setup Target Avatar Info", 0f);
|
||||
yield return null;
|
||||
if (new MeshMatcher().BuildBvhMulti(config.targetBodyMeshes, config.targetAvatarObject.GetComponent<Animator>()) == null)
|
||||
{
|
||||
throw new AutoMorpherException("targetBodyBVH is Null", "[EdenAutoMorpherManater] FittingIteration\n - targetBodyBVH is null");
|
||||
}
|
||||
yield return null;
|
||||
List<Mesh> bakedTargetBodyMeshes = new List<Mesh>();
|
||||
foreach (SkinnedMeshRenderer bodyMesh in config.targetBodyMeshes)
|
||||
{
|
||||
this.SetupProgress("Set Up", "Setup Target Avatar BodyMesh Info", Mathf.Lerp(0.02f, 0.05f, bakedTargetBodyMeshes.Count / config.targetBodyMeshes.Count));
|
||||
yield return null;
|
||||
Mesh mesh = new Mesh();
|
||||
bodyMesh.BakeMesh(mesh);
|
||||
mesh.triangles = bodyMesh.sharedMesh.triangles;
|
||||
mesh.boneWeights = bodyMesh.sharedMesh.boneWeights;
|
||||
bakedTargetBodyMeshes.Add(mesh);
|
||||
}
|
||||
yield return null;
|
||||
IEnumerator setupClothEnum = this.SetupClothInstances(config.targetClothesObject, config.clothesHumanoidMatchedBones, duplicateMesh: false);
|
||||
while (setupClothEnum.MoveNext())
|
||||
{
|
||||
yield return setupClothEnum.Current;
|
||||
}
|
||||
yield return null;
|
||||
Dictionary<Transform, Transform> clonedBoneMap = null;
|
||||
if (!config.transferWeightToAvatar)
|
||||
{
|
||||
new EdenAutoMorpher_SetUpUtil().CreateClothesArmature(config, out clonedBoneMap);
|
||||
}
|
||||
yield return null;
|
||||
WeightTransferUtil weightTransferUtil = new WeightTransferUtil();
|
||||
WeightTransferUtil.Settings wtSettings = new WeightTransferUtil.Settings
|
||||
{
|
||||
maxDistance = 0.07f,
|
||||
maxNormalAngleDeg = 35f,
|
||||
allowFlippedNormal = true,
|
||||
enableSmoothing = true,
|
||||
smoothingIterations = 4,
|
||||
smoothingAlpha = 0.25f,
|
||||
enforceFourBoneLimit = true,
|
||||
weightInClothes = !config.transferWeightToAvatar
|
||||
};
|
||||
yield return null;
|
||||
int weightingI = 0;
|
||||
while (weightingI < this.clothInstances.Count)
|
||||
{
|
||||
ClothInstance clothInstance = this.clothInstances[weightingI];
|
||||
float num = 0.1f;
|
||||
float num2 = (0.95f - num) / (float)Mathf.Max(1, this.clothInstances.Count);
|
||||
float num3 = num + num2 * (float)weightingI;
|
||||
float num4 = 0.8f;
|
||||
float weightingStart = num3;
|
||||
float weightingEnd = num3 + num2 * num4;
|
||||
float applyStart = num3 + num2 * num4;
|
||||
int step = 1;
|
||||
this.SetupProgress("Weighting", $"Weighting | Step {step} [{weightingI + 1}/{this.clothInstances.Count}] - {clothInstance.smr.transform.name}", weightingStart);
|
||||
yield return null;
|
||||
IEnumerator weightingEnum = weightTransferUtil.RetargetAndTransfer(clothInstance, config.targetAvatarObject.GetComponent<Animator>(), config.targetBodyMeshes, bakedTargetBodyMeshes, 0, wtSettings, config.clothBoneTypeMap, clonedBoneMap);
|
||||
while (weightingEnum.MoveNext())
|
||||
{
|
||||
yield return null;
|
||||
step++;
|
||||
float t = 1f - 1f / ((float)step + 1f);
|
||||
float progress = Mathf.Lerp(weightingStart, weightingEnd, t);
|
||||
this.SetupProgress("Weighting", $"Weighting | Step {step} [{weightingI + 1}/{this.clothInstances.Count}] - {clothInstance.smr.transform.name}", progress);
|
||||
yield return weightingEnum.Current;
|
||||
}
|
||||
yield return null;
|
||||
step++;
|
||||
this.SetupProgress("Weighting", $"Weighting | Step {step} - Apply to Mesh [{weightingI + 1}/{this.clothInstances.Count}] - {clothInstance.smr.transform.name}", applyStart);
|
||||
yield return null;
|
||||
clothInstance.ApplyWorldVerticesToMesh();
|
||||
clothInstance.smr.localBounds = new Bounds(Vector3.zero, Vector3.one * 2f);
|
||||
EditorUtility.SetDirty(clothInstance.smr.sharedMesh);
|
||||
EditorUtility.SetDirty(clothInstance.smr);
|
||||
yield return null;
|
||||
int num5 = weightingI + 1;
|
||||
weightingI = num5;
|
||||
}
|
||||
this.SetupProgress("Weighting", "Allocate Bones", 0.95f);
|
||||
yield return null;
|
||||
if (config.transferWeightToAvatar && config.isReparentAccessoryBonesToTargetAvatar)
|
||||
{
|
||||
new BoneAlignmentUtil().ReparentAccessoryBonesToAvatar(config);
|
||||
}
|
||||
this.SetupProgress("Finishing", "Finishing", 1f);
|
||||
yield return null;
|
||||
foreach (ClothInstance clothInstance2 in this.clothInstances)
|
||||
{
|
||||
clothInstance2.Dispose();
|
||||
}
|
||||
this.clothInstances = null;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
private void SaveEditedMeshesToAssets(List<ClothInstance> clothInstances, EdenAutoMorpherConfig config)
|
||||
{
|
||||
if (clothInstances == null || clothInstances.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[EdenAutoMorpher] 저장할 ClothInstance가 없습니다.");
|
||||
throw new AutoMorpherException("Can't Save Mesh", "Therer is no ClothInstance to save mesh");
|
||||
}
|
||||
if (config.targetClothesObject == null || config.targetAvatarObject == null)
|
||||
{
|
||||
Debug.LogWarning("[EdenAutoMorpher] targetClothesObject 또는 targetAvatarObject 가 null 입니다. 메쉬 저장 경로를 만들 수 없습니다.");
|
||||
throw new AutoMorpherException("Can't Save Mesh", "Target Clothes Object or Target Avatar Object is null.\nCan't Create Mesh Folder");
|
||||
}
|
||||
string text = "Assets/@Eden_Mesh";
|
||||
if (!AssetDatabase.IsValidFolder(text))
|
||||
{
|
||||
AssetDatabase.CreateFolder("Assets", "@Eden_Mesh");
|
||||
}
|
||||
string text2 = SanitizeForAssetName(config.targetAvatarObject.name);
|
||||
string text3 = text + "/" + text2;
|
||||
if (!AssetDatabase.IsValidFolder(text3))
|
||||
{
|
||||
AssetDatabase.CreateFolder(text, text2);
|
||||
}
|
||||
string text4 = SanitizeForAssetName(config.targetClothesObject.name);
|
||||
string text5 = text3 + "/" + text4;
|
||||
if (!AssetDatabase.IsValidFolder(text5))
|
||||
{
|
||||
AssetDatabase.CreateFolder(text3, text4);
|
||||
}
|
||||
string text6 = AssetDatabase.GenerateUniqueAssetPath(text5 + "/" + text4 + "_Meshes.asset");
|
||||
int num = 0;
|
||||
AssetDatabase.CreateAsset(new Mesh
|
||||
{
|
||||
name = text4 + "_RootMesh"
|
||||
}, text6);
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
{
|
||||
if (clothInstance != null && !(clothInstance.smr == null))
|
||||
{
|
||||
Mesh sharedMesh = clothInstance.smr.sharedMesh;
|
||||
if (!(sharedMesh == null))
|
||||
{
|
||||
Mesh mesh = UnityEngine.Object.Instantiate(sharedMesh);
|
||||
mesh.name = SanitizeForAssetName(clothInstance.smr.gameObject.name + "_EditedMesh");
|
||||
AssetDatabase.AddObjectToAsset(mesh, text6);
|
||||
clothInstance.smr.sharedMesh = mesh;
|
||||
clothInstance.editableMesh = clothInstance.smr.sharedMesh;
|
||||
EditorUtility.SetDirty(clothInstance.smr);
|
||||
EditorUtility.SetDirty(clothInstance.smr.sharedMesh);
|
||||
EditorUtility.SetDirty(clothInstance.smr.gameObject);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log($"[EdenAutoMorpher] 편집된 메쉬 {num}개를 " + "'" + text6 + "' 에 서브 에셋으로 저장했습니다. (원본 프리팹은 변경하지 않음)");
|
||||
static string SanitizeForAssetName(string rawName)
|
||||
{
|
||||
char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
|
||||
foreach (char oldChar in invalidFileNameChars)
|
||||
{
|
||||
rawName = rawName.Replace(oldChar, '_');
|
||||
}
|
||||
return rawName.Trim();
|
||||
}
|
||||
}
|
||||
private void SaveEditedMeshesToAssets(List<ClothInstance> clothInstances, EdenAutoMorpherConfig config)
|
||||
{
|
||||
if (clothInstances == null || clothInstances.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("[EdenAutoMorpher] 저장할 ClothInstance가 없습니다.");
|
||||
throw new AutoMorpherException("Can't Save Mesh", "Therer is no ClothInstance to save mesh");
|
||||
}
|
||||
if (config.targetClothesObject == null || config.targetAvatarObject == null)
|
||||
{
|
||||
Debug.LogWarning("[EdenAutoMorpher] targetClothesObject 또는 targetAvatarObject 가 null 입니다. 메쉬 저장 경로를 만들 수 없습니다.");
|
||||
throw new AutoMorpherException("Can't Save Mesh", "Target Clothes Object or Target Avatar Object is null.\nCan't Create Mesh Folder");
|
||||
}
|
||||
string text = "Assets/@Eden_Mesh";
|
||||
if (!AssetDatabase.IsValidFolder(text))
|
||||
{
|
||||
AssetDatabase.CreateFolder("Assets", "@Eden_Mesh");
|
||||
}
|
||||
string text2 = SanitizeForAssetName(config.targetAvatarObject.name);
|
||||
string text3 = text + "/" + text2;
|
||||
if (!AssetDatabase.IsValidFolder(text3))
|
||||
{
|
||||
AssetDatabase.CreateFolder(text, text2);
|
||||
}
|
||||
string text4 = SanitizeForAssetName(config.targetClothesObject.name);
|
||||
string text5 = text3 + "/" + text4;
|
||||
if (!AssetDatabase.IsValidFolder(text5))
|
||||
{
|
||||
AssetDatabase.CreateFolder(text3, text4);
|
||||
}
|
||||
string text6 = AssetDatabase.GenerateUniqueAssetPath(text5 + "/" + text4 + "_Meshes.asset");
|
||||
int num = 0;
|
||||
AssetDatabase.CreateAsset(new Mesh
|
||||
{
|
||||
name = text4 + "_RootMesh"
|
||||
}, text6);
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
{
|
||||
if (clothInstance != null && !(clothInstance.smr == null))
|
||||
{
|
||||
Mesh sharedMesh = clothInstance.smr.sharedMesh;
|
||||
if (!(sharedMesh == null))
|
||||
{
|
||||
Mesh mesh = UnityEngine.Object.Instantiate(sharedMesh);
|
||||
mesh.name = SanitizeForAssetName(clothInstance.smr.gameObject.name + "_EditedMesh");
|
||||
AssetDatabase.AddObjectToAsset(mesh, text6);
|
||||
clothInstance.smr.sharedMesh = mesh;
|
||||
clothInstance.editableMesh = clothInstance.smr.sharedMesh;
|
||||
EditorUtility.SetDirty(clothInstance.smr);
|
||||
EditorUtility.SetDirty(clothInstance.smr.sharedMesh);
|
||||
EditorUtility.SetDirty(clothInstance.smr.gameObject);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log($"[EdenAutoMorpher] 편집된 메쉬 {num}개를 " + "'" + text6 + "' 에 서브 에셋으로 저장했습니다. (원본 프리팹은 변경하지 않음)");
|
||||
static string SanitizeForAssetName(string rawName)
|
||||
{
|
||||
char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
|
||||
foreach (char oldChar in invalidFileNameChars)
|
||||
{
|
||||
rawName = rawName.Replace(oldChar, '_');
|
||||
}
|
||||
return rawName.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.MeshClassifier
|
||||
|
||||
@@ -1,246 +1,246 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.MeshMatcher
|
||||
using System.Collections.Generic;
|
||||
using Eden.AutoMorpher;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class MeshMatcher
|
||||
{
|
||||
public struct ClosestHit
|
||||
{
|
||||
public Vector3 closestP;
|
||||
public struct ClosestHit
|
||||
{
|
||||
public Vector3 closestP;
|
||||
|
||||
public Vector3 direction;
|
||||
public Vector3 direction;
|
||||
|
||||
public Vector3 moveVector;
|
||||
public Vector3 moveVector;
|
||||
|
||||
public float distance;
|
||||
}
|
||||
public float distance;
|
||||
}
|
||||
|
||||
public BvhTriangleMesh bodyBVH;
|
||||
public BvhTriangleMesh bodyBVH;
|
||||
|
||||
private readonly HashSet<HumanBodyBones> LeftLegBones = new HashSet<HumanBodyBones>
|
||||
{
|
||||
HumanBodyBones.LeftUpperLeg,
|
||||
HumanBodyBones.LeftLowerLeg,
|
||||
HumanBodyBones.LeftFoot,
|
||||
HumanBodyBones.LeftToes
|
||||
};
|
||||
private readonly HashSet<HumanBodyBones> LeftLegBones = new HashSet<HumanBodyBones>
|
||||
{
|
||||
HumanBodyBones.LeftUpperLeg,
|
||||
HumanBodyBones.LeftLowerLeg,
|
||||
HumanBodyBones.LeftFoot,
|
||||
HumanBodyBones.LeftToes
|
||||
};
|
||||
|
||||
private readonly HashSet<HumanBodyBones> RightLegBones = new HashSet<HumanBodyBones>
|
||||
{
|
||||
HumanBodyBones.RightUpperLeg,
|
||||
HumanBodyBones.RightLowerLeg,
|
||||
HumanBodyBones.RightFoot,
|
||||
HumanBodyBones.RightToes
|
||||
};
|
||||
private readonly HashSet<HumanBodyBones> RightLegBones = new HashSet<HumanBodyBones>
|
||||
{
|
||||
HumanBodyBones.RightUpperLeg,
|
||||
HumanBodyBones.RightLowerLeg,
|
||||
HumanBodyBones.RightFoot,
|
||||
HumanBodyBones.RightToes
|
||||
};
|
||||
|
||||
public BvhTriangleMesh BuildBvhMulti(IReadOnlyList<SkinnedMeshRenderer> bodies, Animator bodyAnimator)
|
||||
{
|
||||
if (bodies == null || bodies.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Body Meshes are Missing", "[BuildBvhMulti] BuildBvhMulti\n - bodies is null or empty");
|
||||
}
|
||||
BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh().BuildFromSkinnedMeshes(bodies, bodyAnimator);
|
||||
if (bvhTriangleMesh == null || bvhTriangleMesh.triangles == null)
|
||||
{
|
||||
Debug.LogError("Failed to build multi-body BVH (no triangles).");
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.BodyBVHFail"), LanguageManager.GetFormat("UI.Exception.message.BodyBVHFail", new object[3]
|
||||
{
|
||||
bodyAnimator.gameObject.name,
|
||||
bvhTriangleMesh == null,
|
||||
bvhTriangleMesh.triangles == null
|
||||
}));
|
||||
}
|
||||
return bvhTriangleMesh;
|
||||
}
|
||||
public BvhTriangleMesh BuildBvhMulti(IReadOnlyList<SkinnedMeshRenderer> bodies, Animator bodyAnimator)
|
||||
{
|
||||
if (bodies == null || bodies.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Body Meshes are Missing", "[BuildBvhMulti] BuildBvhMulti\n - bodies is null or empty");
|
||||
}
|
||||
BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh().BuildFromSkinnedMeshes(bodies, bodyAnimator);
|
||||
if (bvhTriangleMesh == null || bvhTriangleMesh.triangles == null)
|
||||
{
|
||||
Debug.LogError("Failed to build multi-body BVH (no triangles).");
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.BodyBVHFail"), LanguageManager.GetFormat("UI.Exception.message.BodyBVHFail", new object[3]
|
||||
{
|
||||
bodyAnimator.gameObject.name,
|
||||
bvhTriangleMesh == null,
|
||||
bvhTriangleMesh.triangles == null
|
||||
}));
|
||||
}
|
||||
return bvhTriangleMesh;
|
||||
}
|
||||
|
||||
public Vector3[] ExpandVertexMatch(ClothInstance clothInstance, float defaultMinDist = 0.005f, bool skipFootFitting = false, float maxMatchDistance = 0.1f)
|
||||
{
|
||||
Vector3[] worldVertices = clothInstance.worldVertices;
|
||||
float[] minDistance = clothInstance.minDistance;
|
||||
if (bodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("Body BVH is Missing", "[ExpandVertexMatch] ExpandVertexMatch\n - bodyBVH is null");
|
||||
}
|
||||
if (worldVertices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth World Vertices are Missing", "[ExpandVertexMatch] ExpandVertexMatch\n - clothInstance.worldVertices is null");
|
||||
}
|
||||
if (worldVertices.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("clothes mesh has no vertices");
|
||||
return null;
|
||||
}
|
||||
if (minDistance == null)
|
||||
{
|
||||
Debug.LogWarning("minDists is null");
|
||||
}
|
||||
if (minDistance.Length != worldVertices.Length)
|
||||
{
|
||||
Debug.LogWarning("minDists.Length != worldVertexs.Length");
|
||||
}
|
||||
Vector3[] array = new Vector3[worldVertices.Length];
|
||||
float num = maxMatchDistance * maxMatchDistance;
|
||||
for (int i = 0; i < worldVertices.Length; i++)
|
||||
{
|
||||
if (clothInstance.excludedVertices[i])
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (clothInstance.isInsideVertex[i])
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
float num2 = minDistance[i] + defaultMinDist;
|
||||
BvhTriangleMesh.ClosestHit closestHit = (clothInstance.isLeftLegVertex[i] ? bodyBVH.QueryClosest(worldVertices[i], LeftLegBones) : ((!clothInstance.isRightLegVertex[i]) ? bodyBVH.QueryClosest(worldVertices[i]) : bodyBVH.QueryClosest(worldVertices[i], RightLegBones)));
|
||||
if (skipFootFitting && (closestHit.mainHumanBone == HumanBodyBones.LeftFoot || closestHit.mainHumanBone == HumanBodyBones.RightFoot || closestHit.mainHumanBone == HumanBodyBones.RightToes || closestHit.mainHumanBone == HumanBodyBones.LeftToes))
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (closestHit.sqrDistance > num)
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
Vector3 normalized = (closestHit.closestPoint - worldVertices[i]).normalized;
|
||||
float num3 = Vector3.Dot(normalized, closestHit.normal.normalized);
|
||||
if (num3 > 0.7f)
|
||||
{
|
||||
array[i] = closestHit.closestPoint + normalized * num2 - worldVertices[i];
|
||||
}
|
||||
else if (num3 < -0.7f)
|
||||
{
|
||||
if (closestHit.sqrDistance < num2 * num2)
|
||||
{
|
||||
array[i] = closestHit.closestPoint - normalized * num2 - worldVertices[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
public Vector3[] ExpandVertexMatch(ClothInstance clothInstance, float defaultMinDist = 0.005f, bool skipFootFitting = false, float maxMatchDistance = 0.1f)
|
||||
{
|
||||
Vector3[] worldVertices = clothInstance.worldVertices;
|
||||
float[] minDistance = clothInstance.minDistance;
|
||||
if (this.bodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("Body BVH is Missing", "[ExpandVertexMatch] ExpandVertexMatch\n - bodyBVH is null");
|
||||
}
|
||||
if (worldVertices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth World Vertices are Missing", "[ExpandVertexMatch] ExpandVertexMatch\n - clothInstance.worldVertices is null");
|
||||
}
|
||||
if (worldVertices.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("clothes mesh has no vertices");
|
||||
return null;
|
||||
}
|
||||
if (minDistance == null)
|
||||
{
|
||||
Debug.LogWarning("minDists is null");
|
||||
}
|
||||
if (minDistance.Length != worldVertices.Length)
|
||||
{
|
||||
Debug.LogWarning("minDists.Length != worldVertexs.Length");
|
||||
}
|
||||
Vector3[] array = new Vector3[worldVertices.Length];
|
||||
float num = maxMatchDistance * maxMatchDistance;
|
||||
for (int i = 0; i < worldVertices.Length; i++)
|
||||
{
|
||||
if (clothInstance.excludedVertices[i])
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (clothInstance.isInsideVertex[i])
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
float num2 = minDistance[i] + defaultMinDist;
|
||||
BvhTriangleMesh.ClosestHit closestHit = (clothInstance.isLeftLegVertex[i] ? this.bodyBVH.QueryClosest(worldVertices[i], this.LeftLegBones) : ((!clothInstance.isRightLegVertex[i]) ? this.bodyBVH.QueryClosest(worldVertices[i]) : this.bodyBVH.QueryClosest(worldVertices[i], this.RightLegBones)));
|
||||
if (skipFootFitting && (closestHit.mainHumanBone == HumanBodyBones.LeftFoot || closestHit.mainHumanBone == HumanBodyBones.RightFoot || closestHit.mainHumanBone == HumanBodyBones.RightToes || closestHit.mainHumanBone == HumanBodyBones.LeftToes))
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (closestHit.sqrDistance > num)
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
Vector3 normalized = (closestHit.closestPoint - worldVertices[i]).normalized;
|
||||
float num3 = Vector3.Dot(normalized, closestHit.normal.normalized);
|
||||
if (num3 > 0.7f)
|
||||
{
|
||||
array[i] = closestHit.closestPoint + normalized * num2 - worldVertices[i];
|
||||
}
|
||||
else if (num3 < -0.7f)
|
||||
{
|
||||
if (closestHit.sqrDistance < num2 * num2)
|
||||
{
|
||||
array[i] = closestHit.closestPoint - normalized * num2 - worldVertices[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public Vector3[] ShrinkVertexMatch(ClothInstance clothInstance, float defaultMinDist = 0.005f, float maxMatchDistance = 0.1f)
|
||||
{
|
||||
Vector3[] worldVertices = clothInstance.worldVertices;
|
||||
float[] minDistance = clothInstance.minDistance;
|
||||
if (bodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("Body BVH is Missing", "[ShrinkVertexMatch] ShrinkVertexMatch\n - bodyBVH is null");
|
||||
}
|
||||
if (worldVertices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth World Vertices are Missing", "[ShrinkVertexMatch] ShrinkVertexMatch\n - clothInstance.worldVertices is null");
|
||||
}
|
||||
if (worldVertices.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("clothes mesh has no vertices");
|
||||
return null;
|
||||
}
|
||||
if (minDistance == null)
|
||||
{
|
||||
Debug.LogWarning("minDists is null");
|
||||
}
|
||||
if (minDistance.Length != worldVertices.Length)
|
||||
{
|
||||
Debug.LogWarning("minDists.Length != worldVertexs.Length");
|
||||
}
|
||||
Vector3[] array = new Vector3[worldVertices.Length];
|
||||
float num = maxMatchDistance * maxMatchDistance;
|
||||
_ = clothInstance.isLeftLegVertex;
|
||||
_ = clothInstance.isRightLegVertex;
|
||||
for (int i = 0; i < worldVertices.Length; i++)
|
||||
{
|
||||
if (clothInstance.excludedVertices[i])
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (clothInstance.isInsideVertex[i])
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
float num2 = minDistance[i] + defaultMinDist;
|
||||
BvhTriangleMesh.ClosestHit closestHit = (clothInstance.isLeftLegVertex[i] ? bodyBVH.QueryClosest(worldVertices[i], LeftLegBones) : ((!clothInstance.isRightLegVertex[i]) ? bodyBVH.QueryClosest(worldVertices[i]) : bodyBVH.QueryClosest(worldVertices[i], RightLegBones)));
|
||||
if (closestHit.sqrDistance > num)
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (closestHit.mainHumanBone == HumanBodyBones.LeftFoot || closestHit.mainHumanBone == HumanBodyBones.RightFoot || closestHit.mainHumanBone == HumanBodyBones.RightToes || closestHit.mainHumanBone == HumanBodyBones.LeftToes)
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
Vector3 normalized = (closestHit.closestPoint - worldVertices[i]).normalized;
|
||||
float num3 = Vector3.Dot(normalized, closestHit.normal.normalized);
|
||||
if (num3 < -0.7f)
|
||||
{
|
||||
array[i] = closestHit.closestPoint - normalized * num2 - worldVertices[i];
|
||||
}
|
||||
else if (num3 < -0.7f)
|
||||
{
|
||||
if (closestHit.sqrDistance < num2 * num2)
|
||||
{
|
||||
array[i] = closestHit.closestPoint + normalized * num2 - worldVertices[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
public Vector3[] ShrinkVertexMatch(ClothInstance clothInstance, float defaultMinDist = 0.005f, float maxMatchDistance = 0.1f)
|
||||
{
|
||||
Vector3[] worldVertices = clothInstance.worldVertices;
|
||||
float[] minDistance = clothInstance.minDistance;
|
||||
if (this.bodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("Body BVH is Missing", "[ShrinkVertexMatch] ShrinkVertexMatch\n - bodyBVH is null");
|
||||
}
|
||||
if (worldVertices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth World Vertices are Missing", "[ShrinkVertexMatch] ShrinkVertexMatch\n - clothInstance.worldVertices is null");
|
||||
}
|
||||
if (worldVertices.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("clothes mesh has no vertices");
|
||||
return null;
|
||||
}
|
||||
if (minDistance == null)
|
||||
{
|
||||
Debug.LogWarning("minDists is null");
|
||||
}
|
||||
if (minDistance.Length != worldVertices.Length)
|
||||
{
|
||||
Debug.LogWarning("minDists.Length != worldVertexs.Length");
|
||||
}
|
||||
Vector3[] array = new Vector3[worldVertices.Length];
|
||||
float num = maxMatchDistance * maxMatchDistance;
|
||||
_ = clothInstance.isLeftLegVertex;
|
||||
_ = clothInstance.isRightLegVertex;
|
||||
for (int i = 0; i < worldVertices.Length; i++)
|
||||
{
|
||||
if (clothInstance.excludedVertices[i])
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (clothInstance.isInsideVertex[i])
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
float num2 = minDistance[i] + defaultMinDist;
|
||||
BvhTriangleMesh.ClosestHit closestHit = (clothInstance.isLeftLegVertex[i] ? this.bodyBVH.QueryClosest(worldVertices[i], this.LeftLegBones) : ((!clothInstance.isRightLegVertex[i]) ? this.bodyBVH.QueryClosest(worldVertices[i]) : this.bodyBVH.QueryClosest(worldVertices[i], this.RightLegBones)));
|
||||
if (closestHit.sqrDistance > num)
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (closestHit.mainHumanBone == HumanBodyBones.LeftFoot || closestHit.mainHumanBone == HumanBodyBones.RightFoot || closestHit.mainHumanBone == HumanBodyBones.RightToes || closestHit.mainHumanBone == HumanBodyBones.LeftToes)
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
Vector3 normalized = (closestHit.closestPoint - worldVertices[i]).normalized;
|
||||
float num3 = Vector3.Dot(normalized, closestHit.normal.normalized);
|
||||
if (num3 < -0.7f)
|
||||
{
|
||||
array[i] = closestHit.closestPoint - normalized * num2 - worldVertices[i];
|
||||
}
|
||||
else if (num3 < -0.7f)
|
||||
{
|
||||
if (closestHit.sqrDistance < num2 * num2)
|
||||
{
|
||||
array[i] = closestHit.closestPoint + normalized * num2 - worldVertices[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
array[i] = Vector3.zero;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public Vector3[] GetMinDistanceToBody(Vector3[] clothesVertices)
|
||||
{
|
||||
if (bodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("sourceBodyBVH is null", "[MeshMatcher] GetMinDistanceToBodysourceBodyBVH is null");
|
||||
}
|
||||
if (clothesVertices == null || clothesVertices.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Source Vertices is null", "[MeshMatcher] GetMinDistanceToBodySource Vertices is null or no vertices");
|
||||
}
|
||||
Vector3[] array = new Vector3[clothesVertices.Length];
|
||||
for (int i = 0; i < clothesVertices.Length; i++)
|
||||
{
|
||||
Vector3 vector = clothesVertices[i];
|
||||
Vector3 vector2 = bodyBVH.QueryClosest(vector).closestPoint - vector;
|
||||
array[i] = vector2;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
public Vector3[] GetMinDistanceToBody(Vector3[] clothesVertices)
|
||||
{
|
||||
if (this.bodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("sourceBodyBVH is null", "[MeshMatcher] GetMinDistanceToBodysourceBodyBVH is null");
|
||||
}
|
||||
if (clothesVertices == null || clothesVertices.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Source Vertices is null", "[MeshMatcher] GetMinDistanceToBodySource Vertices is null or no vertices");
|
||||
}
|
||||
Vector3[] array = new Vector3[clothesVertices.Length];
|
||||
for (int i = 0; i < clothesVertices.Length; i++)
|
||||
{
|
||||
Vector3 vector = clothesVertices[i];
|
||||
Vector3 vector2 = this.bodyBVH.QueryClosest(vector).closestPoint - vector;
|
||||
array[i] = vector2;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public bool[] GetBodyInsideFlags(Vector3[] worldVertices)
|
||||
{
|
||||
if (bodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("sourceBodyBVH is null", "[MeshMatcher] GetBodyInsideFlagssourceBodyBVH is null");
|
||||
}
|
||||
if (worldVertices == null || worldVertices.Length == 0)
|
||||
{
|
||||
Debug.LogError("clothes is null");
|
||||
throw new AutoMorpherException("Source Vertices is null", "[MeshMatcher] GetMinDistanceToBodySource Vertices is null or no vertices");
|
||||
}
|
||||
bool[] array = new bool[worldVertices.Length];
|
||||
for (int i = 0; i < worldVertices.Length; i++)
|
||||
{
|
||||
BvhTriangleMesh.ClosestHit closestHit = bodyBVH.QueryClosest(worldVertices[i]);
|
||||
float num = Vector3.Dot((closestHit.closestPoint - worldVertices[i]).normalized, closestHit.normal.normalized);
|
||||
array[i] = num > 0f;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
public bool[] GetBodyInsideFlags(Vector3[] worldVertices)
|
||||
{
|
||||
if (this.bodyBVH == null)
|
||||
{
|
||||
throw new AutoMorpherException("sourceBodyBVH is null", "[MeshMatcher] GetBodyInsideFlagssourceBodyBVH is null");
|
||||
}
|
||||
if (worldVertices == null || worldVertices.Length == 0)
|
||||
{
|
||||
Debug.LogError("clothes is null");
|
||||
throw new AutoMorpherException("Source Vertices is null", "[MeshMatcher] GetMinDistanceToBodySource Vertices is null or no vertices");
|
||||
}
|
||||
bool[] array = new bool[worldVertices.Length];
|
||||
for (int i = 0; i < worldVertices.Length; i++)
|
||||
{
|
||||
BvhTriangleMesh.ClosestHit closestHit = this.bodyBVH.QueryClosest(worldVertices[i]);
|
||||
float num = Vector3.Dot((closestHit.closestPoint - worldVertices[i]).normalized, closestHit.normal.normalized);
|
||||
array[i] = num > 0f;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.MorpherMode
|
||||
public enum MorpherMode
|
||||
{
|
||||
AutoMorpher = 0,
|
||||
ManualMorpher = 1,
|
||||
ProfileMorpher = 2,
|
||||
ETC = 99
|
||||
AutoMorpher = 0,
|
||||
ManualMorpher = 1,
|
||||
ProfileMorpher = 2,
|
||||
ETC = 99
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.MorpherState
|
||||
public enum MorpherState
|
||||
{
|
||||
Idle,
|
||||
Fitting_Doing,
|
||||
Fitting_End,
|
||||
Weighting_Doing,
|
||||
Weighting_End
|
||||
Idle,
|
||||
Fitting_Doing,
|
||||
Fitting_End,
|
||||
Weighting_Doing,
|
||||
Weighting_End
|
||||
}
|
||||
|
||||
@@ -1,162 +1,161 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.PcaUtil
|
||||
using System.Collections.Generic;
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public class PcaUtil
|
||||
{
|
||||
public RegionStats ComputeRegionStats(IList<Vector3> points)
|
||||
{
|
||||
RegionStats result = default(RegionStats);
|
||||
if (points == null || points.Count == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
int count = points.Count;
|
||||
Vector3 zero = Vector3.zero;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
zero += points[i];
|
||||
}
|
||||
zero /= (float)count;
|
||||
float num = 0f;
|
||||
float num2 = 0f;
|
||||
float num3 = 0f;
|
||||
float num4 = 0f;
|
||||
float num5 = 0f;
|
||||
float num6 = 0f;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
Vector3 vector = points[j] - zero;
|
||||
num += vector.x * vector.x;
|
||||
num2 += vector.x * vector.y;
|
||||
num3 += vector.x * vector.z;
|
||||
num4 += vector.y * vector.y;
|
||||
num5 += vector.y * vector.z;
|
||||
num6 += vector.z * vector.z;
|
||||
}
|
||||
float num7 = 1f / (float)count;
|
||||
num *= num7;
|
||||
num2 *= num7;
|
||||
num3 *= num7;
|
||||
num4 *= num7;
|
||||
num5 *= num7;
|
||||
num6 *= num7;
|
||||
JacobiEigenDecomposition3x3(num, num2, num3, num4, num5, num6, out var eigenValues, out var eigenVectors);
|
||||
int num8 = 0;
|
||||
if (eigenValues[1] > eigenValues[num8])
|
||||
{
|
||||
num8 = 1;
|
||||
}
|
||||
if (eigenValues[2] > eigenValues[num8])
|
||||
{
|
||||
num8 = 2;
|
||||
}
|
||||
Vector3 normalized = eigenVectors[num8].normalized;
|
||||
float num9 = float.PositiveInfinity;
|
||||
float num10 = float.NegativeInfinity;
|
||||
float num11 = 0f;
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
float num12 = Vector3.Dot(points[k] - zero, normalized);
|
||||
if (num12 < num9)
|
||||
{
|
||||
num9 = num12;
|
||||
}
|
||||
if (num12 > num10)
|
||||
{
|
||||
num10 = num12;
|
||||
}
|
||||
Vector3 vector2 = zero + normalized * num12;
|
||||
float magnitude = (points[k] - vector2).magnitude;
|
||||
num11 += magnitude;
|
||||
}
|
||||
result.center = zero;
|
||||
result.principalAxis = normalized;
|
||||
result.length = num10 - num9;
|
||||
result.avgRadius = num11 / (float)count;
|
||||
return result;
|
||||
}
|
||||
public RegionStats ComputeRegionStats(IList<Vector3> points)
|
||||
{
|
||||
RegionStats result = default(RegionStats);
|
||||
if (points == null || points.Count == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
int count = points.Count;
|
||||
Vector3 zero = Vector3.zero;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
zero += points[i];
|
||||
}
|
||||
zero /= (float)count;
|
||||
float num = 0f;
|
||||
float num2 = 0f;
|
||||
float num3 = 0f;
|
||||
float num4 = 0f;
|
||||
float num5 = 0f;
|
||||
float num6 = 0f;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
Vector3 vector = points[j] - zero;
|
||||
num += vector.x * vector.x;
|
||||
num2 += vector.x * vector.y;
|
||||
num3 += vector.x * vector.z;
|
||||
num4 += vector.y * vector.y;
|
||||
num5 += vector.y * vector.z;
|
||||
num6 += vector.z * vector.z;
|
||||
}
|
||||
float num7 = 1f / (float)count;
|
||||
num *= num7;
|
||||
num2 *= num7;
|
||||
num3 *= num7;
|
||||
num4 *= num7;
|
||||
num5 *= num7;
|
||||
num6 *= num7;
|
||||
this.JacobiEigenDecomposition3x3(num, num2, num3, num4, num5, num6, out var eigenValues, out var eigenVectors);
|
||||
int num8 = 0;
|
||||
if (eigenValues[1] > eigenValues[num8])
|
||||
{
|
||||
num8 = 1;
|
||||
}
|
||||
if (eigenValues[2] > eigenValues[num8])
|
||||
{
|
||||
num8 = 2;
|
||||
}
|
||||
Vector3 normalized = eigenVectors[num8].normalized;
|
||||
float num9 = float.PositiveInfinity;
|
||||
float num10 = float.NegativeInfinity;
|
||||
float num11 = 0f;
|
||||
for (int k = 0; k < count; k++)
|
||||
{
|
||||
float num12 = Vector3.Dot(points[k] - zero, normalized);
|
||||
if (num12 < num9)
|
||||
{
|
||||
num9 = num12;
|
||||
}
|
||||
if (num12 > num10)
|
||||
{
|
||||
num10 = num12;
|
||||
}
|
||||
Vector3 vector2 = zero + normalized * num12;
|
||||
float magnitude = (points[k] - vector2).magnitude;
|
||||
num11 += magnitude;
|
||||
}
|
||||
result.center = zero;
|
||||
result.principalAxis = normalized;
|
||||
result.length = num10 - num9;
|
||||
result.avgRadius = num11 / (float)count;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void JacobiEigenDecomposition3x3(float c00, float c01, float c02, float c11, float c12, float c22, out float[] eigenValues, out Vector3[] eigenVectors)
|
||||
{
|
||||
float[,] array = new float[3, 3]
|
||||
{
|
||||
{ c00, c01, c02 },
|
||||
{ c01, c11, c12 },
|
||||
{ c02, c12, c22 }
|
||||
};
|
||||
float[,] array2 = new float[3, 3]
|
||||
{
|
||||
{ 1f, 0f, 0f },
|
||||
{ 0f, 1f, 0f },
|
||||
{ 0f, 0f, 1f }
|
||||
};
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
int num = 0;
|
||||
int num2 = 1;
|
||||
float num3 = Mathf.Abs(array[0, 1]);
|
||||
float num4 = Mathf.Abs(array[0, 2]);
|
||||
if (num4 > num3)
|
||||
{
|
||||
num3 = num4;
|
||||
num = 0;
|
||||
num2 = 2;
|
||||
}
|
||||
float num5 = Mathf.Abs(array[1, 2]);
|
||||
if (num5 > num3)
|
||||
{
|
||||
num3 = num5;
|
||||
num = 1;
|
||||
num2 = 2;
|
||||
}
|
||||
if (num3 < 1E-10f)
|
||||
{
|
||||
break;
|
||||
}
|
||||
float num6 = array[num, num];
|
||||
float num7 = array[num2, num2];
|
||||
float num8 = array[num, num2];
|
||||
float f = 0.5f * Mathf.Atan2(2f * num8, num7 - num6);
|
||||
float num9 = Mathf.Cos(f);
|
||||
float num10 = Mathf.Sin(f);
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
if (j != num && j != num2)
|
||||
{
|
||||
float num11 = array[j, num];
|
||||
float num12 = array[j, num2];
|
||||
array[j, num] = num9 * num11 - num10 * num12;
|
||||
array[num, j] = array[j, num];
|
||||
array[j, num2] = num10 * num11 + num9 * num12;
|
||||
array[num2, j] = array[j, num2];
|
||||
}
|
||||
}
|
||||
float num13 = num9 * num9 * num6 - 2f * num10 * num9 * num8 + num10 * num10 * num7;
|
||||
float num14 = num10 * num10 * num6 + 2f * num10 * num9 * num8 + num9 * num9 * num7;
|
||||
array[num, num] = num13;
|
||||
array[num2, num2] = num14;
|
||||
array[num, num2] = 0f;
|
||||
array[num2, num] = 0f;
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
float num15 = array2[k, num];
|
||||
float num16 = array2[k, num2];
|
||||
array2[k, num] = num9 * num15 - num10 * num16;
|
||||
array2[k, num2] = num10 * num15 + num9 * num16;
|
||||
}
|
||||
}
|
||||
eigenValues = new float[3];
|
||||
eigenVectors = new Vector3[3];
|
||||
eigenValues[0] = array[0, 0];
|
||||
eigenValues[1] = array[1, 1];
|
||||
eigenValues[2] = array[2, 2];
|
||||
eigenVectors[0] = new Vector3(array2[0, 0], array2[1, 0], array2[2, 0]);
|
||||
eigenVectors[1] = new Vector3(array2[0, 1], array2[1, 1], array2[2, 1]);
|
||||
eigenVectors[2] = new Vector3(array2[0, 2], array2[1, 2], array2[2, 2]);
|
||||
}
|
||||
private void JacobiEigenDecomposition3x3(float c00, float c01, float c02, float c11, float c12, float c22, out float[] eigenValues, out Vector3[] eigenVectors)
|
||||
{
|
||||
float[,] array = new float[3, 3]
|
||||
{
|
||||
{ c00, c01, c02 },
|
||||
{ c01, c11, c12 },
|
||||
{ c02, c12, c22 }
|
||||
};
|
||||
float[,] array2 = new float[3, 3]
|
||||
{
|
||||
{ 1f, 0f, 0f },
|
||||
{ 0f, 1f, 0f },
|
||||
{ 0f, 0f, 1f }
|
||||
};
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
int num = 0;
|
||||
int num2 = 1;
|
||||
float num3 = Mathf.Abs(array[0, 1]);
|
||||
float num4 = Mathf.Abs(array[0, 2]);
|
||||
if (num4 > num3)
|
||||
{
|
||||
num3 = num4;
|
||||
num = 0;
|
||||
num2 = 2;
|
||||
}
|
||||
float num5 = Mathf.Abs(array[1, 2]);
|
||||
if (num5 > num3)
|
||||
{
|
||||
num3 = num5;
|
||||
num = 1;
|
||||
num2 = 2;
|
||||
}
|
||||
if (num3 < 1E-10f)
|
||||
{
|
||||
break;
|
||||
}
|
||||
float num6 = array[num, num];
|
||||
float num7 = array[num2, num2];
|
||||
float num8 = array[num, num2];
|
||||
float f = 0.5f * Mathf.Atan2(2f * num8, num7 - num6);
|
||||
float num9 = Mathf.Cos(f);
|
||||
float num10 = Mathf.Sin(f);
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
if (j != num && j != num2)
|
||||
{
|
||||
float num11 = array[j, num];
|
||||
float num12 = array[j, num2];
|
||||
array[j, num] = num9 * num11 - num10 * num12;
|
||||
array[num, j] = array[j, num];
|
||||
array[j, num2] = num10 * num11 + num9 * num12;
|
||||
array[num2, j] = array[j, num2];
|
||||
}
|
||||
}
|
||||
float num13 = num9 * num9 * num6 - 2f * num10 * num9 * num8 + num10 * num10 * num7;
|
||||
float num14 = num10 * num10 * num6 + 2f * num10 * num9 * num8 + num9 * num9 * num7;
|
||||
array[num, num] = num13;
|
||||
array[num2, num2] = num14;
|
||||
array[num, num2] = 0f;
|
||||
array[num2, num] = 0f;
|
||||
for (int k = 0; k < 3; k++)
|
||||
{
|
||||
float num15 = array2[k, num];
|
||||
float num16 = array2[k, num2];
|
||||
array2[k, num] = num9 * num15 - num10 * num16;
|
||||
array2[k, num2] = num10 * num15 + num9 * num16;
|
||||
}
|
||||
}
|
||||
eigenValues = new float[3];
|
||||
eigenVectors = new Vector3[3];
|
||||
eigenValues[0] = array[0, 0];
|
||||
eigenValues[1] = array[1, 1];
|
||||
eigenValues[2] = array[2, 2];
|
||||
eigenVectors[0] = new Vector3(array2[0, 0], array2[1, 0], array2[2, 0]);
|
||||
eigenVectors[1] = new Vector3(array2[0, 1], array2[1, 1], array2[2, 1]);
|
||||
eigenVectors[2] = new Vector3(array2[0, 2], array2[1, 2], array2[2, 2]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.ProcessInfo
|
||||
public struct ProcessInfo
|
||||
{
|
||||
public string title;
|
||||
public string title;
|
||||
|
||||
public string text;
|
||||
public string text;
|
||||
|
||||
public float progress;
|
||||
public float progress;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.profile.ProfileLoader
|
||||
@@ -6,293 +6,291 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Eden.AutoMorpher;
|
||||
using Eden.AutoMorpher.profile;
|
||||
using UnityEngine;
|
||||
|
||||
public class ProfileLoader
|
||||
{
|
||||
private ProfileData loadedProfileData;
|
||||
private ProfileData loadedProfileData;
|
||||
|
||||
private const int HEX32_W = 8;
|
||||
private const int HEX32_W = 8;
|
||||
|
||||
public List<string> GetProfileList()
|
||||
{
|
||||
ProfileUtils profileUtils = new ProfileUtils();
|
||||
string text = Path.Combine(Application.dataPath, profileUtils.GetProfileBasePath());
|
||||
List<string> list = new List<string>();
|
||||
if (!Directory.Exists(text))
|
||||
{
|
||||
Debug.LogWarning("[ProfileUtils] Profile base path does not exist: " + text);
|
||||
return list;
|
||||
}
|
||||
string[] directories = Directory.GetDirectories(text);
|
||||
foreach (string text2 in directories)
|
||||
{
|
||||
string fileName = Path.GetFileName(text2);
|
||||
if (!string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
string path = Path.Combine(text2, fileName + ".json");
|
||||
string path2 = Path.Combine(text2, fileName + ".eb");
|
||||
if (File.Exists(path) && File.Exists(path2))
|
||||
{
|
||||
list.Add(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
public List<string> GetProfileList()
|
||||
{
|
||||
ProfileUtils profileUtils = new ProfileUtils();
|
||||
string text = Path.Combine(Application.dataPath, profileUtils.GetProfileBasePath());
|
||||
List<string> list = new List<string>();
|
||||
if (!Directory.Exists(text))
|
||||
{
|
||||
Debug.LogWarning("[ProfileUtils] Profile base path does not exist: " + text);
|
||||
return list;
|
||||
}
|
||||
string[] directories = Directory.GetDirectories(text);
|
||||
foreach (string text2 in directories)
|
||||
{
|
||||
string fileName = Path.GetFileName(text2);
|
||||
if (!string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
string path = Path.Combine(text2, fileName + ".json");
|
||||
string path2 = Path.Combine(text2, fileName + ".eb");
|
||||
if (File.Exists(path) && File.Exists(path2))
|
||||
{
|
||||
list.Add(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public ProfileData LoadProfileData(string profileName)
|
||||
{
|
||||
ProfileUtils profileUtils = new ProfileUtils();
|
||||
string path = Path.Combine(Application.dataPath, profileUtils.GetProfileBasePath());
|
||||
path = Path.Combine(path, profileName);
|
||||
path = Path.Combine(path, profileName + ".json");
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
throw new AutoMorpherException("Profile File Path is Invalid", "[ProfileLoader] LoadProfileData\n - Profile Path is null, empty, or whitespace");
|
||||
}
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new AutoMorpherException("Profile File Does Not Exist", "[ProfileLoader] LoadProfileData\n - profile file does not exist\n - path : " + path);
|
||||
}
|
||||
string json = File.ReadAllText(path);
|
||||
loadedProfileData = JsonUtility.FromJson<ProfileData>(json);
|
||||
if (loadedProfileData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Failed to Load Profile Data", "[ProfileLoader] LoadProfileData\n - Can't Load Profile Data\n - Please place a valid profile data file at " + path);
|
||||
}
|
||||
return loadedProfileData;
|
||||
}
|
||||
public ProfileData LoadProfileData(string profileName)
|
||||
{
|
||||
ProfileUtils profileUtils = new ProfileUtils();
|
||||
string path = Path.Combine(Application.dataPath, profileUtils.GetProfileBasePath());
|
||||
path = Path.Combine(path, profileName);
|
||||
path = Path.Combine(path, profileName + ".json");
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
throw new AutoMorpherException("Profile File Path is Invalid", "[ProfileLoader] LoadProfileData\n - Profile Path is null, empty, or whitespace");
|
||||
}
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new AutoMorpherException("Profile File Does Not Exist", "[ProfileLoader] LoadProfileData\n - profile file does not exist\n - path : " + path);
|
||||
}
|
||||
string json = File.ReadAllText(path);
|
||||
this.loadedProfileData = JsonUtility.FromJson<ProfileData>(json);
|
||||
if (this.loadedProfileData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Failed to Load Profile Data", "[ProfileLoader] LoadProfileData\n - Can't Load Profile Data\n - Please place a valid profile data file at " + path);
|
||||
}
|
||||
return this.loadedProfileData;
|
||||
}
|
||||
|
||||
public BvhTriangleMesh LoadBvhWithRootTransform(Transform rootTransform, string profileName)
|
||||
{
|
||||
ProfileUtils profileUtils = new ProfileUtils();
|
||||
string path = Path.Combine(Application.dataPath, profileUtils.GetProfileBasePath());
|
||||
path = Path.Combine(path, profileName);
|
||||
path = Path.Combine(path, profileName + ".eb");
|
||||
if (rootTransform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Root Transform is Null", "[ProfileLoader] LoadBvhWithRootTransform\n - rootTransform is null");
|
||||
}
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Path is Invalid", "[ProfileLoader] LoadBvhWithRootTransform\n - profileBvhPath is null or empty");
|
||||
}
|
||||
int version;
|
||||
ProfileBVH profileBVH = LoadProfileBVHData(path, out version);
|
||||
if (profileBVH == null || profileBVH.vertices == null || profileBVH.datas == null || profileBVH.nodes == null || profileBVH.dataIndices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Data is Invalid", "[ProfileLoader] LoadBvhWithRootTransform\n - profile or one of its internal data fields is null");
|
||||
}
|
||||
Matrix4x4 localToWorldMatrix = rootTransform.localToWorldMatrix;
|
||||
int num = profileBVH.datas.Length;
|
||||
BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh
|
||||
{
|
||||
triangles = new BvhTriangle[num],
|
||||
triIndices = new int[profileBVH.dataIndices.Length],
|
||||
nodes = new BvhNode[profileBVH.nodes.Length]
|
||||
};
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
profileBVHData profileBVHData2 = profileBVH.datas[i];
|
||||
Vector3 point = profileBVH.vertices[profileBVHData2.verA];
|
||||
Vector3 point2 = profileBVH.vertices[profileBVHData2.verB];
|
||||
Vector3 point3 = profileBVH.vertices[profileBVHData2.verC];
|
||||
Vector3 a = localToWorldMatrix.MultiplyPoint3x4(point);
|
||||
Vector3 b = localToWorldMatrix.MultiplyPoint3x4(point2);
|
||||
Vector3 c = localToWorldMatrix.MultiplyPoint3x4(point3);
|
||||
Vector3 normal = ComputeTriangleNormal(a, b, c);
|
||||
bvhTriangleMesh.triangles[i] = new BvhTriangle
|
||||
{
|
||||
a = a,
|
||||
b = b,
|
||||
c = c,
|
||||
normal = normal,
|
||||
mainHumanBone = HumanBodyBones.LastBone
|
||||
};
|
||||
}
|
||||
Array.Copy(profileBVH.dataIndices, bvhTriangleMesh.triIndices, profileBVH.dataIndices.Length);
|
||||
for (int j = 0; j < profileBVH.nodes.Length; j++)
|
||||
{
|
||||
profileBVHNode profileBVHNode2 = profileBVH.nodes[j];
|
||||
bvhTriangleMesh.nodes[j] = new BvhNode
|
||||
{
|
||||
isLeaf = profileBVHNode2.isLeaf,
|
||||
leftChild = profileBVHNode2.leftChild,
|
||||
rightChild = profileBVHNode2.rightChild,
|
||||
start = profileBVHNode2.start,
|
||||
count = profileBVHNode2.count,
|
||||
bounds = TransformBoundsToWorldAABB(localToWorldMatrix, profileBVHNode2.bounds)
|
||||
};
|
||||
}
|
||||
return bvhTriangleMesh;
|
||||
}
|
||||
public BvhTriangleMesh LoadBvhWithRootTransform(Transform rootTransform, string profileName)
|
||||
{
|
||||
ProfileUtils profileUtils = new ProfileUtils();
|
||||
string path = Path.Combine(Application.dataPath, profileUtils.GetProfileBasePath());
|
||||
path = Path.Combine(path, profileName);
|
||||
path = Path.Combine(path, profileName + ".eb");
|
||||
if (rootTransform == null)
|
||||
{
|
||||
throw new AutoMorpherException("Root Transform is Null", "[ProfileLoader] LoadBvhWithRootTransform\n - rootTransform is null");
|
||||
}
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Path is Invalid", "[ProfileLoader] LoadBvhWithRootTransform\n - profileBvhPath is null or empty");
|
||||
}
|
||||
int version;
|
||||
ProfileBVH profileBVH = this.LoadProfileBVHData(path, out version);
|
||||
if (profileBVH == null || profileBVH.vertices == null || profileBVH.datas == null || profileBVH.nodes == null || profileBVH.dataIndices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Data is Invalid", "[ProfileLoader] LoadBvhWithRootTransform\n - profile or one of its internal data fields is null");
|
||||
}
|
||||
Matrix4x4 localToWorldMatrix = rootTransform.localToWorldMatrix;
|
||||
int num = profileBVH.datas.Length;
|
||||
BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh
|
||||
{
|
||||
triangles = new BvhTriangle[num],
|
||||
triIndices = new int[profileBVH.dataIndices.Length],
|
||||
nodes = new BvhNode[profileBVH.nodes.Length]
|
||||
};
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
profileBVHData profileBVHData2 = profileBVH.datas[i];
|
||||
Vector3 point = profileBVH.vertices[profileBVHData2.verA];
|
||||
Vector3 point2 = profileBVH.vertices[profileBVHData2.verB];
|
||||
Vector3 point3 = profileBVH.vertices[profileBVHData2.verC];
|
||||
Vector3 a = localToWorldMatrix.MultiplyPoint3x4(point);
|
||||
Vector3 b = localToWorldMatrix.MultiplyPoint3x4(point2);
|
||||
Vector3 c = localToWorldMatrix.MultiplyPoint3x4(point3);
|
||||
Vector3 normal = this.ComputeTriangleNormal(a, b, c);
|
||||
bvhTriangleMesh.triangles[i] = new BvhTriangle
|
||||
{
|
||||
a = a,
|
||||
b = b,
|
||||
c = c,
|
||||
normal = normal,
|
||||
mainHumanBone = HumanBodyBones.LastBone
|
||||
};
|
||||
}
|
||||
Array.Copy(profileBVH.dataIndices, bvhTriangleMesh.triIndices, profileBVH.dataIndices.Length);
|
||||
for (int j = 0; j < profileBVH.nodes.Length; j++)
|
||||
{
|
||||
profileBVHNode profileBVHNode2 = profileBVH.nodes[j];
|
||||
bvhTriangleMesh.nodes[j] = new BvhNode
|
||||
{
|
||||
isLeaf = profileBVHNode2.isLeaf,
|
||||
leftChild = profileBVHNode2.leftChild,
|
||||
rightChild = profileBVHNode2.rightChild,
|
||||
start = profileBVHNode2.start,
|
||||
count = profileBVHNode2.count,
|
||||
bounds = this.TransformBoundsToWorldAABB(localToWorldMatrix, profileBVHNode2.bounds)
|
||||
};
|
||||
}
|
||||
return bvhTriangleMesh;
|
||||
}
|
||||
|
||||
private ProfileBVH LoadProfileBVHData(string path, out int version)
|
||||
{
|
||||
version = 0;
|
||||
int num = 0;
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH File Not Found", "[ProfileLoader] LoadProfileBVHData\n - file not found\n - path : " + path);
|
||||
}
|
||||
string text = File.ReadAllText(path, Encoding.UTF8);
|
||||
int num2 = 0;
|
||||
ProfileUtils profileUtils = new ProfileUtils();
|
||||
string profileMagic = profileUtils.GetProfileMagic();
|
||||
if (text.Length < profileMagic.Length || text.Substring(0, profileMagic.Length) != profileMagic)
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Magic Mismatch", "[ProfileLoader] LoadProfileBVHData\n - magic string mismatch\n - invalid or corrupted BVH file");
|
||||
}
|
||||
num2 += profileMagic.Length;
|
||||
version = ReadHexIntSafe(text, ref num2);
|
||||
num = ReadHexIntSafe(text, ref num2);
|
||||
int num3 = ReadHexIntSafe(text, ref num2);
|
||||
int num4 = ReadHexIntSafe(text, ref num2);
|
||||
int num5 = ReadHexIntSafe(text, ref num2);
|
||||
int num6 = ReadHexIntSafe(text, ref num2);
|
||||
if (num3 < 0 || num4 < 0 || num5 < 0 || num6 < 0)
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Count Data is Invalid", "[ProfileLoader] LoadProfileBVHData\n - one or more count values are negative");
|
||||
}
|
||||
Vector3[] array = new Vector3[num3];
|
||||
for (int i = 0; i < num3; i++)
|
||||
{
|
||||
array[i] = ReadHexVec3Safe(text, ref num2);
|
||||
}
|
||||
int version2;
|
||||
int countInFile;
|
||||
BaseKey3[] array2 = new ProfileUtils_VertexUtil().LoadTable(profileUtils.GetBaseDataPath(), out version2, out countInFile);
|
||||
if (array2 == null || array2.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Base Vertex Table is Invalid", "[ProfileLoader] LoadProfileBVHData\n - base vertex table is null or empty");
|
||||
}
|
||||
ProfileUtil_IndexUtil profileUtil_IndexUtil = new ProfileUtil_IndexUtil();
|
||||
profileUtil_IndexUtil.Build(num);
|
||||
Vector3[] array3 = new Vector3[num3];
|
||||
profileUtil_IndexUtil.DecodeInto(array, array3);
|
||||
Vector3[] array4 = new Vector3[num3];
|
||||
for (int j = 0; j < num3; j++)
|
||||
{
|
||||
array4[j] = TransformVec3(array3[j], array2[j % array2.Length]);
|
||||
}
|
||||
ProfileBVH profileBVH = new ProfileBVH
|
||||
{
|
||||
vertices = new List<Vector3>(num3),
|
||||
datas = new profileBVHData[num4],
|
||||
nodes = new profileBVHNode[num5],
|
||||
dataIndices = new int[num6]
|
||||
};
|
||||
profileBVH.vertices.AddRange(array4);
|
||||
for (int k = 0; k < num4; k++)
|
||||
{
|
||||
profileBVH.datas[k] = new profileBVHData
|
||||
{
|
||||
verA = ReadHexIntSafe(text, ref num2),
|
||||
verB = ReadHexIntSafe(text, ref num2),
|
||||
verC = ReadHexIntSafe(text, ref num2)
|
||||
};
|
||||
}
|
||||
for (int l = 0; l < num5; l++)
|
||||
{
|
||||
Vector3 center = ReadHexVec3Safe(text, ref num2);
|
||||
Vector3 vector = ReadHexVec3Safe(text, ref num2);
|
||||
profileBVH.nodes[l] = new profileBVHNode
|
||||
{
|
||||
bounds = new Bounds(center, vector * 2f),
|
||||
leftChild = ReadHexIntSafe(text, ref num2),
|
||||
rightChild = ReadHexIntSafe(text, ref num2),
|
||||
start = ReadHexIntSafe(text, ref num2),
|
||||
count = ReadHexIntSafe(text, ref num2),
|
||||
isLeaf = (num2 < text.Length && text[num2++] == '1')
|
||||
};
|
||||
}
|
||||
for (int m = 0; m < num6; m++)
|
||||
{
|
||||
profileBVH.dataIndices[m] = ReadHexIntSafe(text, ref num2);
|
||||
}
|
||||
return profileBVH;
|
||||
}
|
||||
private ProfileBVH LoadProfileBVHData(string path, out int version)
|
||||
{
|
||||
version = 0;
|
||||
int num = 0;
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH File Not Found", "[ProfileLoader] LoadProfileBVHData\n - file not found\n - path : " + path);
|
||||
}
|
||||
string text = File.ReadAllText(path, Encoding.UTF8);
|
||||
int num2 = 0;
|
||||
ProfileUtils profileUtils = new ProfileUtils();
|
||||
string profileMagic = profileUtils.GetProfileMagic();
|
||||
if (text.Length < profileMagic.Length || text.Substring(0, profileMagic.Length) != profileMagic)
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Magic Mismatch", "[ProfileLoader] LoadProfileBVHData\n - magic string mismatch\n - invalid or corrupted BVH file");
|
||||
}
|
||||
num2 += profileMagic.Length;
|
||||
version = this.ReadHexIntSafe(text, ref num2);
|
||||
num = this.ReadHexIntSafe(text, ref num2);
|
||||
int num3 = this.ReadHexIntSafe(text, ref num2);
|
||||
int num4 = this.ReadHexIntSafe(text, ref num2);
|
||||
int num5 = this.ReadHexIntSafe(text, ref num2);
|
||||
int num6 = this.ReadHexIntSafe(text, ref num2);
|
||||
if (num3 < 0 || num4 < 0 || num5 < 0 || num6 < 0)
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Count Data is Invalid", "[ProfileLoader] LoadProfileBVHData\n - one or more count values are negative");
|
||||
}
|
||||
Vector3[] array = new Vector3[num3];
|
||||
for (int i = 0; i < num3; i++)
|
||||
{
|
||||
array[i] = this.ReadHexVec3Safe(text, ref num2);
|
||||
}
|
||||
int version2;
|
||||
int countInFile;
|
||||
BaseKey3[] array2 = new ProfileUtils_VertexUtil().LoadTable(profileUtils.GetBaseDataPath(), out version2, out countInFile);
|
||||
if (array2 == null || array2.Length == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Profile BVH Base Vertex Table is Invalid", "[ProfileLoader] LoadProfileBVHData\n - base vertex table is null or empty");
|
||||
}
|
||||
ProfileUtil_IndexUtil profileUtil_IndexUtil = new ProfileUtil_IndexUtil();
|
||||
profileUtil_IndexUtil.Build(num);
|
||||
Vector3[] array3 = new Vector3[num3];
|
||||
profileUtil_IndexUtil.DecodeInto(array, array3);
|
||||
Vector3[] array4 = new Vector3[num3];
|
||||
for (int j = 0; j < num3; j++)
|
||||
{
|
||||
array4[j] = this.TransformVec3(array3[j], array2[j % array2.Length]);
|
||||
}
|
||||
ProfileBVH profileBVH = new ProfileBVH
|
||||
{
|
||||
vertices = new List<Vector3>(num3),
|
||||
datas = new profileBVHData[num4],
|
||||
nodes = new profileBVHNode[num5],
|
||||
dataIndices = new int[num6]
|
||||
};
|
||||
profileBVH.vertices.AddRange(array4);
|
||||
for (int k = 0; k < num4; k++)
|
||||
{
|
||||
profileBVH.datas[k] = new profileBVHData
|
||||
{
|
||||
verA = this.ReadHexIntSafe(text, ref num2),
|
||||
verB = this.ReadHexIntSafe(text, ref num2),
|
||||
verC = this.ReadHexIntSafe(text, ref num2)
|
||||
};
|
||||
}
|
||||
for (int l = 0; l < num5; l++)
|
||||
{
|
||||
Vector3 center = this.ReadHexVec3Safe(text, ref num2);
|
||||
Vector3 vector = this.ReadHexVec3Safe(text, ref num2);
|
||||
profileBVH.nodes[l] = new profileBVHNode
|
||||
{
|
||||
bounds = new Bounds(center, vector * 2f),
|
||||
leftChild = this.ReadHexIntSafe(text, ref num2),
|
||||
rightChild = this.ReadHexIntSafe(text, ref num2),
|
||||
start = this.ReadHexIntSafe(text, ref num2),
|
||||
count = this.ReadHexIntSafe(text, ref num2),
|
||||
isLeaf = (num2 < text.Length && text[num2++] == '1')
|
||||
};
|
||||
}
|
||||
for (int m = 0; m < num6; m++)
|
||||
{
|
||||
profileBVH.dataIndices[m] = this.ReadHexIntSafe(text, ref num2);
|
||||
}
|
||||
return profileBVH;
|
||||
}
|
||||
|
||||
private int ReadHexIntSafe(string s, ref int p)
|
||||
{
|
||||
if (p + 8 > s.Length)
|
||||
{
|
||||
p = s.Length;
|
||||
throw new AutoMorpherException("Profile BVH ReadHexInt Out of Range", "[ProfileBVH] ReadHexIntSafe\n - read position exceeds string length");
|
||||
}
|
||||
uint result = Convert.ToUInt32(s.Substring(p, 8), 16);
|
||||
p += 8;
|
||||
return (int)result;
|
||||
}
|
||||
private int ReadHexIntSafe(string s, ref int p)
|
||||
{
|
||||
if (p + 8 > s.Length)
|
||||
{
|
||||
p = s.Length;
|
||||
throw new AutoMorpherException("Profile BVH ReadHexInt Out of Range", "[ProfileBVH] ReadHexIntSafe\n - read position exceeds string length");
|
||||
}
|
||||
uint result = Convert.ToUInt32(s.Substring(p, 8), 16);
|
||||
p += 8;
|
||||
return (int)result;
|
||||
}
|
||||
|
||||
private Vector3 ReadHexVec3Safe(string s, ref int p)
|
||||
{
|
||||
return new Vector3(ReadHexFloatSafe(s, ref p), ReadHexFloatSafe(s, ref p), ReadHexFloatSafe(s, ref p));
|
||||
}
|
||||
private Vector3 ReadHexVec3Safe(string s, ref int p)
|
||||
{
|
||||
return new Vector3(this.ReadHexFloatSafe(s, ref p), this.ReadHexFloatSafe(s, ref p), this.ReadHexFloatSafe(s, ref p));
|
||||
}
|
||||
|
||||
private float ReadHexFloatSafe(string s, ref int p)
|
||||
{
|
||||
if (p + 8 > s.Length)
|
||||
{
|
||||
p = s.Length;
|
||||
throw new AutoMorpherException("Profile BVH ReadHexFloat Out of Range", "[ProfileBVH] ReadHexFloat\n - read position exceeds string length");
|
||||
}
|
||||
uint value = Convert.ToUInt32(s.Substring(p, 8), 16);
|
||||
p += 8;
|
||||
return BitConverter.Int32BitsToSingle((int)value);
|
||||
}
|
||||
private float ReadHexFloatSafe(string s, ref int p)
|
||||
{
|
||||
if (p + 8 > s.Length)
|
||||
{
|
||||
p = s.Length;
|
||||
throw new AutoMorpherException("Profile BVH ReadHexFloat Out of Range", "[ProfileBVH] ReadHexFloat\n - read position exceeds string length");
|
||||
}
|
||||
uint value = Convert.ToUInt32(s.Substring(p, 8), 16);
|
||||
p += 8;
|
||||
return BitConverter.Int32BitsToSingle((int)value);
|
||||
}
|
||||
|
||||
private Vector3 TransformVec3(Vector3 v, BaseKey3 k)
|
||||
{
|
||||
return new Vector3(TransformFloatBits(v.x, k.x), TransformFloatBits(v.y, k.y), TransformFloatBits(v.z, k.z));
|
||||
}
|
||||
private Vector3 TransformVec3(Vector3 v, BaseKey3 k)
|
||||
{
|
||||
return new Vector3(this.TransformFloatBits(v.x, k.x), this.TransformFloatBits(v.y, k.y), this.TransformFloatBits(v.z, k.z));
|
||||
}
|
||||
|
||||
private float TransformFloatBits(float a, uint keyBits)
|
||||
{
|
||||
return BitConverter.Int32BitsToSingle(BitConverter.SingleToInt32Bits(a) ^ (int)keyBits);
|
||||
}
|
||||
private float TransformFloatBits(float a, uint keyBits)
|
||||
{
|
||||
return BitConverter.Int32BitsToSingle(BitConverter.SingleToInt32Bits(a) ^ (int)keyBits);
|
||||
}
|
||||
|
||||
private Vector3 ComputeTriangleNormal(Vector3 a, Vector3 b, Vector3 c)
|
||||
{
|
||||
Vector3 vector = Vector3.Cross(b - a, c - a);
|
||||
float magnitude = vector.magnitude;
|
||||
if (magnitude > 1E-08f)
|
||||
{
|
||||
return vector / magnitude;
|
||||
}
|
||||
return Vector3.up;
|
||||
}
|
||||
private Vector3 ComputeTriangleNormal(Vector3 a, Vector3 b, Vector3 c)
|
||||
{
|
||||
Vector3 vector = Vector3.Cross(b - a, c - a);
|
||||
float magnitude = vector.magnitude;
|
||||
if (magnitude > 1E-08f)
|
||||
{
|
||||
return vector / magnitude;
|
||||
}
|
||||
return Vector3.up;
|
||||
}
|
||||
|
||||
private Bounds TransformBoundsToWorldAABB(Matrix4x4 l2w, Bounds localBounds)
|
||||
{
|
||||
Vector3 center = localBounds.center;
|
||||
Vector3 extents = localBounds.extents;
|
||||
Vector3 vector = l2w.MultiplyPoint3x4(center + new Vector3(0f - extents.x, 0f - extents.y, 0f - extents.z));
|
||||
Vector3 p = l2w.MultiplyPoint3x4(center + new Vector3(0f - extents.x, 0f - extents.y, extents.z));
|
||||
Vector3 p2 = l2w.MultiplyPoint3x4(center + new Vector3(0f - extents.x, extents.y, 0f - extents.z));
|
||||
Vector3 p3 = l2w.MultiplyPoint3x4(center + new Vector3(0f - extents.x, extents.y, extents.z));
|
||||
Vector3 p4 = l2w.MultiplyPoint3x4(center + new Vector3(extents.x, 0f - extents.y, 0f - extents.z));
|
||||
Vector3 p5 = l2w.MultiplyPoint3x4(center + new Vector3(extents.x, 0f - extents.y, extents.z));
|
||||
Vector3 p6 = l2w.MultiplyPoint3x4(center + new Vector3(extents.x, extents.y, 0f - extents.z));
|
||||
Vector3 p7 = l2w.MultiplyPoint3x4(center + new Vector3(extents.x, extents.y, extents.z));
|
||||
Vector3 min = vector;
|
||||
Vector3 max = vector;
|
||||
Encapsulate(ref min, ref max, p);
|
||||
Encapsulate(ref min, ref max, p2);
|
||||
Encapsulate(ref min, ref max, p3);
|
||||
Encapsulate(ref min, ref max, p4);
|
||||
Encapsulate(ref min, ref max, p5);
|
||||
Encapsulate(ref min, ref max, p6);
|
||||
Encapsulate(ref min, ref max, p7);
|
||||
return new Bounds((min + max) * 0.5f, max - min);
|
||||
}
|
||||
private Bounds TransformBoundsToWorldAABB(Matrix4x4 l2w, Bounds localBounds)
|
||||
{
|
||||
Vector3 center = localBounds.center;
|
||||
Vector3 extents = localBounds.extents;
|
||||
Vector3 vector = l2w.MultiplyPoint3x4(center + new Vector3(0f - extents.x, 0f - extents.y, 0f - extents.z));
|
||||
Vector3 p = l2w.MultiplyPoint3x4(center + new Vector3(0f - extents.x, 0f - extents.y, extents.z));
|
||||
Vector3 p2 = l2w.MultiplyPoint3x4(center + new Vector3(0f - extents.x, extents.y, 0f - extents.z));
|
||||
Vector3 p3 = l2w.MultiplyPoint3x4(center + new Vector3(0f - extents.x, extents.y, extents.z));
|
||||
Vector3 p4 = l2w.MultiplyPoint3x4(center + new Vector3(extents.x, 0f - extents.y, 0f - extents.z));
|
||||
Vector3 p5 = l2w.MultiplyPoint3x4(center + new Vector3(extents.x, 0f - extents.y, extents.z));
|
||||
Vector3 p6 = l2w.MultiplyPoint3x4(center + new Vector3(extents.x, extents.y, 0f - extents.z));
|
||||
Vector3 p7 = l2w.MultiplyPoint3x4(center + new Vector3(extents.x, extents.y, extents.z));
|
||||
Vector3 min = vector;
|
||||
Vector3 max = vector;
|
||||
this.Encapsulate(ref min, ref max, p);
|
||||
this.Encapsulate(ref min, ref max, p2);
|
||||
this.Encapsulate(ref min, ref max, p3);
|
||||
this.Encapsulate(ref min, ref max, p4);
|
||||
this.Encapsulate(ref min, ref max, p5);
|
||||
this.Encapsulate(ref min, ref max, p6);
|
||||
this.Encapsulate(ref min, ref max, p7);
|
||||
return new Bounds((min + max) * 0.5f, max - min);
|
||||
}
|
||||
|
||||
private void Encapsulate(ref Vector3 min, ref Vector3 max, Vector3 p)
|
||||
{
|
||||
min = Vector3.Min(min, p);
|
||||
max = Vector3.Max(max, p);
|
||||
}
|
||||
private void Encapsulate(ref Vector3 min, ref Vector3 max, Vector3 p)
|
||||
{
|
||||
min = Vector3.Min(min, p);
|
||||
max = Vector3.Max(max, p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +1,78 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.profile.ProfilePoseMatchUtil
|
||||
using System.Collections.Generic;
|
||||
using Eden.AutoMorpher;
|
||||
using Eden.AutoMorpher.profile;
|
||||
using UnityEngine;
|
||||
|
||||
public class ProfilePoseMatchUtil
|
||||
{
|
||||
private WorldVertexUtil _worldVertexUtil;
|
||||
private WorldVertexUtil _worldVertexUtil;
|
||||
|
||||
private MeshClassifier meshClassifier;
|
||||
private MeshClassifier meshClassifier;
|
||||
|
||||
public ProfilePoseMatchUtil()
|
||||
{
|
||||
_worldVertexUtil = new WorldVertexUtil();
|
||||
meshClassifier = new MeshClassifier();
|
||||
}
|
||||
public ProfilePoseMatchUtil()
|
||||
{
|
||||
this._worldVertexUtil = new WorldVertexUtil();
|
||||
this.meshClassifier = new MeshClassifier();
|
||||
}
|
||||
|
||||
public void ProfilePoseMatcher(GameObject targetAvatar, IReadOnlyList<SkinnedMeshRenderer> targetBodyMeshes, GameObject targetCloth, ProfileData profileData, Dictionary<HumanBodyBones, HashSet<Transform>> clothHumanBonesMap, Dictionary<Transform, ClothBoneType> clothBoneTypeMap, float neckTargetHeight = 1.5f)
|
||||
{
|
||||
if (targetAvatar == null)
|
||||
{
|
||||
throw new AutoMorpherException("Target Avatar is Null", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - targetAvatar is null");
|
||||
}
|
||||
if (targetAvatar.GetComponent<Animator>() == null)
|
||||
{
|
||||
throw new AutoMorpherException("Target Avatar Animator is Null", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - targetAvatar has no animator");
|
||||
}
|
||||
if (targetBodyMeshes == null || targetBodyMeshes.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Target Body Meshes are Missing", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - targetBodyMeshes is null or empty");
|
||||
}
|
||||
if (targetCloth == null)
|
||||
{
|
||||
throw new AutoMorpherException("Target Cloth is Null", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - targetCloth is null");
|
||||
}
|
||||
if (profileData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Data is Null", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - profileData is null");
|
||||
}
|
||||
if (clothHumanBonesMap == null || clothHumanBonesMap.Count == 0 || clothBoneTypeMap == null || clothBoneTypeMap.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Clothing Bone Match Data is Missing", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - profile Clothe Bone Match Data is null or empty");
|
||||
}
|
||||
Transform transform = targetAvatar.transform;
|
||||
Transform transform2 = targetCloth.transform;
|
||||
Transform parent = transform.parent;
|
||||
transform.SetParent(null, worldPositionStays: true);
|
||||
Transform parent2 = transform2.parent;
|
||||
transform2.SetParent(null, worldPositionStays: true);
|
||||
transform2.position = transform.position;
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary = meshClassifier.MeshHumanoidBoneMatcher(targetAvatar.GetComponent<Animator>(), targetBodyMeshes);
|
||||
if (dictionary == null || dictionary.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Target Avatar Bone Match Data is Missing", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - target Avatar Bone Match Data is null or empty");
|
||||
}
|
||||
BodyPoseMatchSetupUtil bodyPoseMatchSetupUtil = new BodyPoseMatchSetupUtil();
|
||||
Vector3 comprehensiveScale = bodyPoseMatchSetupUtil.GetComprehensiveScale(transform2, clothHumanBonesMap, profileData);
|
||||
Debug.Log($"ComprehensiveScale: {comprehensiveScale}");
|
||||
bodyPoseMatchSetupUtil.AdjustAvatarScaleByNeck(transform, dictionary, neckTargetHeight);
|
||||
bodyPoseMatchSetupUtil.AdjustAvatarScaleByNeck(transform2, clothHumanBonesMap, neckTargetHeight);
|
||||
List<BakedBodyMesh> list = new List<BakedBodyMesh>();
|
||||
foreach (SkinnedMeshRenderer targetBodyMesh in targetBodyMeshes)
|
||||
{
|
||||
list.Add(new BakedBodyMesh(targetBodyMesh));
|
||||
}
|
||||
new BodyPoseMatch_Torso().AlignTorsoByNeck(transform, list, dictionary, clothHumanBonesMap, transform2, profileData, comprehensiveScale);
|
||||
BodyPoseMatch_Arm bodyPoseMatch_Arm = new BodyPoseMatch_Arm();
|
||||
bodyPoseMatch_Arm.AlignUpperArmByArmPcaCenters(list, dictionary, clothHumanBonesMap, transform2, profileData, comprehensiveScale);
|
||||
bodyPoseMatch_Arm.ScalingBothArmsLength(list, dictionary, clothHumanBonesMap, profileData, comprehensiveScale);
|
||||
BodyPoseMatch_Leg bodyPoseMatch_Leg = new BodyPoseMatch_Leg();
|
||||
bodyPoseMatch_Leg.AlignBothUpperLegs(transform, list, dictionary, transform2, clothHumanBonesMap, profileData, comprehensiveScale);
|
||||
bodyPoseMatch_Leg.ScalingBothLegsAndFoots(transform, list, dictionary, transform2, clothHumanBonesMap, profileData, comprehensiveScale);
|
||||
transform.SetParent(parent, worldPositionStays: true);
|
||||
transform2.SetParent(parent2, worldPositionStays: true);
|
||||
}
|
||||
public void ProfilePoseMatcher(GameObject targetAvatar, IReadOnlyList<SkinnedMeshRenderer> targetBodyMeshes, GameObject targetCloth, ProfileData profileData, Dictionary<HumanBodyBones, HashSet<Transform>> clothHumanBonesMap, Dictionary<Transform, ClothBoneType> clothBoneTypeMap, float neckTargetHeight = 1.5f)
|
||||
{
|
||||
if (targetAvatar == null)
|
||||
{
|
||||
throw new AutoMorpherException("Target Avatar is Null", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - targetAvatar is null");
|
||||
}
|
||||
if (targetAvatar.GetComponent<Animator>() == null)
|
||||
{
|
||||
throw new AutoMorpherException("Target Avatar Animator is Null", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - targetAvatar has no animator");
|
||||
}
|
||||
if (targetBodyMeshes == null || targetBodyMeshes.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Target Body Meshes are Missing", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - targetBodyMeshes is null or empty");
|
||||
}
|
||||
if (targetCloth == null)
|
||||
{
|
||||
throw new AutoMorpherException("Target Cloth is Null", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - targetCloth is null");
|
||||
}
|
||||
if (profileData == null)
|
||||
{
|
||||
throw new AutoMorpherException("Profile Data is Null", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - profileData is null");
|
||||
}
|
||||
if (clothHumanBonesMap == null || clothHumanBonesMap.Count == 0 || clothBoneTypeMap == null || clothBoneTypeMap.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Clothing Bone Match Data is Missing", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - profile Clothe Bone Match Data is null or empty");
|
||||
}
|
||||
Transform transform = targetAvatar.transform;
|
||||
Transform transform2 = targetCloth.transform;
|
||||
Transform parent = transform.parent;
|
||||
transform.SetParent(null, worldPositionStays: true);
|
||||
Transform parent2 = transform2.parent;
|
||||
transform2.SetParent(null, worldPositionStays: true);
|
||||
transform2.position = transform.position;
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary = this.meshClassifier.MeshHumanoidBoneMatcher(targetAvatar.GetComponent<Animator>(), targetBodyMeshes);
|
||||
if (dictionary == null || dictionary.Count == 0)
|
||||
{
|
||||
throw new AutoMorpherException("Target Avatar Bone Match Data is Missing", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - target Avatar Bone Match Data is null or empty");
|
||||
}
|
||||
BodyPoseMatchSetupUtil bodyPoseMatchSetupUtil = new BodyPoseMatchSetupUtil();
|
||||
Vector3 comprehensiveScale = bodyPoseMatchSetupUtil.GetComprehensiveScale(transform2, clothHumanBonesMap, profileData);
|
||||
Debug.Log($"ComprehensiveScale: {comprehensiveScale}");
|
||||
bodyPoseMatchSetupUtil.AdjustAvatarScaleByNeck(transform, dictionary, neckTargetHeight);
|
||||
bodyPoseMatchSetupUtil.AdjustAvatarScaleByNeck(transform2, clothHumanBonesMap, neckTargetHeight);
|
||||
List<BakedBodyMesh> list = new List<BakedBodyMesh>();
|
||||
foreach (SkinnedMeshRenderer targetBodyMesh in targetBodyMeshes)
|
||||
{
|
||||
list.Add(new BakedBodyMesh(targetBodyMesh));
|
||||
}
|
||||
new BodyPoseMatch_Torso().AlignTorsoByNeck(transform, list, dictionary, clothHumanBonesMap, transform2, profileData, comprehensiveScale);
|
||||
BodyPoseMatch_Arm bodyPoseMatch_Arm = new BodyPoseMatch_Arm();
|
||||
bodyPoseMatch_Arm.AlignUpperArmByArmPcaCenters(list, dictionary, clothHumanBonesMap, transform2, profileData, comprehensiveScale);
|
||||
bodyPoseMatch_Arm.ScalingBothArmsLength(list, dictionary, clothHumanBonesMap, profileData, comprehensiveScale);
|
||||
BodyPoseMatch_Leg bodyPoseMatch_Leg = new BodyPoseMatch_Leg();
|
||||
bodyPoseMatch_Leg.AlignBothUpperLegs(transform, list, dictionary, transform2, clothHumanBonesMap, profileData, comprehensiveScale);
|
||||
bodyPoseMatch_Leg.ScalingBothLegsAndFoots(transform, list, dictionary, transform2, clothHumanBonesMap, profileData, comprehensiveScale);
|
||||
transform.SetParent(parent, worldPositionStays: true);
|
||||
transform2.SetParent(parent2, worldPositionStays: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.RegionStats
|
||||
@@ -6,11 +6,11 @@ using UnityEngine;
|
||||
|
||||
public struct RegionStats
|
||||
{
|
||||
public Vector3 center;
|
||||
public Vector3 center;
|
||||
|
||||
public Vector3 principalAxis;
|
||||
public Vector3 principalAxis;
|
||||
|
||||
public float length;
|
||||
public float length;
|
||||
|
||||
public float avgRadius;
|
||||
public float avgRadius;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.SkinningUtil
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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
|
||||
// TempBoneMarker
|
||||
@@ -7,9 +7,9 @@ using UnityEngine;
|
||||
|
||||
public class TempBoneMarker : MonoBehaviour
|
||||
{
|
||||
public Transform originalParent;
|
||||
public Transform originalParent;
|
||||
|
||||
public string additionalInfo = "";
|
||||
public string additionalInfo = "";
|
||||
|
||||
public List<string> wrappedChildNames = new List<string>();
|
||||
public List<string> wrappedChildNames = new List<string>();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.TransformInfo
|
||||
@@ -6,67 +6,67 @@ using UnityEngine;
|
||||
|
||||
public class TransformInfo
|
||||
{
|
||||
public Transform parentTransform;
|
||||
public Transform parentTransform;
|
||||
|
||||
public Vector3 position;
|
||||
public Vector3 position;
|
||||
|
||||
public Vector3 localPosition;
|
||||
public Vector3 localPosition;
|
||||
|
||||
public Quaternion rotation;
|
||||
public Quaternion rotation;
|
||||
|
||||
public Quaternion localRotation;
|
||||
public Quaternion localRotation;
|
||||
|
||||
public Vector3 localScale;
|
||||
public Vector3 localScale;
|
||||
|
||||
public string name;
|
||||
public string name;
|
||||
|
||||
public TransformInfo(Transform t)
|
||||
{
|
||||
parentTransform = t.parent;
|
||||
position = t.position;
|
||||
localPosition = t.localPosition;
|
||||
rotation = t.rotation;
|
||||
localRotation = t.localRotation;
|
||||
localScale = t.localScale;
|
||||
name = t.name;
|
||||
}
|
||||
public TransformInfo(Transform t)
|
||||
{
|
||||
this.parentTransform = t.parent;
|
||||
this.position = t.position;
|
||||
this.localPosition = t.localPosition;
|
||||
this.rotation = t.rotation;
|
||||
this.localRotation = t.localRotation;
|
||||
this.localScale = t.localScale;
|
||||
this.name = t.name;
|
||||
}
|
||||
|
||||
public void ApplyToTransform(Transform t, bool applyParent, bool applyPosition, bool applyRotation, bool applyScale, bool applyName = false)
|
||||
{
|
||||
if (applyParent)
|
||||
{
|
||||
t.SetParent(parentTransform, worldPositionStays: true);
|
||||
if (applyPosition)
|
||||
{
|
||||
t.localPosition = localPosition;
|
||||
}
|
||||
if (applyRotation)
|
||||
{
|
||||
t.localRotation = localRotation;
|
||||
}
|
||||
if (applyScale)
|
||||
{
|
||||
t.localScale = localScale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (applyPosition)
|
||||
{
|
||||
t.position = position;
|
||||
}
|
||||
if (applyRotation)
|
||||
{
|
||||
t.rotation = rotation;
|
||||
}
|
||||
if (applyScale)
|
||||
{
|
||||
t.localScale = localScale;
|
||||
}
|
||||
}
|
||||
if (applyName)
|
||||
{
|
||||
t.name = name;
|
||||
}
|
||||
}
|
||||
public void ApplyToTransform(Transform t, bool applyParent, bool applyPosition, bool applyRotation, bool applyScale, bool applyName = false)
|
||||
{
|
||||
if (applyParent)
|
||||
{
|
||||
t.SetParent(this.parentTransform, worldPositionStays: true);
|
||||
if (applyPosition)
|
||||
{
|
||||
t.localPosition = this.localPosition;
|
||||
}
|
||||
if (applyRotation)
|
||||
{
|
||||
t.localRotation = this.localRotation;
|
||||
}
|
||||
if (applyScale)
|
||||
{
|
||||
t.localScale = this.localScale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (applyPosition)
|
||||
{
|
||||
t.position = this.position;
|
||||
}
|
||||
if (applyRotation)
|
||||
{
|
||||
t.rotation = this.rotation;
|
||||
}
|
||||
if (applyScale)
|
||||
{
|
||||
t.localScale = this.localScale;
|
||||
}
|
||||
}
|
||||
if (applyName)
|
||||
{
|
||||
t.name = this.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.TriangleUtil
|
||||
@@ -6,52 +6,52 @@ using UnityEngine;
|
||||
|
||||
public class TriangleUtil
|
||||
{
|
||||
public Vector3 ClosestPointOnTriangle(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
|
||||
{
|
||||
Vector3 vector = b - a;
|
||||
Vector3 vector2 = c - a;
|
||||
Vector3 rhs = p - a;
|
||||
float num = Vector3.Dot(vector, rhs);
|
||||
float num2 = Vector3.Dot(vector2, rhs);
|
||||
if (num <= 0f && num2 <= 0f)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
Vector3 rhs2 = p - b;
|
||||
float num3 = Vector3.Dot(vector, rhs2);
|
||||
float num4 = Vector3.Dot(vector2, rhs2);
|
||||
if (num3 >= 0f && num4 <= num3)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
float num5 = num * num4 - num3 * num2;
|
||||
if (num5 <= 0f && num >= 0f && num3 <= 0f)
|
||||
{
|
||||
float num6 = num / (num - num3);
|
||||
return a + num6 * vector;
|
||||
}
|
||||
Vector3 rhs3 = p - c;
|
||||
float num7 = Vector3.Dot(vector, rhs3);
|
||||
float num8 = Vector3.Dot(vector2, rhs3);
|
||||
if (num8 >= 0f && num7 <= num8)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
float num9 = num7 * num2 - num * num8;
|
||||
if (num9 <= 0f && num2 >= 0f && num8 <= 0f)
|
||||
{
|
||||
float num10 = num2 / (num2 - num8);
|
||||
return a + num10 * vector2;
|
||||
}
|
||||
float num11 = num3 * num8 - num7 * num4;
|
||||
if (num11 <= 0f && num4 - num3 >= 0f && num7 - num8 >= 0f)
|
||||
{
|
||||
float num12 = (num4 - num3) / (num4 - num3 + (num7 - num8));
|
||||
return b + num12 * (c - b);
|
||||
}
|
||||
float num13 = 1f / (num11 + num9 + num5);
|
||||
float num14 = num9 * num13;
|
||||
float num15 = num5 * num13;
|
||||
return a + vector * num14 + vector2 * num15;
|
||||
}
|
||||
public Vector3 ClosestPointOnTriangle(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
|
||||
{
|
||||
Vector3 vector = b - a;
|
||||
Vector3 vector2 = c - a;
|
||||
Vector3 rhs = p - a;
|
||||
float num = Vector3.Dot(vector, rhs);
|
||||
float num2 = Vector3.Dot(vector2, rhs);
|
||||
if (num <= 0f && num2 <= 0f)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
Vector3 rhs2 = p - b;
|
||||
float num3 = Vector3.Dot(vector, rhs2);
|
||||
float num4 = Vector3.Dot(vector2, rhs2);
|
||||
if (num3 >= 0f && num4 <= num3)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
float num5 = num * num4 - num3 * num2;
|
||||
if (num5 <= 0f && num >= 0f && num3 <= 0f)
|
||||
{
|
||||
float num6 = num / (num - num3);
|
||||
return a + num6 * vector;
|
||||
}
|
||||
Vector3 rhs3 = p - c;
|
||||
float num7 = Vector3.Dot(vector, rhs3);
|
||||
float num8 = Vector3.Dot(vector2, rhs3);
|
||||
if (num8 >= 0f && num7 <= num8)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
float num9 = num7 * num2 - num * num8;
|
||||
if (num9 <= 0f && num2 >= 0f && num8 <= 0f)
|
||||
{
|
||||
float num10 = num2 / (num2 - num8);
|
||||
return a + num10 * vector2;
|
||||
}
|
||||
float num11 = num3 * num8 - num7 * num4;
|
||||
if (num11 <= 0f && num4 - num3 >= 0f && num7 - num8 >= 0f)
|
||||
{
|
||||
float num12 = (num4 - num3) / (num4 - num3 + (num7 - num8));
|
||||
return b + num12 * (c - b);
|
||||
}
|
||||
float num13 = 1f / (num11 + num9 + num5);
|
||||
float num14 = num9 * num13;
|
||||
float num15 = num5 * num13;
|
||||
return a + vector * num14 + vector2 * num15;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.VertexFittingUtil
|
||||
|
||||
@@ -1,173 +1,172 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.VertexMoverUtil
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public class VertexMoverUtil
|
||||
{
|
||||
public Vector3[] MoveVertices(ClothInstance cloth, Vector3 targetPoint, bool centerIsLeftLeg, bool centerIsRightLeg, float maxRadius, float param, Vector3 vertexMovement)
|
||||
{
|
||||
if (cloth == null || cloth.worldVertices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth or World Vertices are Missing", "[MoveVertices] MoveVertices\n - cloth is null or cloth.worldVertices is null");
|
||||
}
|
||||
Vector3[] worldVertices = cloth.worldVertices;
|
||||
int num = worldVertices.Length;
|
||||
bool[] isInboundVerts;
|
||||
float[] array = ComputeEuclideanDistances(worldVertices, targetPoint, maxRadius, out isInboundVerts);
|
||||
if (array == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
float[] array2 = ComputeKernelWeights(array, isInboundVerts, maxRadius, WeightKernel.Gaussian, param);
|
||||
Vector3[] array3 = new Vector3[num];
|
||||
bool[] isLeftLegVertex = cloth.isLeftLegVertex;
|
||||
bool[] isRightLegVertex = cloth.isRightLegVertex;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (!isInboundVerts[i])
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (centerIsLeftLeg && IsRightLegVertex(isRightLegVertex, i))
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (centerIsRightLeg && IsLeftLegVertex(isLeftLegVertex, i))
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
float num2 = array2[i];
|
||||
array3[i] = vertexMovement * num2;
|
||||
}
|
||||
return array3;
|
||||
}
|
||||
public Vector3[] MoveVertices(ClothInstance cloth, Vector3 targetPoint, bool centerIsLeftLeg, bool centerIsRightLeg, float maxRadius, float param, Vector3 vertexMovement)
|
||||
{
|
||||
if (cloth == null || cloth.worldVertices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth or World Vertices are Missing", "[MoveVertices] MoveVertices\n - cloth is null or cloth.worldVertices is null");
|
||||
}
|
||||
Vector3[] worldVertices = cloth.worldVertices;
|
||||
int num = worldVertices.Length;
|
||||
bool[] isInboundVerts;
|
||||
float[] array = this.ComputeEuclideanDistances(worldVertices, targetPoint, maxRadius, out isInboundVerts);
|
||||
if (array == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
float[] array2 = this.ComputeKernelWeights(array, isInboundVerts, maxRadius, WeightKernel.Gaussian, param);
|
||||
Vector3[] array3 = new Vector3[num];
|
||||
bool[] isLeftLegVertex = cloth.isLeftLegVertex;
|
||||
bool[] isRightLegVertex = cloth.isRightLegVertex;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (!isInboundVerts[i])
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (centerIsLeftLeg && this.IsRightLegVertex(isRightLegVertex, i))
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (centerIsRightLeg && this.IsLeftLegVertex(isLeftLegVertex, i))
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
float num2 = array2[i];
|
||||
array3[i] = vertexMovement * num2;
|
||||
}
|
||||
return array3;
|
||||
}
|
||||
|
||||
public Vector3[] MoveVertices(ClothInstance cloth, int targetVertexIdx, bool centerIsLeftLeg, bool centerIsRightLeg, float maxRadius, float param, Vector3 vertexMovement)
|
||||
{
|
||||
if (cloth == null || cloth.worldVertices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth or World Vertices are Missing", "[MoveVertices] MoveVertices\n - cloth is null or cloth.worldVertices is null");
|
||||
}
|
||||
Vector3[] worldVertices = cloth.worldVertices;
|
||||
int num = worldVertices.Length;
|
||||
bool[] isInboundVerts;
|
||||
float[] array = ComputeEuclideanDistances(worldVertices, targetVertexIdx, maxRadius, out isInboundVerts);
|
||||
if (array == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
float[] array2 = ComputeKernelWeights(array, isInboundVerts, maxRadius, WeightKernel.Gaussian, param);
|
||||
Vector3[] array3 = new Vector3[num];
|
||||
bool[] isLeftLegVertex = cloth.isLeftLegVertex;
|
||||
bool[] isRightLegVertex = cloth.isRightLegVertex;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (!isInboundVerts[i])
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (centerIsLeftLeg && IsRightLegVertex(isRightLegVertex, i))
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (centerIsRightLeg && IsLeftLegVertex(isLeftLegVertex, i))
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
float num2 = array2[i];
|
||||
array3[i] = vertexMovement * num2;
|
||||
}
|
||||
return array3;
|
||||
}
|
||||
public Vector3[] MoveVertices(ClothInstance cloth, int targetVertexIdx, bool centerIsLeftLeg, bool centerIsRightLeg, float maxRadius, float param, Vector3 vertexMovement)
|
||||
{
|
||||
if (cloth == null || cloth.worldVertices == null)
|
||||
{
|
||||
throw new AutoMorpherException("Cloth or World Vertices are Missing", "[MoveVertices] MoveVertices\n - cloth is null or cloth.worldVertices is null");
|
||||
}
|
||||
Vector3[] worldVertices = cloth.worldVertices;
|
||||
int num = worldVertices.Length;
|
||||
bool[] isInboundVerts;
|
||||
float[] array = this.ComputeEuclideanDistances(worldVertices, targetVertexIdx, maxRadius, out isInboundVerts);
|
||||
if (array == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
float[] array2 = this.ComputeKernelWeights(array, isInboundVerts, maxRadius, WeightKernel.Gaussian, param);
|
||||
Vector3[] array3 = new Vector3[num];
|
||||
bool[] isLeftLegVertex = cloth.isLeftLegVertex;
|
||||
bool[] isRightLegVertex = cloth.isRightLegVertex;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (!isInboundVerts[i])
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (centerIsLeftLeg && this.IsRightLegVertex(isRightLegVertex, i))
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
if (centerIsRightLeg && this.IsLeftLegVertex(isLeftLegVertex, i))
|
||||
{
|
||||
array3[i] = Vector3.zero;
|
||||
continue;
|
||||
}
|
||||
float num2 = array2[i];
|
||||
array3[i] = vertexMovement * num2;
|
||||
}
|
||||
return array3;
|
||||
}
|
||||
|
||||
private float[] ComputeEuclideanDistances(Vector3[] verts, int targetVertIdx, float maxRadius, out bool[] isInboundVerts)
|
||||
{
|
||||
return ComputeEuclideanDistances(verts, verts[targetVertIdx], maxRadius, out isInboundVerts);
|
||||
}
|
||||
private float[] ComputeEuclideanDistances(Vector3[] verts, int targetVertIdx, float maxRadius, out bool[] isInboundVerts)
|
||||
{
|
||||
return this.ComputeEuclideanDistances(verts, verts[targetVertIdx], maxRadius, out isInboundVerts);
|
||||
}
|
||||
|
||||
private float[] ComputeEuclideanDistances(Vector3[] verts, Vector3 targetVert, float maxRadius, out bool[] isInboundVerts)
|
||||
{
|
||||
int num = verts.Length;
|
||||
float[] array = new float[num];
|
||||
isInboundVerts = new bool[num];
|
||||
bool flag = false;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
array[i] = Vector3.Distance(verts[i], targetVert);
|
||||
isInboundVerts[i] = array[i] <= maxRadius;
|
||||
flag |= isInboundVerts[i];
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
private float[] ComputeEuclideanDistances(Vector3[] verts, Vector3 targetVert, float maxRadius, out bool[] isInboundVerts)
|
||||
{
|
||||
int num = verts.Length;
|
||||
float[] array = new float[num];
|
||||
isInboundVerts = new bool[num];
|
||||
bool flag = false;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
array[i] = Vector3.Distance(verts[i], targetVert);
|
||||
isInboundVerts[i] = array[i] <= maxRadius;
|
||||
flag |= isInboundVerts[i];
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private float ComputeGaussianWeight(float distance, float alpah)
|
||||
{
|
||||
return Mathf.Exp((0f - distance * distance) / (2f * alpah * alpah));
|
||||
}
|
||||
private float ComputeGaussianWeight(float distance, float alpah)
|
||||
{
|
||||
return Mathf.Exp((0f - distance * distance) / (2f * alpah * alpah));
|
||||
}
|
||||
|
||||
private float ComputeLaplacianWeight(float distance, float beta)
|
||||
{
|
||||
return Mathf.Exp(0f - distance / beta);
|
||||
}
|
||||
private float ComputeLaplacianWeight(float distance, float beta)
|
||||
{
|
||||
return Mathf.Exp(0f - distance / beta);
|
||||
}
|
||||
|
||||
private float[] ComputeKernelWeights(float[] dist, bool[] isInboundVerts, float maxRadius, WeightKernel kernel, float param)
|
||||
{
|
||||
int num = dist.Length;
|
||||
float[] array = new float[num];
|
||||
float num2 = Mathf.Max(1E-08f, param);
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (!isInboundVerts[i])
|
||||
{
|
||||
array[i] = 0f;
|
||||
continue;
|
||||
}
|
||||
switch (kernel)
|
||||
{
|
||||
case WeightKernel.Gaussian:
|
||||
array[i] = ComputeGaussianWeight(dist[i], num2);
|
||||
break;
|
||||
case WeightKernel.Laplacian:
|
||||
array[i] = ComputeLaplacianWeight(dist[i], num2);
|
||||
break;
|
||||
default:
|
||||
array[i] = 0f;
|
||||
break;
|
||||
}
|
||||
float num3 = 1f - dist[i] / maxRadius;
|
||||
array[i] *= num3 * num3;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
private float[] ComputeKernelWeights(float[] dist, bool[] isInboundVerts, float maxRadius, WeightKernel kernel, float param)
|
||||
{
|
||||
int num = dist.Length;
|
||||
float[] array = new float[num];
|
||||
float num2 = Mathf.Max(1E-08f, param);
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (!isInboundVerts[i])
|
||||
{
|
||||
array[i] = 0f;
|
||||
continue;
|
||||
}
|
||||
switch (kernel)
|
||||
{
|
||||
case WeightKernel.Gaussian:
|
||||
array[i] = this.ComputeGaussianWeight(dist[i], num2);
|
||||
break;
|
||||
case WeightKernel.Laplacian:
|
||||
array[i] = this.ComputeLaplacianWeight(dist[i], num2);
|
||||
break;
|
||||
default:
|
||||
array[i] = 0f;
|
||||
break;
|
||||
}
|
||||
float num3 = 1f - dist[i] / maxRadius;
|
||||
array[i] *= num3 * num3;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private bool IsLeftLegVertex(bool[] leftMask, int index)
|
||||
{
|
||||
if (leftMask != null && index >= 0 && index < leftMask.Length)
|
||||
{
|
||||
return leftMask[index];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private bool IsLeftLegVertex(bool[] leftMask, int index)
|
||||
{
|
||||
if (leftMask != null && index >= 0 && index < leftMask.Length)
|
||||
{
|
||||
return leftMask[index];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsRightLegVertex(bool[] rightMask, int index)
|
||||
{
|
||||
if (rightMask != null && index >= 0 && index < rightMask.Length)
|
||||
{
|
||||
return rightMask[index];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private bool IsRightLegVertex(bool[] rightMask, int index)
|
||||
{
|
||||
if (rightMask != null && index >= 0 && index < rightMask.Length)
|
||||
{
|
||||
return rightMask[index];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.WeightKernel
|
||||
public enum WeightKernel
|
||||
{
|
||||
Gaussian,
|
||||
Laplacian
|
||||
Gaussian,
|
||||
Laplacian
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,68 +1,67 @@
|
||||
// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
|
||||
// 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.WorldVertexUtil
|
||||
using Eden.AutoMorpher;
|
||||
using UnityEngine;
|
||||
|
||||
public class WorldVertexUtil
|
||||
{
|
||||
public Vector3[] GetWorldVertices(SkinnedMeshRenderer smr)
|
||||
{
|
||||
Mesh bakedMesh = new Mesh();
|
||||
return GetWorldVertices(smr, ref bakedMesh);
|
||||
}
|
||||
public Vector3[] GetWorldVertices(SkinnedMeshRenderer smr)
|
||||
{
|
||||
Mesh bakedMesh = new Mesh();
|
||||
return this.GetWorldVertices(smr, ref bakedMesh);
|
||||
}
|
||||
|
||||
public Vector3[] GetWorldVertices(SkinnedMeshRenderer smr, ref Mesh bakedMesh)
|
||||
{
|
||||
if (smr == null)
|
||||
{
|
||||
throw new AutoMorpherException("SkinnedMeshRenderer is Missing", "[SkinnedMeshWorldUtil] GetWorldVertices\n - smr is null");
|
||||
}
|
||||
if (bakedMesh == null)
|
||||
{
|
||||
bakedMesh = new Mesh();
|
||||
}
|
||||
else
|
||||
{
|
||||
bakedMesh.Clear();
|
||||
}
|
||||
smr.BakeMesh(bakedMesh);
|
||||
Transform transform = smr.transform;
|
||||
Vector3 lossyScale = 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));
|
||||
Matrix4x4 matrix4x = transform.localToWorldMatrix * Matrix4x4.Scale(vector);
|
||||
Vector3[] vertices = bakedMesh.vertices;
|
||||
int num = vertices.Length;
|
||||
Vector3[] array = new Vector3[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
array[i] = matrix4x.MultiplyPoint3x4(vertices[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
public Vector3[] GetWorldVertices(SkinnedMeshRenderer smr, ref Mesh bakedMesh)
|
||||
{
|
||||
if (smr == null)
|
||||
{
|
||||
throw new AutoMorpherException("SkinnedMeshRenderer is Missing", "[SkinnedMeshWorldUtil] GetWorldVertices\n - smr is null");
|
||||
}
|
||||
if (bakedMesh == null)
|
||||
{
|
||||
bakedMesh = new Mesh();
|
||||
}
|
||||
else
|
||||
{
|
||||
bakedMesh.Clear();
|
||||
}
|
||||
smr.BakeMesh(bakedMesh);
|
||||
Transform transform = smr.transform;
|
||||
Vector3 lossyScale = 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));
|
||||
Matrix4x4 matrix4x = transform.localToWorldMatrix * Matrix4x4.Scale(vector);
|
||||
Vector3[] vertices = bakedMesh.vertices;
|
||||
int num = vertices.Length;
|
||||
Vector3[] array = new Vector3[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
array[i] = matrix4x.MultiplyPoint3x4(vertices[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public Vector3[] GetWorldVerticesWithBakedMesh(SkinnedMeshRenderer smr, Mesh bakedMesh)
|
||||
{
|
||||
if (smr == null)
|
||||
{
|
||||
throw new AutoMorpherException("SkinnedMeshRenderer is Missing", "[SkinnedMeshWorldUtil] GetWorldVerticesWithBakedMesh\n - smr is null");
|
||||
}
|
||||
if (bakedMesh == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Transform transform = smr.transform;
|
||||
Vector3 lossyScale = 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));
|
||||
Matrix4x4 matrix4x = transform.localToWorldMatrix * Matrix4x4.Scale(vector);
|
||||
Vector3[] vertices = bakedMesh.vertices;
|
||||
int num = vertices.Length;
|
||||
Vector3[] array = new Vector3[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
array[i] = matrix4x.MultiplyPoint3x4(vertices[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
public Vector3[] GetWorldVerticesWithBakedMesh(SkinnedMeshRenderer smr, Mesh bakedMesh)
|
||||
{
|
||||
if (smr == null)
|
||||
{
|
||||
throw new AutoMorpherException("SkinnedMeshRenderer is Missing", "[SkinnedMeshWorldUtil] GetWorldVerticesWithBakedMesh\n - smr is null");
|
||||
}
|
||||
if (bakedMesh == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Transform transform = smr.transform;
|
||||
Vector3 lossyScale = 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));
|
||||
Matrix4x4 matrix4x = transform.localToWorldMatrix * Matrix4x4.Scale(vector);
|
||||
Vector3[] vertices = bakedMesh.vertices;
|
||||
int num = vertices.Length;
|
||||
Vector3[] array = new Vector3[num];
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
array[i] = matrix4x.MultiplyPoint3x4(vertices[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user