Compare commits
1 Commits
Decompile
...
f9c4088ef4
| Author | SHA1 | Date | |
|---|---|---|---|
| f9c4088ef4 |
8
Assets/@Eden_Tools/Eden_AutoMorpher/Script.meta
Normal file
8
Assets/@Eden_Tools/Eden_AutoMorpher/Script.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4603c2167fca184b81e3c38f3c116c0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
53
Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs
Normal file
53
Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.AutoMorpherDev
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public static class AutoMorpherDev
|
||||
{
|
||||
public static bool isDeveloperMode;
|
||||
|
||||
public static void Log(string message)
|
||||
{
|
||||
if (!AutoMorpherDev.isDeveloperMode)
|
||||
return;
|
||||
UnityEngine.Debug.Log((object)message);
|
||||
}
|
||||
|
||||
public static AutoMorpherDev.ScopeTimer Profile(string label)
|
||||
{
|
||||
return new AutoMorpherDev.ScopeTimer(AutoMorpherDev.isDeveloperMode, label);
|
||||
}
|
||||
|
||||
public readonly struct ScopeTimer : IDisposable
|
||||
{
|
||||
private readonly bool _enabled;
|
||||
private readonly string _label;
|
||||
private readonly Stopwatch _sw;
|
||||
|
||||
public ScopeTimer(bool enabled, string label)
|
||||
{
|
||||
this._enabled = enabled;
|
||||
this._label = label;
|
||||
if (enabled)
|
||||
this._sw = Stopwatch.StartNew();
|
||||
else
|
||||
this._sw = (Stopwatch)null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!this._enabled || this._sw == null)
|
||||
return;
|
||||
this._sw.Stop();
|
||||
UnityEngine.Debug.Log((object)$"[DevTimer] {this._label}: {this._sw.ElapsedMilliseconds} ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74e149c92cc858147bcd96dbf83bfce5
|
||||
@@ -0,0 +1,21 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.AutoMorpherException
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class AutoMorpherException : Exception
|
||||
{
|
||||
public string title;
|
||||
|
||||
public AutoMorpherException(string title, string message)
|
||||
: base(message)
|
||||
{
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3893985c83ce4847ba97b12c88c7792
|
||||
32
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs
Normal file
32
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BakedBodyMesh
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BakedBodyMesh
|
||||
{
|
||||
public SkinnedMeshRenderer smr;
|
||||
public Mesh bakedMesh;
|
||||
|
||||
public BakedBodyMesh(SkinnedMeshRenderer _smr)
|
||||
{
|
||||
this.smr = _smr;
|
||||
this.bakedMesh = new Mesh();
|
||||
this.smr.BakeMesh(this.bakedMesh);
|
||||
}
|
||||
|
||||
public void ReBakeMesh() => this.smr.BakeMesh(this.bakedMesh);
|
||||
|
||||
~BakedBodyMesh()
|
||||
{
|
||||
this.smr = (SkinnedMeshRenderer)null;
|
||||
this.bakedMesh = (Mesh)null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 83084f45d44ba1c4088b9c47d504847d
|
||||
@@ -0,0 +1,191 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BodyPoseMatchSetupUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BodyPoseMatchSetupUtil
|
||||
{
|
||||
public void AdjustAvatarScaleByNeck(
|
||||
Transform avatarRoot,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanBoneMap,
|
||||
float targetHeight)
|
||||
{
|
||||
if (Object.op_Equality((Object)avatarRoot, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] NormalizeAvatarScaleByNeck: avatar == null");
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform boneFromBoneMap = new BodyPoseMatch_CommonUtil().GetBoneFromBoneMap(humanBoneMap, (HumanBodyBones)9);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)$"[AvatarBodyMatchUtil] {((Object)avatarRoot).name} 에서 Neck 본을 찾지 못했습니다. 스케일 정규화를 건너뜁니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform transform = ((Component)avatarRoot).transform;
|
||||
float num1 = boneFromBoneMap.position.y - transform.position.y;
|
||||
if (Mathf.Approximately(num1, 0.0f))
|
||||
{
|
||||
Debug.LogWarning((object)$"[AvatarBodyMatchUtil] {((Object)avatarRoot).name} Neck Y가 0에 가까워 스케일 계산을 건너뜁니다. (neckY = {num1})");
|
||||
}
|
||||
else
|
||||
{
|
||||
float num2 = targetHeight / num1;
|
||||
Vector3 vector3 = Vector3.op_Multiply(transform.localScale, num2);
|
||||
transform.localScale = vector3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject CreateBodyProxy(
|
||||
Animator sourceAvatar,
|
||||
IReadOnlyList<SkinnedMeshRenderer> sourceBodyMeshes,
|
||||
out List<SkinnedMeshRenderer> proxyBodyMeshes,
|
||||
out Dictionary<Transform, Transform> sourceToProxy)
|
||||
{
|
||||
proxyBodyMeshes = (List<SkinnedMeshRenderer>)null;
|
||||
if (Object.op_Equality((Object)sourceAvatar, (Object)null))
|
||||
{
|
||||
Debug.LogError((object)"[AvatarBodyMatchUtil] CreateSourceBodyProxy: sourceAvatar == null");
|
||||
sourceToProxy = new Dictionary<Transform, Transform>();
|
||||
return (GameObject)null;
|
||||
}
|
||||
GameObject clone = Object.Instantiate<GameObject>(((Component)sourceAvatar).gameObject);
|
||||
((Object)clone).name = ((Object)sourceAvatar).name + "_BodyProxy";
|
||||
HashSet<Transform> remainTransforms = new HashSet<Transform>();
|
||||
remainTransforms.Add(clone.transform);
|
||||
Animator component = clone.GetComponent<Animator>();
|
||||
if (Object.op_Inequality((Object)component, (Object)null))
|
||||
{
|
||||
((Behaviour)component).enabled = false;
|
||||
remainTransforms.Add(((Component)component).transform);
|
||||
}
|
||||
if (Object.op_Inequality((Object)component, (Object)null) && Object.op_Inequality((Object)component.avatar, (Object)null) && component.avatar.isHuman)
|
||||
{
|
||||
for (int index = 0; index < 55; ++index)
|
||||
{
|
||||
HumanBodyBones humanBodyBones = (HumanBodyBones)index;
|
||||
Transform boneTransform = component.GetBoneTransform(humanBodyBones);
|
||||
if (Object.op_Inequality((Object)boneTransform, (Object)null))
|
||||
remainTransforms.Add(boneTransform);
|
||||
}
|
||||
}
|
||||
HashSet<Mesh> meshSet = new HashSet<Mesh>();
|
||||
if (sourceBodyMeshes != null)
|
||||
{
|
||||
foreach (SkinnedMeshRenderer sourceBodyMesh in (IEnumerable<SkinnedMeshRenderer>)sourceBodyMeshes)
|
||||
{
|
||||
if (!Object.op_Equality((Object)sourceBodyMesh, (Object)null) && !Object.op_Equality((Object)sourceBodyMesh.sharedMesh, (Object)null))
|
||||
meshSet.Add(sourceBodyMesh.sharedMesh);
|
||||
}
|
||||
}
|
||||
SkinnedMeshRenderer[] componentsInChildren1 = clone.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
List<SkinnedMeshRenderer> skinnedMeshRendererList = new List<SkinnedMeshRenderer>();
|
||||
foreach (SkinnedMeshRenderer skinnedMeshRenderer in componentsInChildren1)
|
||||
{
|
||||
if (!Object.op_Equality((Object)skinnedMeshRenderer, (Object)null))
|
||||
{
|
||||
Mesh sharedMesh = skinnedMeshRenderer.sharedMesh;
|
||||
if (!Object.op_Equality((Object)sharedMesh, (Object)null) && meshSet.Contains(sharedMesh))
|
||||
skinnedMeshRendererList.Add(skinnedMeshRenderer);
|
||||
}
|
||||
}
|
||||
if (skinnedMeshRendererList.Count == 0)
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] CreateSourceBodyProxy: clone에서 동일 sharedMesh를 가진 BodyMesh를 찾지 못했습니다.");
|
||||
if (skinnedMeshRendererList.Count > 0)
|
||||
{
|
||||
MeshClassifier meshClassifier = new MeshClassifier();
|
||||
foreach (SkinnedMeshRenderer smr in skinnedMeshRendererList)
|
||||
{
|
||||
if (!Object.op_Equality((Object)smr, (Object)null))
|
||||
{
|
||||
remainTransforms.Add(((Component)smr).transform);
|
||||
HashSet<Transform> activeBones = meshClassifier.GetActiveBones(smr);
|
||||
if (activeBones == null)
|
||||
{
|
||||
Debug.LogWarning((object)$"[AvatarBodyMatchUtil] CreateSourceBodyProxy: clone smr '{((Object)smr).name}' has null bones array (mesh='{((Object)smr.sharedMesh)?.name}')");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Transform transform in activeBones)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform, (Object)null))
|
||||
remainTransforms.Add(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Transform t in remainTransforms.ToList<Transform>())
|
||||
AddWithParents(t);
|
||||
Transform[] componentsInChildren2 = clone.GetComponentsInChildren<Transform>(true);
|
||||
for (int index = componentsInChildren2.Length - 1; index >= 0; --index)
|
||||
{
|
||||
Transform transform = componentsInChildren2[index];
|
||||
if (!Object.op_Equality((Object)transform, (Object)null) && !Object.op_Equality((Object)transform, (Object)clone.transform) && !remainTransforms.Contains(transform))
|
||||
Object.DestroyImmediate((Object)((Component)transform).gameObject);
|
||||
}
|
||||
proxyBodyMeshes = skinnedMeshRendererList;
|
||||
new BoneMatchUtil().BuildSourceToProxyBoneMap(sourceAvatar, component, out sourceToProxy);
|
||||
return clone;
|
||||
|
||||
void AddWithParents(Transform t)
|
||||
{
|
||||
for (; Object.op_Inequality((Object)t, (Object)null) && Object.op_Inequality((Object)t, (Object)clone.transform); t = t.parent)
|
||||
remainTransforms.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 GetComprehensiveScale(
|
||||
Transform rootT,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothHumanoidBoneMap,
|
||||
ProfileData profileData)
|
||||
{
|
||||
if (Object.op_Equality((Object)rootT, (Object)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 transform1 = (Transform)null;
|
||||
HashSet<Transform> transformSet;
|
||||
if (clothHumanoidBoneMap.TryGetValue((HumanBodyBones)0, out transformSet) && transformSet != null && transformSet.Count > 0)
|
||||
{
|
||||
foreach (Transform transform2 in transformSet)
|
||||
{
|
||||
if (Object.op_Inequality((Object)transform2, (Object)null))
|
||||
{
|
||||
transform1 = transform2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.op_Equality((Object)transform1, (Object)null))
|
||||
throw new AutoMorpherException("Hip Transform is Missing", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - failed to get [hip] transform from clothHumanoidBoneMap");
|
||||
BoneData boneData = (BoneData)null;
|
||||
for (int index = 0; index < profileData.bones.Count; ++index)
|
||||
{
|
||||
BoneData bone = profileData.bones[index];
|
||||
if (bone != null && bone.hBone == null)
|
||||
{
|
||||
boneData = bone;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Vector3 vector3_1 = boneData != null ? boneData.rootLocalScale : throw new AutoMorpherException("Hip Bone Data is Missing in Profile", "[BodyPoseMatch_CommonUtil] GetComprehensiveScale\n - profileData bones does not contain Hips");
|
||||
Vector3 lossyScale1 = rootT.lossyScale;
|
||||
Vector3 lossyScale2 = transform1.lossyScale;
|
||||
Vector3 vector3_2;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3)ref vector3_2).\u002Ector(lossyScale2.x / lossyScale1.x, lossyScale2.y / lossyScale1.y, lossyScale2.z / lossyScale1.z);
|
||||
return new Vector3(vector3_2.x / vector3_1.x, vector3_2.y / vector3_1.y, vector3_2.z / vector3_1.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: feba191d9b996fb4f92fb50b0bdc9c66
|
||||
107
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs
Normal file
107
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BodyPoseMatchUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BodyPoseMatchUtil
|
||||
{
|
||||
private WorldVertexUtil _worldVertexUtil;
|
||||
private MeshClassifier meshClassifier;
|
||||
private BodyPoseMatch_CommonUtil poseMatchCommonUtil;
|
||||
private bool doDebug;
|
||||
|
||||
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 component1 = sourceAvatar.GetComponent<Animator>();
|
||||
Animator component2 = targetAvatar.GetComponent<Animator>();
|
||||
if (Object.op_Equality((Object)component1, (Object)null) || Object.op_Equality((Object)component2, (Object)null))
|
||||
{
|
||||
Debug.LogError((object)"[AvatarBodyMatchUtil] sourceAvatar 또는 targetAvatar가 null입니다.");
|
||||
sourceToProxy = new Dictionary<Transform, Transform>();
|
||||
return (GameObject)null;
|
||||
}
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanBoneMap = this.meshClassifier.MeshHumanoidBoneMatcher(component1, sourceBodyMeshes);
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary1 = this.meshClassifier.MeshHumanoidBoneMatcher(component2, targetBodyMeshes);
|
||||
BodyPoseMatchSetupUtil poseMatchSetupUtil = new BodyPoseMatchSetupUtil();
|
||||
poseMatchSetupUtil.AdjustAvatarScaleByNeck(sourceAvatar.transform, humanBoneMap, neckTargetHeight);
|
||||
poseMatchSetupUtil.AdjustAvatarScaleByNeck(targetAvatar.transform, dictionary1, neckTargetHeight);
|
||||
List<SkinnedMeshRenderer> proxyBodyMeshes;
|
||||
GameObject bodyProxy = poseMatchSetupUtil.CreateBodyProxy(component1, sourceBodyMeshes, out proxyBodyMeshes, out sourceToProxy);
|
||||
Animator component3 = bodyProxy.GetComponent<Animator>();
|
||||
if (onlyScaling)
|
||||
{
|
||||
bodyProxy.transform.SetParent(targetAvatar.transform);
|
||||
bodyProxy.transform.localPosition = Vector3.zero;
|
||||
return bodyProxy;
|
||||
}
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary2 = this.meshClassifier.MeshHumanoidBoneMatcher(component3, (IReadOnlyList<SkinnedMeshRenderer>)proxyBodyMeshes);
|
||||
if (dictionary2 == null || dictionary2.Count == 0)
|
||||
throw new AutoMorpherException("Proxy Bone Map is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - proxyBoneMap is null");
|
||||
bodyProxy.transform.SetParent(targetAvatar.transform);
|
||||
bodyProxy.transform.localPosition = Vector3.zero;
|
||||
List<BakedBodyMesh> bakedBodyMeshList1 = new List<BakedBodyMesh>();
|
||||
foreach (SkinnedMeshRenderer _smr in proxyBodyMeshes)
|
||||
bakedBodyMeshList1.Add(new BakedBodyMesh(_smr));
|
||||
List<BakedBodyMesh> bakedBodyMeshList2 = new List<BakedBodyMesh>();
|
||||
foreach (SkinnedMeshRenderer targetBodyMesh in (IEnumerable<SkinnedMeshRenderer>)targetBodyMeshes)
|
||||
bakedBodyMeshList2.Add(new BakedBodyMesh(targetBodyMesh));
|
||||
BodyPoseMatch_Torso bodyPoseMatchTorso = new BodyPoseMatch_Torso();
|
||||
bodyPoseMatchTorso.AlignTorsoByNeck(bodyProxy, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList1, dictionary2, targetAvatar, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList2, dictionary1);
|
||||
if (this.doDebug)
|
||||
{
|
||||
bodyPoseMatchTorso.DrawTorsoPcaDebug(bodyProxy, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList1, dictionary2, Color.yellow, Color.cyan, duration: 20f);
|
||||
bodyPoseMatchTorso.DrawTorsoPcaDebug(targetAvatar, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList2, dictionary1, Color.red, Color.green, duration: 20f);
|
||||
}
|
||||
foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1)
|
||||
bakedBodyMesh.ReBakeMesh();
|
||||
BodyPoseMatch_Arm bodyPoseMatchArm = new BodyPoseMatch_Arm();
|
||||
bodyPoseMatchArm.AlignUpperArmByArmPcaCenters((IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList1, dictionary2, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList2, dictionary1);
|
||||
if (this.doDebug)
|
||||
{
|
||||
bodyPoseMatchArm.DrawArmPcaDebug(bodyProxy, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList1, dictionary2, true, Color.yellow, Color.cyan, duration: 20f);
|
||||
bodyPoseMatchArm.DrawArmPcaDebug(targetAvatar, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList2, dictionary1, true, Color.red, Color.green, duration: 20f);
|
||||
}
|
||||
foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1)
|
||||
bakedBodyMesh.ReBakeMesh();
|
||||
bodyPoseMatchArm.ScalingBothArmsLength((IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList1, dictionary2, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList2, dictionary1);
|
||||
foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1)
|
||||
bakedBodyMesh.ReBakeMesh();
|
||||
BodyPoseMatch_Leg bodyPoseMatchLeg = new BodyPoseMatch_Leg();
|
||||
bodyPoseMatchLeg.AlignBothUpperLegs(bodyProxy, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList1, dictionary2, targetAvatar, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList2, dictionary1);
|
||||
foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1)
|
||||
bakedBodyMesh.ReBakeMesh();
|
||||
bodyPoseMatchLeg.ScalingBothLegsAndFoots(bodyProxy, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList1, dictionary2, targetAvatar, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList2, dictionary1);
|
||||
if (this.doDebug)
|
||||
{
|
||||
foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1)
|
||||
bakedBodyMesh.ReBakeMesh();
|
||||
bodyPoseMatchLeg.DrawLegPcaDebug(bodyProxy, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList1, dictionary2, true, Color.yellow, Color.cyan, duration: 5f);
|
||||
bodyPoseMatchLeg.DrawLegPcaDebug(bodyProxy, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList1, dictionary2, false, Color.yellow, Color.cyan, duration: 5f);
|
||||
bodyPoseMatchLeg.DrawLegPcaDebug(targetAvatar, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList2, dictionary1, true, Color.magenta, Color.green, duration: 5f);
|
||||
bodyPoseMatchLeg.DrawLegPcaDebug(targetAvatar, (IReadOnlyList<BakedBodyMesh>)bakedBodyMeshList2, dictionary1, false, Color.magenta, Color.green, duration: 5f);
|
||||
bodyPoseMatchArm.DrawForearmExtremeDebugPair(bodyProxy.gameObject, (IReadOnlyList<SkinnedMeshRenderer>)proxyBodyMeshes, targetAvatar, targetBodyMeshes, true, 1f, 5f);
|
||||
}
|
||||
return bodyProxy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a85962b0b9eb9ec4094079c0f62db81d
|
||||
557
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs
Normal file
557
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs
Normal file
@@ -0,0 +1,557 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BodyPoseMatch_Arm
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BodyPoseMatch_Arm
|
||||
{
|
||||
private readonly BodyPoseMatch_CommonUtil poseMatchCommonUtil;
|
||||
|
||||
public BodyPoseMatch_Arm() => this.poseMatchCommonUtil = new BodyPoseMatch_CommonUtil();
|
||||
|
||||
public void AlignUpperArmByArmCenters(
|
||||
IReadOnlyCollection<Transform> sourceLeftUpperArmSet,
|
||||
IReadOnlyCollection<Transform> sourceRightUpperArmSet,
|
||||
Vector3 sourceShoulderCenterWorld,
|
||||
Vector3 targetShoulderCenterWorld,
|
||||
Transform axisReferenceTransform,
|
||||
bool lockRightAxis = true)
|
||||
{
|
||||
if (sourceLeftUpperArmSet == null || sourceLeftUpperArmSet.Count == 0)
|
||||
throw new AutoMorpherException("Source Left UpperArm Set is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmCenters\n - sourceLeftUpperArmSet is null or empty");
|
||||
if (sourceRightUpperArmSet == null || sourceRightUpperArmSet.Count == 0)
|
||||
throw new AutoMorpherException("Source Right UpperArm Set is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmCenters\n - sourceRightUpperArmSet is null or empty");
|
||||
if (Object.op_Equality((Object)axisReferenceTransform, (Object)null))
|
||||
throw new AutoMorpherException("Axis Reference Transform is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmCenters\n - axisReferenceTransform is null");
|
||||
Vector3 vector3 = Vector3.op_Subtraction(targetShoulderCenterWorld, sourceShoulderCenterWorld);
|
||||
if (lockRightAxis)
|
||||
{
|
||||
Vector3 right = axisReferenceTransform.right;
|
||||
float num = Vector3.Dot(vector3, right);
|
||||
vector3 = Vector3.op_Subtraction(vector3, Vector3.op_Multiply(right, num));
|
||||
}
|
||||
foreach (Transform sourceLeftUpperArm in (IEnumerable<Transform>)sourceLeftUpperArmSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)sourceLeftUpperArm, (Object)null))
|
||||
{
|
||||
Transform transform = sourceLeftUpperArm;
|
||||
transform.position = Vector3.op_Addition(transform.position, vector3);
|
||||
}
|
||||
}
|
||||
foreach (Transform sourceRightUpperArm in (IEnumerable<Transform>)sourceRightUpperArmSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)sourceRightUpperArm, (Object)null))
|
||||
{
|
||||
Transform transform = sourceRightUpperArm;
|
||||
transform.position = Vector3.op_Addition(transform.position, vector3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AlignUpperArmByArmPcaCenters(
|
||||
IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap)
|
||||
{
|
||||
Transform axisReferenceTransform = proxyBoneMap != null ? this.poseMatchCommonUtil.GetBoneFromBoneMap(proxyBoneMap, (HumanBodyBones)0) : throw new AutoMorpherException("Proxy Bone Map is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - proxyBoneMap is null");
|
||||
if (Object.op_Equality((Object)axisReferenceTransform, (Object)null))
|
||||
throw new AutoMorpherException("Proxy Hips is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - proxy hips transform is null");
|
||||
RegionStats armRegionStats1 = this.ComputeArmRegionStats(proxyBakedBodyMeshes, proxyBoneMap, true);
|
||||
RegionStats armRegionStats2 = this.ComputeArmRegionStats(proxyBakedBodyMeshes, proxyBoneMap, false);
|
||||
bool leftValid1 = (double)armRegionStats1.length > 9.9999997473787516E-05;
|
||||
bool rightValid1 = (double)armRegionStats2.length > 9.9999997473787516E-05;
|
||||
if (!leftValid1 && !rightValid1)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters: proxy arm PCA failed. Skip.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 shoulderCenter1 = this.CalculateShoulderCenter(leftValid1, rightValid1, armRegionStats1.center, armRegionStats2.center);
|
||||
RegionStats armRegionStats3 = this.ComputeArmRegionStats(targetBakedBodyMeshes, targetBoneMap, true);
|
||||
RegionStats armRegionStats4 = this.ComputeArmRegionStats(targetBakedBodyMeshes, targetBoneMap, false);
|
||||
bool leftValid2 = (double)armRegionStats3.length > 9.9999997473787516E-05;
|
||||
bool rightValid2 = (double)armRegionStats4.length > 9.9999997473787516E-05;
|
||||
if (!leftValid2 && !rightValid2)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters: target arm PCA failed. Skip.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 shoulderCenter2 = this.CalculateShoulderCenter(leftValid2, rightValid2, armRegionStats3.center, armRegionStats4.center);
|
||||
HashSet<Transform> sourceLeftUpperArmSet;
|
||||
if (!proxyBoneMap.TryGetValue((HumanBodyBones)13, out sourceLeftUpperArmSet) || sourceLeftUpperArmSet == null || sourceLeftUpperArmSet.Count == 0)
|
||||
throw new AutoMorpherException("Proxy Left UpperArm Set is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - proxyBoneMap has no LeftUpperArm set");
|
||||
HashSet<Transform> sourceRightUpperArmSet;
|
||||
if (!proxyBoneMap.TryGetValue((HumanBodyBones)14, out sourceRightUpperArmSet) || sourceRightUpperArmSet == null || sourceRightUpperArmSet.Count == 0)
|
||||
throw new AutoMorpherException("Proxy Right UpperArm Set is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - proxyBoneMap has no RightUpperArm set");
|
||||
this.AlignUpperArmByArmCenters((IReadOnlyCollection<Transform>)sourceLeftUpperArmSet, (IReadOnlyCollection<Transform>)sourceRightUpperArmSet, shoulderCenter1, shoulderCenter2, axisReferenceTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AlignUpperArmByArmPcaCenters(
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
Transform clothesTransform,
|
||||
ProfileData profileData,
|
||||
Vector3 comprehensiveScale)
|
||||
{
|
||||
if (clothBoneMap == null)
|
||||
throw new AutoMorpherException("Cloth Bone Map is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - clothBoneMap is null");
|
||||
if (profileData == null)
|
||||
throw new AutoMorpherException("Profile Data is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - profileData is null");
|
||||
Transform boneFromBoneMap = this.poseMatchCommonUtil.GetBoneFromBoneMap(clothBoneMap, (HumanBodyBones)0);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap, (Object)null))
|
||||
throw new AutoMorpherException("Cloth Hips is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - cloth hips transform is null");
|
||||
bool leftValid1 = profileData.LeftUpperArmSpatialData != null && profileData.LeftUpperArmSpatialData.pcaData != null && (double)profileData.LeftUpperArmSpatialData.pcaData.pcaLength > 9.9999997473787516E-05;
|
||||
bool rightValid1 = profileData.RightUpperArmSpatialData != null && profileData.RightUpperArmSpatialData.pcaData != null && (double)profileData.RightUpperArmSpatialData.pcaData.pcaLength > 9.9999997473787516E-05;
|
||||
if (!leftValid1 && !rightValid1)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters: profile arm data invalid. Skip.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 leftCenter = Vector3.zero;
|
||||
if (leftValid1)
|
||||
leftCenter = this.poseMatchCommonUtil.GetProfilePcaCenterWorld(clothBoneMap, profileData.LeftUpperArmSpatialData, comprehensiveScale);
|
||||
Vector3 rightCenter = Vector3.zero;
|
||||
if (rightValid1)
|
||||
rightCenter = this.poseMatchCommonUtil.GetProfilePcaCenterWorld(clothBoneMap, profileData.RightUpperArmSpatialData, comprehensiveScale);
|
||||
Vector3 shoulderCenter1 = this.CalculateShoulderCenter(leftValid1, rightValid1, leftCenter, rightCenter);
|
||||
RegionStats armRegionStats1 = this.ComputeArmRegionStats(targetBakedBodyMeshes, targetBoneMap, true);
|
||||
RegionStats armRegionStats2 = this.ComputeArmRegionStats(targetBakedBodyMeshes, targetBoneMap, false);
|
||||
bool leftValid2 = (double)armRegionStats1.length > 9.9999997473787516E-05;
|
||||
bool rightValid2 = (double)armRegionStats2.length > 9.9999997473787516E-05;
|
||||
if (!leftValid2 && !rightValid2)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters: target arm PCA failed. Skip.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 shoulderCenter2 = this.CalculateShoulderCenter(leftValid2, rightValid2, armRegionStats1.center, armRegionStats2.center);
|
||||
HashSet<Transform> sourceLeftUpperArmSet;
|
||||
if (!clothBoneMap.TryGetValue((HumanBodyBones)13, out sourceLeftUpperArmSet) || sourceLeftUpperArmSet == null || sourceLeftUpperArmSet.Count == 0)
|
||||
throw new AutoMorpherException("Cloth Left UpperArm Set is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - clothBoneMap has no LeftUpperArm set");
|
||||
HashSet<Transform> sourceRightUpperArmSet;
|
||||
if (!clothBoneMap.TryGetValue((HumanBodyBones)14, out sourceRightUpperArmSet) || sourceRightUpperArmSet == null || sourceRightUpperArmSet.Count == 0)
|
||||
throw new AutoMorpherException("Cloth Right UpperArm Set is Missing", "[BodyPoseMatch_Arm] AlignUpperArmByArmPcaCenters\n - clothBoneMap has no RightUpperArm set");
|
||||
this.AlignUpperArmByArmCenters((IReadOnlyCollection<Transform>)sourceLeftUpperArmSet, (IReadOnlyCollection<Transform>)sourceRightUpperArmSet, shoulderCenter1, shoulderCenter2, boneFromBoneMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 CalculateShoulderCenter(
|
||||
bool leftValid,
|
||||
bool rightValid,
|
||||
Vector3 leftCenter,
|
||||
Vector3 rightCenter)
|
||||
{
|
||||
if (leftValid & rightValid)
|
||||
return Vector3.op_Multiply(0.5f, Vector3.op_Addition(leftCenter, rightCenter));
|
||||
return leftValid ? leftCenter : rightCenter;
|
||||
}
|
||||
|
||||
public RegionStats ComputeArmRegionStats(
|
||||
IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap,
|
||||
bool isLeft)
|
||||
{
|
||||
// ISSUE: unable to decompile the method.
|
||||
}
|
||||
|
||||
private void ScalingUpperArmLength(
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> sourceBoneMap,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
bool isLeft,
|
||||
bool autoDetectAxis,
|
||||
int forceAxisIndex)
|
||||
{
|
||||
HumanBodyBones humanBodyBones = isLeft ? (HumanBodyBones)13 : (HumanBodyBones)14;
|
||||
HumanBodyBones bone1 = isLeft ? (HumanBodyBones)15 : (HumanBodyBones)16 /*0x10*/;
|
||||
HumanBodyBones bone2 = isLeft ? (HumanBodyBones)17 : (HumanBodyBones)18;
|
||||
Transform boneFromBoneMap1 = this.poseMatchCommonUtil.GetBoneFromBoneMap(sourceBoneMap, humanBodyBones);
|
||||
Transform boneFromBoneMap2 = this.poseMatchCommonUtil.GetBoneFromBoneMap(sourceBoneMap, bone1);
|
||||
Transform boneFromBoneMap3 = this.poseMatchCommonUtil.GetBoneFromBoneMap(sourceBoneMap, bone2);
|
||||
Transform boneFromBoneMap4 = this.poseMatchCommonUtil.GetBoneFromBoneMap(targetBoneMap, humanBodyBones);
|
||||
Transform boneFromBoneMap5 = this.poseMatchCommonUtil.GetBoneFromBoneMap(targetBoneMap, bone1);
|
||||
Transform boneFromBoneMap6 = this.poseMatchCommonUtil.GetBoneFromBoneMap(targetBoneMap, bone2);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap1, (Object)null) || Object.op_Equality((Object)boneFromBoneMap2, (Object)null) || Object.op_Equality((Object)boneFromBoneMap3, (Object)null) || Object.op_Equality((Object)boneFromBoneMap4, (Object)null) || Object.op_Equality((Object)boneFromBoneMap5, (Object)null) || Object.op_Equality((Object)boneFromBoneMap6, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] ScalingSingArmLenght: some arm bones are null. Skip.");
|
||||
}
|
||||
else
|
||||
{
|
||||
HashSet<Transform> proxyParentSet;
|
||||
if (sourceBoneMap == null || !sourceBoneMap.TryGetValue(humanBodyBones, out proxyParentSet) || proxyParentSet == null || proxyParentSet.Count == 0)
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] ScalingSingArmLenght: sourceUpperSet missing. Skip.");
|
||||
else
|
||||
this.poseMatchCommonUtil.BoneLengthAdjust(boneFromBoneMap1, boneFromBoneMap2, boneFromBoneMap4, boneFromBoneMap5, proxyParentSet, autoDetectAxis, forceAxisIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void ScalingLowerArmLength(
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> sourceBoneMap,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
bool isLeft,
|
||||
bool autoDetectAxis,
|
||||
int forceAxisIndex,
|
||||
float sourceLowerarmExtremeX,
|
||||
float targetLowerarmExtremeX)
|
||||
{
|
||||
HumanBodyBones humanBodyBones = isLeft ? (HumanBodyBones)15 : (HumanBodyBones)16 /*0x10*/;
|
||||
HumanBodyBones bone = isLeft ? (HumanBodyBones)17 : (HumanBodyBones)18;
|
||||
Transform boneFromBoneMap1 = this.poseMatchCommonUtil.GetBoneFromBoneMap(sourceBoneMap, humanBodyBones);
|
||||
Transform boneFromBoneMap2 = this.poseMatchCommonUtil.GetBoneFromBoneMap(sourceBoneMap, bone);
|
||||
Transform boneFromBoneMap3 = this.poseMatchCommonUtil.GetBoneFromBoneMap(targetBoneMap, humanBodyBones);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap1, (Object)null) || Object.op_Equality((Object)boneFromBoneMap2, (Object)null) || Object.op_Equality((Object)boneFromBoneMap3, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] ScalingSingArmLenght: some arm bones are null. Skip.");
|
||||
}
|
||||
else
|
||||
{
|
||||
float x1 = boneFromBoneMap1.position.x;
|
||||
float x2 = boneFromBoneMap3.position.x;
|
||||
float num1 = Mathf.Abs(sourceLowerarmExtremeX - x1);
|
||||
float num2 = Mathf.Abs(targetLowerarmExtremeX - x2);
|
||||
if ((double)num1 < 9.9999997473787516E-05 || (double)num2 < 9.9999997473787516E-05)
|
||||
{
|
||||
Debug.LogWarning((object)$"[BodyPoseMatch_Arm] ScalingSingArmLenght: span too small. source={num1}, target={num2}");
|
||||
}
|
||||
else
|
||||
{
|
||||
float num3 = num2 / num1;
|
||||
int num4 = this.ResolveArmLengthAxisIndex(boneFromBoneMap1, boneFromBoneMap2, autoDetectAxis, forceAxisIndex);
|
||||
Vector3 localScale = boneFromBoneMap1.localScale;
|
||||
switch (num4)
|
||||
{
|
||||
case 0:
|
||||
localScale.x *= num3;
|
||||
break;
|
||||
case 1:
|
||||
localScale.y *= num3;
|
||||
break;
|
||||
case 2:
|
||||
localScale.z *= num3;
|
||||
break;
|
||||
}
|
||||
foreach (Transform transform in sourceBoneMap[humanBodyBones])
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform, (Object)null))
|
||||
transform.localScale = localScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ScalingBothArmsLength(
|
||||
IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
bool autoDetectAxis = true,
|
||||
int forceAxisIndex = 1)
|
||||
{
|
||||
if (proxyBoneMap == null || targetBoneMap == null)
|
||||
throw new AutoMorpherException("Cloth Bone Map is Missing", "[BodyPoseMatch_Arm] ScalingSingArmLenght\n - BoneMap is null");
|
||||
this.ScalingUpperArmLength(proxyBoneMap, targetBoneMap, true, autoDetectAxis, forceAxisIndex);
|
||||
this.ScalingUpperArmLength(proxyBoneMap, targetBoneMap, false, autoDetectAxis, forceAxisIndex);
|
||||
if (proxyBakedBodyMeshes != null)
|
||||
{
|
||||
foreach (BakedBodyMesh proxyBakedBodyMesh in (IEnumerable<BakedBodyMesh>)proxyBakedBodyMeshes)
|
||||
proxyBakedBodyMesh.ReBakeMesh();
|
||||
}
|
||||
this.ScalingLowerArmLength_BodyMatch(proxyBakedBodyMeshes, proxyBoneMap, targetBakedBodyMeshes, targetBoneMap, autoDetectAxis, forceAxisIndex);
|
||||
}
|
||||
|
||||
private void ScalingLowerArmLength_BodyMatch(
|
||||
IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
bool autoDetectAxis,
|
||||
int forceAxisIndex)
|
||||
{
|
||||
float extremeX1;
|
||||
float extremeX2;
|
||||
if (this.TryGetForearmExtremeX(proxyBakedBodyMeshes, proxyBoneMap, (HumanBodyBones)17, true, out extremeX1) && this.TryGetForearmExtremeX(targetBakedBodyMeshes, targetBoneMap, (HumanBodyBones)17, true, out extremeX2))
|
||||
this.ScalingLowerArmLength(proxyBoneMap, targetBoneMap, true, autoDetectAxis, forceAxisIndex, extremeX1, extremeX2);
|
||||
else
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] ScalingLowerArmLength_BodyMatch: left extreme calc failed. Skip left lower.");
|
||||
float extremeX3;
|
||||
float extremeX4;
|
||||
if (this.TryGetForearmExtremeX(proxyBakedBodyMeshes, proxyBoneMap, (HumanBodyBones)18, false, out extremeX3) && this.TryGetForearmExtremeX(targetBakedBodyMeshes, targetBoneMap, (HumanBodyBones)18, false, out extremeX4))
|
||||
this.ScalingLowerArmLength(proxyBoneMap, targetBoneMap, false, autoDetectAxis, forceAxisIndex, extremeX3, extremeX4);
|
||||
else
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] ScalingLowerArmLength_BodyMatch: right extreme calc failed. Skip right lower.");
|
||||
}
|
||||
|
||||
public void ScalingBothArmsLength(
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
ProfileData profileData,
|
||||
Vector3 comprehensiveScale,
|
||||
bool autoDetectAxis = true,
|
||||
int forceAxisIndex = 1)
|
||||
{
|
||||
if (clothBoneMap == null || targetBoneMap == null)
|
||||
throw new AutoMorpherException("Cloth Bone Map is Missing", "[BodyPoseMatch_Arm] ScalingSingArmLenght\n - BoneMap is null");
|
||||
if (profileData == null)
|
||||
throw new AutoMorpherException("Profile Data is Missing", "[BodyPoseMatch_Arm] ScalingSingArmLenght\n - profileData is null");
|
||||
this.ScalingUpperArmLength(clothBoneMap, targetBoneMap, true, autoDetectAxis, forceAxisIndex);
|
||||
this.ScalingUpperArmLength(clothBoneMap, targetBoneMap, false, autoDetectAxis, forceAxisIndex);
|
||||
this.ScalingLowerArmLength_ProfileMatch(targetBakedBodyMeshes, targetBoneMap, clothBoneMap, profileData, comprehensiveScale, autoDetectAxis, forceAxisIndex);
|
||||
}
|
||||
|
||||
private void ScalingLowerArmLength_ProfileMatch(
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
ProfileData profileData,
|
||||
Vector3 comprehensiveScale,
|
||||
bool autoDetectAxis,
|
||||
int forceAxisIndex)
|
||||
{
|
||||
if (profileData.LeftLowerArm_HandSpatialData == null || profileData.LeftLowerArm_HandSpatialData.volumeData == null)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] ScalingLowerArmLength_ProfileMatch: left spatial data missing. Skip left lower.");
|
||||
}
|
||||
else
|
||||
{
|
||||
float extremeX;
|
||||
if (this.TryGetForearmExtremeX(targetBakedBodyMeshes, targetBoneMap, (HumanBodyBones)17, true, out extremeX))
|
||||
{
|
||||
float profileForearmExtremeX = this.GetProfileForearmExtremeX(clothBoneMap, profileData.LeftLowerArm_HandSpatialData, comprehensiveScale, true);
|
||||
this.ScalingLowerArmLength(clothBoneMap, targetBoneMap, true, autoDetectAxis, forceAxisIndex, profileForearmExtremeX, extremeX);
|
||||
}
|
||||
else
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] ScalingLowerArmLength_ProfileMatch: left target extreme calc failed. Skip left lower.");
|
||||
}
|
||||
if (profileData.RightLowerArm_HandSpatialData == null || profileData.RightLowerArm_HandSpatialData.volumeData == null)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] ScalingLowerArmLength_ProfileMatch: right spatial data missing. Skip right lower.");
|
||||
}
|
||||
else
|
||||
{
|
||||
float extremeX;
|
||||
if (this.TryGetForearmExtremeX(targetBakedBodyMeshes, targetBoneMap, (HumanBodyBones)18, false, out extremeX))
|
||||
{
|
||||
float profileForearmExtremeX = this.GetProfileForearmExtremeX(clothBoneMap, profileData.RightLowerArm_HandSpatialData, comprehensiveScale, false);
|
||||
this.ScalingLowerArmLength(clothBoneMap, targetBoneMap, false, autoDetectAxis, forceAxisIndex, profileForearmExtremeX, extremeX);
|
||||
}
|
||||
else
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Arm] ScalingLowerArmLength_ProfileMatch: right target extreme calc failed. Skip right lower.");
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetForearmExtremeX(
|
||||
IReadOnlyList<BakedBodyMesh> bakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> boneMap,
|
||||
HumanBodyBones targetBone,
|
||||
bool isLeft,
|
||||
out float extremeX,
|
||||
float weightThreshold = 0.15f,
|
||||
int sampleStep = 1)
|
||||
{
|
||||
extremeX = isLeft ? float.PositiveInfinity : float.NegativeInfinity;
|
||||
HashSet<Transform> targetBoneSet;
|
||||
if (bakedBodyMeshes == null || boneMap == null || !boneMap.TryGetValue(targetBone, out targetBoneSet) || targetBoneSet == null || targetBoneSet.Count == 0)
|
||||
return false;
|
||||
List<Vector3> vector3List = this.poseMatchCommonUtil.CollectWeightedVerticesWorld(bakedBodyMeshes, targetBoneSet, weightThreshold, sampleStep);
|
||||
if (vector3List == null || vector3List.Count == 0)
|
||||
return false;
|
||||
for (int index = 0; index < vector3List.Count; ++index)
|
||||
{
|
||||
float x = vector3List[index].x;
|
||||
if (isLeft)
|
||||
{
|
||||
if ((double)x < (double)extremeX)
|
||||
extremeX = x;
|
||||
}
|
||||
else if ((double)x > (double)extremeX)
|
||||
extremeX = x;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private float GetProfileForearmExtremeX(
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
BoneSpatialData spatialData,
|
||||
Vector3 comprehensiveScale,
|
||||
bool isLeft)
|
||||
{
|
||||
if (spatialData == null || spatialData.volumeData == null)
|
||||
throw new AutoMorpherException("Profile Volume Data is Missing", "[BodyPoseMatch_Arm] GetProfileForearmExtremeX\n - spatialData or spatialData.volumeData is null");
|
||||
if (Object.op_Equality((Object)this.poseMatchCommonUtil.GetBoneFromBoneMap(clothBoneMap, spatialData.refBone), (Object)null))
|
||||
throw new AutoMorpherException("Profile Ref Bone Transform is Missing", "[BodyPoseMatch_Arm] GetProfileForearmExtremeX\n - refBone transform is null");
|
||||
BodyPoseMatch_CommonUtil poseMatchCommonUtil = new BodyPoseMatch_CommonUtil();
|
||||
float x1 = poseMatchCommonUtil.GetProfileVolumeMinWorld(clothBoneMap, spatialData, 1, comprehensiveScale).x;
|
||||
float x2 = poseMatchCommonUtil.GetProfileVolumeMaxWorld(clothBoneMap, spatialData, 1, comprehensiveScale).x;
|
||||
return !isLeft ? x2 : x1;
|
||||
}
|
||||
|
||||
private int ResolveArmLengthAxisIndex(
|
||||
Transform lowerArm,
|
||||
Transform hand,
|
||||
bool autoDetectAxis,
|
||||
int forceAxisIndex)
|
||||
{
|
||||
if (!autoDetectAxis)
|
||||
return Mathf.Clamp(forceAxisIndex, 0, 2);
|
||||
Vector3 vector3_1 = Vector3.op_Subtraction(hand.position, lowerArm.position);
|
||||
Vector3 vector3_2 = lowerArm.InverseTransformDirection(vector3_1);
|
||||
float num1 = Mathf.Abs(vector3_2.x);
|
||||
float num2 = Mathf.Abs(vector3_2.y);
|
||||
float num3 = Mathf.Abs(vector3_2.z);
|
||||
if ((double)num2 >= (double)num1 && (double)num2 >= (double)num3)
|
||||
return 1;
|
||||
return (double)num1 >= (double)num3 ? 0 : 2;
|
||||
}
|
||||
|
||||
public void DrawArmPcaDebug(
|
||||
GameObject avatarObject,
|
||||
IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap,
|
||||
bool isLeft,
|
||||
Color centerColor,
|
||||
Color axisColor,
|
||||
float axisScale = 1f,
|
||||
float duration = 0.1f)
|
||||
{
|
||||
if (avatarBakedBodyMeshes == null || avatarBoneMap == null)
|
||||
return;
|
||||
RegionStats armRegionStats = this.ComputeArmRegionStats(avatarBakedBodyMeshes, avatarBoneMap, isLeft);
|
||||
if ((double)armRegionStats.length < 9.9999997473787516E-05)
|
||||
return;
|
||||
Vector3 center = armRegionStats.center;
|
||||
Vector3 vector3 = (double)((Vector3)ref armRegionStats.principalAxis).sqrMagnitude > 9.99999993922529E-09 ? ((Vector3)ref armRegionStats.principalAxis).normalized : Vector3.up;
|
||||
float num1 = 0.02f * axisScale;
|
||||
Debug.DrawLine(Vector3.op_Addition(center, Vector3.op_Multiply(Vector3.up, num1)), Vector3.op_Subtraction(center, Vector3.op_Multiply(Vector3.up, num1)), centerColor, duration);
|
||||
Debug.DrawLine(Vector3.op_Addition(center, Vector3.op_Multiply(Vector3.right, num1)), Vector3.op_Subtraction(center, Vector3.op_Multiply(Vector3.right, num1)), centerColor, duration);
|
||||
Debug.DrawLine(Vector3.op_Addition(center, Vector3.op_Multiply(Vector3.forward, num1)), Vector3.op_Subtraction(center, Vector3.op_Multiply(Vector3.forward, num1)), centerColor, duration);
|
||||
float num2 = armRegionStats.length * 0.5f * axisScale;
|
||||
Debug.DrawLine(Vector3.op_Subtraction(center, Vector3.op_Multiply(vector3, num2)), Vector3.op_Addition(center, Vector3.op_Multiply(vector3, num2)), axisColor, duration);
|
||||
}
|
||||
|
||||
public void DrawForearmExtremeDebugPair(
|
||||
GameObject proxyObject,
|
||||
IReadOnlyList<SkinnedMeshRenderer> proxyBodyMeshes,
|
||||
GameObject targetObject,
|
||||
IReadOnlyList<SkinnedMeshRenderer> targetBodyMeshes,
|
||||
bool isLeft,
|
||||
float size = 0.03f,
|
||||
float duration = 3f)
|
||||
{
|
||||
this.DrawForearmExtremeDebugSingle(proxyObject, proxyBodyMeshes, isLeft, Color.blue, Color.cyan, size, duration);
|
||||
this.DrawForearmExtremeDebugSingle(targetObject, targetBodyMeshes, isLeft, Color.red, Color.magenta, size, duration);
|
||||
}
|
||||
|
||||
public void DrawForearmExtremeDebugSingle(
|
||||
GameObject avatarObject,
|
||||
IReadOnlyList<SkinnedMeshRenderer> bodyMeshes,
|
||||
bool isLeft,
|
||||
Color lineColor,
|
||||
Color pointColor,
|
||||
float size = 0.03f,
|
||||
float duration = 3f)
|
||||
{
|
||||
if (Object.op_Equality((Object)avatarObject, (Object)null) || bodyMeshes == null || bodyMeshes.Count == 0)
|
||||
return;
|
||||
Animator component = avatarObject.GetComponent<Animator>();
|
||||
if (Object.op_Equality((Object)component, (Object)null))
|
||||
return;
|
||||
HumanBodyBones humanBodyBones = isLeft ? (HumanBodyBones)15 : (HumanBodyBones)16 /*0x10*/;
|
||||
Transform boneTransform = component.GetBoneTransform(humanBodyBones);
|
||||
if (Object.op_Equality((Object)boneTransform, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)$"[BodyPoseMatch_Arm] DrawForearmExtremeDebugSingle: elbow bone missing. isLeft={isLeft}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 extremePos;
|
||||
if (!this.TryGetForearmExtremePoint(component, bodyMeshes, isLeft, out extremePos))
|
||||
{
|
||||
Debug.LogWarning((object)$"[BodyPoseMatch_Arm] DrawForearmExtremeDebugSingle: extreme vertex not found. isLeft={isLeft}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.DrawLine(boneTransform.position, extremePos, lineColor, duration);
|
||||
float num = size;
|
||||
Debug.DrawLine(Vector3.op_Addition(extremePos, Vector3.op_Multiply(Vector3.up, num)), Vector3.op_Subtraction(extremePos, Vector3.op_Multiply(Vector3.up, num)), pointColor, duration);
|
||||
Debug.DrawLine(Vector3.op_Addition(extremePos, Vector3.op_Multiply(Vector3.right, num)), Vector3.op_Subtraction(extremePos, Vector3.op_Multiply(Vector3.right, num)), pointColor, duration);
|
||||
Debug.DrawLine(Vector3.op_Addition(extremePos, Vector3.op_Multiply(Vector3.forward, num)), Vector3.op_Subtraction(extremePos, Vector3.op_Multiply(Vector3.forward, num)), pointColor, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetForearmExtremePoint(
|
||||
Animator avatar,
|
||||
IReadOnlyList<SkinnedMeshRenderer> bodyMeshes,
|
||||
bool isLeft,
|
||||
out Vector3 extremePos)
|
||||
{
|
||||
extremePos = new Vector3();
|
||||
if (Object.op_Equality((Object)avatar, (Object)null) || bodyMeshes == null || bodyMeshes.Count == 0)
|
||||
return false;
|
||||
HumanBodyBones humanBodyBones = isLeft ? (HumanBodyBones)17 : (HumanBodyBones)18;
|
||||
Transform boneTransform = avatar.GetBoneTransform(humanBodyBones);
|
||||
if (Object.op_Equality((Object)boneTransform, (Object)null))
|
||||
return false;
|
||||
HashSet<Transform> targetBoneSet = new HashSet<Transform>()
|
||||
{
|
||||
boneTransform
|
||||
};
|
||||
List<BakedBodyMesh> bakedBodyMeshes = new List<BakedBodyMesh>(bodyMeshes.Count);
|
||||
for (int index = 0; index < bodyMeshes.Count; ++index)
|
||||
{
|
||||
SkinnedMeshRenderer bodyMesh = bodyMeshes[index];
|
||||
if (!Object.op_Equality((Object)bodyMesh, (Object)null))
|
||||
{
|
||||
BakedBodyMesh bakedBodyMesh = new BakedBodyMesh(bodyMesh);
|
||||
bakedBodyMesh.ReBakeMesh();
|
||||
bakedBodyMeshes.Add(bakedBodyMesh);
|
||||
}
|
||||
}
|
||||
if (bakedBodyMeshes.Count == 0)
|
||||
return false;
|
||||
List<Vector3> vector3List = this.poseMatchCommonUtil.CollectWeightedVerticesWorld((IReadOnlyList<BakedBodyMesh>)bakedBodyMeshes, targetBoneSet, 0.1f);
|
||||
if (vector3List == null || vector3List.Count == 0)
|
||||
return false;
|
||||
bool forearmExtremePoint = false;
|
||||
float num = isLeft ? float.PositiveInfinity : float.NegativeInfinity;
|
||||
for (int index = 0; index < vector3List.Count; ++index)
|
||||
{
|
||||
Vector3 vector3 = vector3List[index];
|
||||
float x = vector3.x;
|
||||
if (!forearmExtremePoint)
|
||||
{
|
||||
forearmExtremePoint = true;
|
||||
num = x;
|
||||
extremePos = vector3;
|
||||
}
|
||||
else if (isLeft)
|
||||
{
|
||||
if ((double)x < (double)num)
|
||||
{
|
||||
num = x;
|
||||
extremePos = vector3;
|
||||
}
|
||||
}
|
||||
else if ((double)x > (double)num)
|
||||
{
|
||||
num = x;
|
||||
extremePos = vector3;
|
||||
}
|
||||
}
|
||||
return forearmExtremePoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e4304e521b929546b171b5c3eedf84b
|
||||
@@ -0,0 +1,269 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BodyPoseMatch_CommonUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BodyPoseMatch_CommonUtil
|
||||
{
|
||||
public Transform GetBoneFromBoneMap(
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> boneMap,
|
||||
HumanBodyBones bone)
|
||||
{
|
||||
HashSet<Transform> source;
|
||||
return boneMap == null || !boneMap.TryGetValue(bone, out source) || source == null ? (Transform)null : source.FirstOrDefault<Transform>();
|
||||
}
|
||||
|
||||
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 (Object.op_Equality((Object)boneFromBoneMap, (Object)null))
|
||||
throw new AutoMorpherException("Profile Ref Bone Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld" + $"\n - refBone transform is null (refBone={boneSpatialData.refBone}, context={errorContext})");
|
||||
if (Object.op_Equality((Object)this.GetBoneFromBoneMap(clothBoneMap, (HumanBodyBones)0), (Object)null))
|
||||
throw new AutoMorpherException("Hip Transform is Missing", $"[BodyPoseMatch_CommonUtil] GetProfilePcaCenterWorld\n - hip transform is null (context={errorContext})");
|
||||
Vector3 pcaCenter = boneSpatialData.pcaData.pcaCenter;
|
||||
Vector3 vector3;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3)ref vector3).\u002Ector(pcaCenter.x / comprehensiveScale.x, pcaCenter.y / comprehensiveScale.y, pcaCenter.z / comprehensiveScale.z);
|
||||
return boneFromBoneMap.TransformPoint(vector3);
|
||||
}
|
||||
|
||||
public Vector3 GetProfileVolumeMinWorld(
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
BoneSpatialData spatialData,
|
||||
int axis,
|
||||
Vector3 comprehensiveScale)
|
||||
{
|
||||
return this.GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, true);
|
||||
}
|
||||
|
||||
public Vector3 GetProfileVolumeMaxWorld(
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
BoneSpatialData spatialData,
|
||||
int axis,
|
||||
Vector3 comprehensiveScale)
|
||||
{
|
||||
return this.GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, 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 = this.GetBoneFromBoneMap(clothBoneMap, spatialData.refBone);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap, (Object)null))
|
||||
throw new AutoMorpherException("Profile Ref Bone Transform is Missing", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld" + $"\n - refBone transform is null (refBone={spatialData.refBone})");
|
||||
Vector3 vector3_1;
|
||||
switch (axisIndex)
|
||||
{
|
||||
case 0:
|
||||
vector3_1 = isMin ? spatialData.volumeData.fMinLocalPos : spatialData.volumeData.fMaxLocalPos;
|
||||
break;
|
||||
case 1:
|
||||
vector3_1 = isMin ? spatialData.volumeData.rMinLocalPos : spatialData.volumeData.rMaxLocalPos;
|
||||
break;
|
||||
case 2:
|
||||
vector3_1 = isMin ? spatialData.volumeData.uMinLocalPos : spatialData.volumeData.uMaxLocalPos;
|
||||
break;
|
||||
default:
|
||||
throw new AutoMorpherException("Unsupported Volume Axis Index", "[BodyPoseMatch_CommonUtil] GetProfileVolumeWorld" + $"\n - axisIndex must be 0(Forward), 1(Right), 2(Up) (axisIndex={axisIndex})");
|
||||
}
|
||||
Vector3 vector3_2;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3)ref vector3_2).\u002Ector(vector3_1.x / comprehensiveScale.x, vector3_1.y / comprehensiveScale.y, vector3_1.z / comprehensiveScale.z);
|
||||
return boneFromBoneMap.TransformPoint(vector3_2);
|
||||
}
|
||||
|
||||
public List<Vector3> CollectWeightedVerticesWorld(
|
||||
IReadOnlyList<BakedBodyMesh> bakedBodyMeshes,
|
||||
HashSet<Transform> targetBoneSet,
|
||||
float weightThreshold = 0.15f,
|
||||
int sampleStep = 1)
|
||||
{
|
||||
List<Vector3> vector3List = new List<Vector3>();
|
||||
if (bakedBodyMeshes == null || targetBoneSet == null || targetBoneSet.Count == 0)
|
||||
return vector3List;
|
||||
foreach (BakedBodyMesh bakedBodyMesh in (IEnumerable<BakedBodyMesh>)bakedBodyMeshes)
|
||||
{
|
||||
if (bakedBodyMesh != null && !Object.op_Equality((Object)bakedBodyMesh.smr, (Object)null))
|
||||
{
|
||||
Mesh sharedMesh = bakedBodyMesh.smr.sharedMesh;
|
||||
if (!Object.op_Equality((Object)sharedMesh, (Object)null))
|
||||
{
|
||||
BoneWeight[] boneWeights = sharedMesh.boneWeights;
|
||||
Transform[] bones = bakedBodyMesh.smr.bones;
|
||||
if (boneWeights != null && boneWeights.Length != 0 && bones != null && bones.Length != 0)
|
||||
{
|
||||
Vector3[] verticesWithBakedMesh = new WorldVertexUtil().GetWorldVerticesWithBakedMesh(bakedBodyMesh.smr, bakedBodyMesh.bakedMesh);
|
||||
if (verticesWithBakedMesh != null)
|
||||
{
|
||||
int num = Mathf.Min(verticesWithBakedMesh.Length, boneWeights.Length);
|
||||
for (int index = 0; index < num; index += sampleStep)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[index];
|
||||
float wSum = 0.0f;
|
||||
Acc(((BoneWeight)ref boneWeight).boneIndex0, ((BoneWeight)ref boneWeight).weight0);
|
||||
Acc(((BoneWeight)ref boneWeight).boneIndex1, ((BoneWeight)ref boneWeight).weight1);
|
||||
Acc(((BoneWeight)ref boneWeight).boneIndex2, ((BoneWeight)ref boneWeight).weight2);
|
||||
Acc(((BoneWeight)ref boneWeight).boneIndex3, ((BoneWeight)ref boneWeight).weight3);
|
||||
if ((double)wSum >= (double)weightThreshold)
|
||||
vector3List.Add(verticesWithBakedMesh[index]);
|
||||
|
||||
void Acc(int index, float w)
|
||||
{
|
||||
if (index < 0 || index >= bones.Length || (double)w <= 0.0)
|
||||
return;
|
||||
Transform bone = bones[index];
|
||||
if (!Object.op_Inequality((Object)bone, (Object)null) || !targetBoneSet.Contains(bone))
|
||||
return;
|
||||
wSum += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return vector3List;
|
||||
}
|
||||
|
||||
public List<Vector3> CollectHumanoidVerticesWorld(
|
||||
IReadOnlyList<HumanBodyBones> targetHumanBones,
|
||||
IReadOnlyList<BakedBodyMesh> bakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> boneMap,
|
||||
float weightThreshold = 0.15f,
|
||||
int sampleStep = 1)
|
||||
{
|
||||
List<Vector3> vector3List = 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> targetBoneSet = new HashSet<Transform>();
|
||||
foreach (HumanBodyBones targetHumanBone in (IEnumerable<HumanBodyBones>)targetHumanBones)
|
||||
{
|
||||
HashSet<Transform> transformSet;
|
||||
if (boneMap.TryGetValue(targetHumanBone, out transformSet) && transformSet != null)
|
||||
{
|
||||
foreach (Transform transform in transformSet)
|
||||
{
|
||||
if (Object.op_Inequality((Object)transform, (Object)null))
|
||||
targetBoneSet.Add(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targetBoneSet.Count != 0)
|
||||
return this.CollectWeightedVerticesWorld(bakedBodyMeshes, targetBoneSet, weightThreshold, sampleStep);
|
||||
Debug.Log((object)"[AvatarBodyMatchUtil] CollectBodyPartVerticesWorld: targetBoneSet is empty.");
|
||||
return vector3List;
|
||||
}
|
||||
|
||||
public void BoneLengthAdjust(
|
||||
Transform proxyParent,
|
||||
Transform proxyChild,
|
||||
Transform targetParent,
|
||||
Transform targetChild,
|
||||
HashSet<Transform> proxyParentSet,
|
||||
bool autoDetectAxis = true,
|
||||
int forceAxisIndex = 1)
|
||||
{
|
||||
if (Object.op_Equality((Object)proxyParent, (Object)null) || Object.op_Equality((Object)proxyChild, (Object)null) || Object.op_Equality((Object)targetParent, (Object)null) || Object.op_Equality((Object)targetChild, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] MatchBoneSegmentLength: bone null");
|
||||
}
|
||||
else
|
||||
{
|
||||
float num1 = Vector3.Distance(proxyParent.position, proxyChild.position);
|
||||
float num2 = Vector3.Distance(targetParent.position, targetChild.position);
|
||||
if ((double)num1 < 9.9999999747524271E-07 || (double)num2 < 9.9999999747524271E-07)
|
||||
{
|
||||
Debug.LogWarning((object)$"[AvatarBodyMatchUtil] MatchBoneSegmentLength: too small length. proxy={num1}, target={num2}");
|
||||
}
|
||||
else
|
||||
{
|
||||
float num3 = num2 / num1;
|
||||
int num4;
|
||||
if (autoDetectAxis)
|
||||
{
|
||||
Vector3 vector3_1 = Vector3.op_Subtraction(proxyChild.position, proxyParent.position);
|
||||
Vector3 vector3_2 = proxyParent.InverseTransformDirection(vector3_1);
|
||||
float num5 = Mathf.Abs(vector3_2.x);
|
||||
float num6 = Mathf.Abs(vector3_2.y);
|
||||
float num7 = Mathf.Abs(vector3_2.z);
|
||||
num4 = (double)num6 < (double)num5 || (double)num6 < (double)num7 ? ((double)num5 < (double)num7 ? 2 : 0) : 1;
|
||||
}
|
||||
else
|
||||
num4 = Mathf.Clamp(forceAxisIndex, 0, 2);
|
||||
Vector3 localScale = proxyParent.localScale;
|
||||
switch (num4)
|
||||
{
|
||||
case 0:
|
||||
localScale.x *= num3;
|
||||
break;
|
||||
case 1:
|
||||
localScale.y *= num3;
|
||||
break;
|
||||
case 2:
|
||||
localScale.z *= num3;
|
||||
break;
|
||||
}
|
||||
foreach (Transform proxyParent1 in proxyParentSet)
|
||||
proxyParent1.localScale = localScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Transform CreateTempMarker(
|
||||
string markerObjectName,
|
||||
Transform parentTransform,
|
||||
IReadOnlyList<Transform> childTransforms,
|
||||
Vector3 markerWorldPosition,
|
||||
Quaternion markerWorldRotation,
|
||||
Vector3 markerLocalScale,
|
||||
out TempBoneMarker tempBoneMarker)
|
||||
{
|
||||
if (Object.op_Equality((Object)parentTransform, (Object)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, true);
|
||||
transform.position = markerWorldPosition;
|
||||
transform.rotation = markerWorldRotation;
|
||||
transform.localScale = markerLocalScale;
|
||||
tempBoneMarker = ((Component)transform).gameObject.AddComponent<TempBoneMarker>();
|
||||
tempBoneMarker.originalParent = parentTransform;
|
||||
tempBoneMarker.additionalInfo = "";
|
||||
tempBoneMarker.wrappedChildNames = new List<string>();
|
||||
for (int index = 0; index < childTransforms.Count; ++index)
|
||||
{
|
||||
Transform childTransform = childTransforms[index];
|
||||
if (!Object.op_Equality((Object)childTransform, (Object)null))
|
||||
{
|
||||
tempBoneMarker.wrappedChildNames.Add(((Object)childTransform).name);
|
||||
childTransform.SetParent(transform, true);
|
||||
}
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e11035ab0ef1a734eae6c759861df3b3
|
||||
748
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs
Normal file
748
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs
Normal file
@@ -0,0 +1,748 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BodyPoseMatch_Leg
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BodyPoseMatch_Leg
|
||||
{
|
||||
private readonly BodyPoseMatch_CommonUtil poseMatchCommonUtil;
|
||||
|
||||
public BodyPoseMatch_Leg() => this.poseMatchCommonUtil = new BodyPoseMatch_CommonUtil();
|
||||
|
||||
public void AlignBothUpperLegs(
|
||||
GameObject proxyObject,
|
||||
IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap,
|
||||
GameObject targetObject,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap)
|
||||
{
|
||||
if (Object.op_Equality((Object)proxyObject, (Object)null) || Object.op_Equality((Object)targetObject, (Object)null))
|
||||
throw new AutoMorpherException("Proxy or Target Object is Missing", "[BodyPoseMatch_Leg] AlignBothUpperLegs\n - proxyObject or targetObject is null");
|
||||
this.AlignUpperLeg_BodyMatch(proxyObject, proxyBakedBodyMeshes, proxyBoneMap, targetObject, targetBakedBodyMeshes, targetBoneMap, true);
|
||||
this.AlignUpperLeg_BodyMatch(proxyObject, proxyBakedBodyMeshes, proxyBoneMap, targetObject, targetBakedBodyMeshes, targetBoneMap, false);
|
||||
}
|
||||
|
||||
public void AlignBothUpperLegs(
|
||||
Transform targetTransform,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
Transform clothesTransform,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
ProfileData profileData,
|
||||
Vector3 comprehensiveScale)
|
||||
{
|
||||
this.AlignUpperLeg_Profile(targetTransform, targetBakedBodyMeshes, targetBoneMap, clothesTransform, clothBoneMap, profileData, comprehensiveScale, true);
|
||||
this.AlignUpperLeg_Profile(targetTransform, targetBakedBodyMeshes, targetBoneMap, clothesTransform, clothBoneMap, profileData, comprehensiveScale, false);
|
||||
}
|
||||
|
||||
public void AlignUpperLeg_BodyMatch(
|
||||
GameObject proxyObject,
|
||||
IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap,
|
||||
GameObject targetObject,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
bool isLeft)
|
||||
{
|
||||
if (Object.op_Equality((Object)proxyObject, (Object)null) || Object.op_Equality((Object)targetObject, (Object)null))
|
||||
throw new AutoMorpherException("Proxy or Target Object is Missing", "[BodyPoseMatch_Leg] AlignUpperLeg_BodyMatch\n - proxyObject or targetObject is null");
|
||||
RegionStats legRegionStats1 = this.ComputeLegRegionStats(proxyObject.transform, proxyBakedBodyMeshes, proxyBoneMap, isLeft);
|
||||
RegionStats legRegionStats2 = this.ComputeLegRegionStats(targetObject.transform, targetBakedBodyMeshes, targetBoneMap, isLeft);
|
||||
if ((double)legRegionStats1.length < 9.9999997473787516E-05 || (double)legRegionStats2.length < 9.9999997473787516E-05)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] AlignUpperLeg_BodyMatch: leg PCA 통계가 비정상입니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
HumanBodyBones key = isLeft ? (HumanBodyBones)1 : (HumanBodyBones)2;
|
||||
HashSet<Transform> upperLegSet;
|
||||
if (proxyBoneMap == null || !proxyBoneMap.TryGetValue(key, out upperLegSet) || upperLegSet == null || upperLegSet.Count == 0)
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] AlignUpperLeg_BodyMatch: proxy UpperLeg 본을 찾지 못했습니다.");
|
||||
else
|
||||
this.AlignUpperLegCore((IReadOnlyCollection<Transform>)upperLegSet, legRegionStats1.center, legRegionStats2.center);
|
||||
}
|
||||
}
|
||||
|
||||
public void AlignUpperLeg_Profile(
|
||||
Transform targetTransform,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
Transform clothesTransform,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
ProfileData profileData,
|
||||
Vector3 comprehensiveScale,
|
||||
bool isLeft)
|
||||
{
|
||||
if (Object.op_Equality((Object)targetTransform, (Object)null))
|
||||
throw new AutoMorpherException("Target Object is Missing", "[BodyPoseMatch_Leg] AlignUpperLeg_Profile\n - targetObject is null");
|
||||
HumanBodyBones key = isLeft ? (HumanBodyBones)1 : (HumanBodyBones)2;
|
||||
BoneSpatialData boneSpatialData = isLeft ? profileData.LeftUpperLegSpatialData : profileData.RightUpperLegSpatialData;
|
||||
if (boneSpatialData == null || boneSpatialData.pcaData == null)
|
||||
{
|
||||
Debug.LogWarning((object)$"[BodyPoseMatch_Leg] AlignUpperLeg: {(isLeft ? "Left" : "Right")} spatial data missing.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 profilePcaCenterWorld = this.poseMatchCommonUtil.GetProfilePcaCenterWorld(clothBoneMap, boneSpatialData, comprehensiveScale);
|
||||
RegionStats legRegionStats = this.ComputeLegRegionStats(targetTransform, targetBakedBodyMeshes, targetBoneMap, isLeft);
|
||||
if ((double)legRegionStats.length < 9.9999997473787516E-05)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] AlignUpperLeg: Target leg PCA 통계가 비정상입니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
HashSet<Transform> upperLegSet;
|
||||
if (clothBoneMap == null || !clothBoneMap.TryGetValue(key, out upperLegSet) || upperLegSet == null || upperLegSet.Count == 0)
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] AlignUpperLeg: clothes UpperLeg 본을 찾지 못했습니다.");
|
||||
else
|
||||
this.AlignUpperLegCore((IReadOnlyCollection<Transform>)upperLegSet, profilePcaCenterWorld, legRegionStats.center);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AlignUpperLegCore(
|
||||
IReadOnlyCollection<Transform> upperLegSet,
|
||||
Vector3 sourceLegCenterWorld,
|
||||
Vector3 targetLegCenterWorld)
|
||||
{
|
||||
if (upperLegSet == null || upperLegSet.Count == 0)
|
||||
return;
|
||||
Vector3 vector3 = Vector3.op_Subtraction(targetLegCenterWorld, sourceLegCenterWorld);
|
||||
vector3.y = 0.0f;
|
||||
foreach (Transform upperLeg in (IEnumerable<Transform>)upperLegSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)upperLeg, (Object)null))
|
||||
{
|
||||
Transform transform = upperLeg;
|
||||
transform.position = Vector3.op_Addition(transform.position, vector3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RegionStats ComputeLegRegionStats(
|
||||
Transform avatarTransform,
|
||||
IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap,
|
||||
bool isLeft)
|
||||
{
|
||||
HumanBodyBones[] targetHumanBones;
|
||||
if (!isLeft)
|
||||
targetHumanBones = new HumanBodyBones[2]
|
||||
{
|
||||
(HumanBodyBones) 2,
|
||||
(HumanBodyBones) 4
|
||||
};
|
||||
else
|
||||
targetHumanBones = new HumanBodyBones[2]
|
||||
{
|
||||
(HumanBodyBones) 1,
|
||||
(HumanBodyBones) 3
|
||||
};
|
||||
List<Vector3> points = this.poseMatchCommonUtil.CollectHumanoidVerticesWorld((IReadOnlyList<HumanBodyBones>)targetHumanBones, avatarBakedBodyMeshes, avatarBoneMap);
|
||||
if (points == null || points.Count == 0)
|
||||
{
|
||||
Debug.LogWarning((object)$"[BodyPoseMatch_Leg] ComputeLegRegionStats: leg vertices 0개. avatar={((Object)avatarTransform)?.name}, isLeft={isLeft}");
|
||||
return new RegionStats();
|
||||
}
|
||||
RegionStats regionStats = new PcaUtil().ComputeRegionStats((IList<Vector3>)points);
|
||||
Transform boneFromBoneMap1 = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, isLeft ? (HumanBodyBones)1 : (HumanBodyBones)2);
|
||||
Transform boneFromBoneMap2 = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, isLeft ? (HumanBodyBones)3 : (HumanBodyBones)4);
|
||||
if (Object.op_Inequality((Object)boneFromBoneMap1, (Object)null) && Object.op_Inequality((Object)boneFromBoneMap2, (Object)null))
|
||||
{
|
||||
Vector3 vector3_1 = Vector3.op_Subtraction(boneFromBoneMap2.position, boneFromBoneMap1.position);
|
||||
Vector3 normalized = ((Vector3)ref vector3_1).normalized;
|
||||
Vector3 vector3_2 = ((Vector3)ref regionStats.principalAxis).normalized;
|
||||
if ((double)Vector3.Dot(vector3_2, normalized) < 0.0)
|
||||
vector3_2 = Vector3.op_UnaryNegation(vector3_2);
|
||||
regionStats.principalAxis = vector3_2;
|
||||
}
|
||||
return regionStats;
|
||||
}
|
||||
|
||||
public void ScalingBothLegsAndFoots(
|
||||
GameObject proxyObject,
|
||||
IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap,
|
||||
GameObject targetObject,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
bool autoDetectAxis = true,
|
||||
int forceAxisIndex = 1)
|
||||
{
|
||||
this.ScalingLeg(proxyBoneMap, targetBoneMap, true, autoDetectAxis, forceAxisIndex);
|
||||
this.ScalingLeg(proxyBoneMap, targetBoneMap, false, autoDetectAxis, forceAxisIndex);
|
||||
if (proxyBakedBodyMeshes != null)
|
||||
{
|
||||
foreach (BakedBodyMesh proxyBakedBodyMesh in (IEnumerable<BakedBodyMesh>)proxyBakedBodyMeshes)
|
||||
proxyBakedBodyMesh?.ReBakeMesh();
|
||||
}
|
||||
this.ScalingFoot(proxyObject, proxyBakedBodyMeshes, proxyBoneMap, targetObject, targetBakedBodyMeshes, targetBoneMap, true);
|
||||
this.ScalingFoot(proxyObject, proxyBakedBodyMeshes, proxyBoneMap, targetObject, targetBakedBodyMeshes, targetBoneMap, false);
|
||||
}
|
||||
|
||||
public void ScalingBothLegsAndFoots(
|
||||
Transform targetTransform,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
Transform clothTransform,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
ProfileData profileData,
|
||||
Vector3 comprehensiveScale,
|
||||
bool autoDetectAxis = true,
|
||||
int forceAxisIndex = 1)
|
||||
{
|
||||
this.ScalingLeg(clothBoneMap, targetBoneMap, true, autoDetectAxis, forceAxisIndex);
|
||||
this.ScalingLeg(clothBoneMap, targetBoneMap, false, autoDetectAxis, forceAxisIndex);
|
||||
this.ScalingFoot(profileData, comprehensiveScale, clothBoneMap, targetTransform, targetBakedBodyMeshes, targetBoneMap, true);
|
||||
this.ScalingFoot(profileData, comprehensiveScale, clothBoneMap, targetTransform, targetBakedBodyMeshes, targetBoneMap, false);
|
||||
}
|
||||
|
||||
public void ScalingLeg(
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
bool isLeft,
|
||||
bool autoDetectAxis = true,
|
||||
int forceAxisIndex = 1)
|
||||
{
|
||||
HumanBodyBones humanBodyBones1 = isLeft ? (HumanBodyBones)1 : (HumanBodyBones)2;
|
||||
HumanBodyBones bone = isLeft ? (HumanBodyBones)3 : (HumanBodyBones)4;
|
||||
Transform boneFromBoneMap1 = this.poseMatchCommonUtil.GetBoneFromBoneMap(proxyBoneMap, humanBodyBones1);
|
||||
Transform boneFromBoneMap2 = this.poseMatchCommonUtil.GetBoneFromBoneMap(proxyBoneMap, bone);
|
||||
Transform boneFromBoneMap3 = this.poseMatchCommonUtil.GetBoneFromBoneMap(targetBoneMap, humanBodyBones1);
|
||||
Transform boneFromBoneMap4 = this.poseMatchCommonUtil.GetBoneFromBoneMap(targetBoneMap, bone);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap1, (Object)null) || Object.op_Equality((Object)boneFromBoneMap2, (Object)null) || Object.op_Equality((Object)boneFromBoneMap3, (Object)null) || Object.op_Equality((Object)boneFromBoneMap4, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] ScalingLeg: some leg bones are null");
|
||||
}
|
||||
else
|
||||
{
|
||||
HashSet<Transform> proxyParentSet;
|
||||
if (proxyBoneMap == null || !proxyBoneMap.TryGetValue(humanBodyBones1, out proxyParentSet) || proxyParentSet == null || proxyParentSet.Count == 0)
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] ScalingLeg: proxy upperLeg bone set missing");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.poseMatchCommonUtil.BoneLengthAdjust(boneFromBoneMap1, boneFromBoneMap2, boneFromBoneMap3, boneFromBoneMap4, proxyParentSet, autoDetectAxis, forceAxisIndex);
|
||||
HumanBodyBones humanBodyBones2 = isLeft ? (HumanBodyBones)5 : (HumanBodyBones)6;
|
||||
Transform boneFromBoneMap5 = this.poseMatchCommonUtil.GetBoneFromBoneMap(proxyBoneMap, humanBodyBones2);
|
||||
Transform boneFromBoneMap6 = this.poseMatchCommonUtil.GetBoneFromBoneMap(targetBoneMap, humanBodyBones2);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap5, (Object)null) || Object.op_Equality((Object)boneFromBoneMap6, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] ScalingFoot: proxyFoot or targetFoot is null");
|
||||
}
|
||||
else
|
||||
{
|
||||
float y = boneFromBoneMap5.position.y;
|
||||
float num = boneFromBoneMap6.position.y - y;
|
||||
if ((double)Mathf.Abs(num) <= 9.9999999747524271E-07)
|
||||
return;
|
||||
Vector3 vector3;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3)ref vector3).\u002Ector(0.0f, num, 0.0f);
|
||||
HashSet<Transform> transformSet;
|
||||
if (proxyBoneMap == null || !proxyBoneMap.TryGetValue(humanBodyBones2, out transformSet) || transformSet == null || transformSet.Count <= 0)
|
||||
return;
|
||||
foreach (Transform transform1 in transformSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform1, (Object)null))
|
||||
{
|
||||
Transform transform2 = transform1;
|
||||
transform2.position = Vector3.op_Addition(transform2.position, vector3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ScalingFootCore(
|
||||
Transform proxyHip,
|
||||
Transform targetFoot,
|
||||
bool isLeft,
|
||||
HashSet<Transform> footBoneSet,
|
||||
float proxyToeF,
|
||||
float proxyHeelF,
|
||||
float proxySideMin,
|
||||
float proxySideMax,
|
||||
float proxySoleY,
|
||||
float targetToeF,
|
||||
float targetHeelF,
|
||||
float targetSideMin,
|
||||
float targetSideMax,
|
||||
float targetSoleY)
|
||||
{
|
||||
if (Object.op_Equality((Object)proxyHip, (Object)null) || Object.op_Equality((Object)targetFoot, (Object)null))
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] ScalingFootCore: proxyHip or targetFoot is null");
|
||||
else if (footBoneSet == null || footBoneSet.Count == 0)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] ScalingFootCore: footBoneSet is null or empty");
|
||||
}
|
||||
else
|
||||
{
|
||||
Dictionary<Transform, List<Transform>> dictionary = new Dictionary<Transform, List<Transform>>();
|
||||
foreach (Transform footBone in footBoneSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)footBone, (Object)null))
|
||||
{
|
||||
Transform parent = footBone.parent;
|
||||
List<Transform> transformList;
|
||||
if (!dictionary.TryGetValue(parent, out transformList))
|
||||
{
|
||||
transformList = new List<Transform>();
|
||||
dictionary.Add(parent, transformList);
|
||||
}
|
||||
transformList.Add(footBone);
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<Transform, List<Transform>> keyValuePair in dictionary)
|
||||
{
|
||||
Transform key = keyValuePair.Key;
|
||||
List<Transform> childTransforms = keyValuePair.Value;
|
||||
if (!Object.op_Equality((Object)key, (Object)null) && childTransforms != null && childTransforms.Count != 0)
|
||||
{
|
||||
Transform transform = childTransforms[0];
|
||||
if (!Object.op_Equality((Object)transform, (Object)null))
|
||||
{
|
||||
Transform tempMarker = this.poseMatchCommonUtil.CreateTempMarker("scaleSupportBone", key, (IReadOnlyList<Transform>)childTransforms, transform.position, Quaternion.identity, transform.localScale, out TempBoneMarker _);
|
||||
if (!Object.op_Equality((Object)tempMarker, (Object)null))
|
||||
{
|
||||
this.ScaleAndAlignAlongAxis(proxyHip, proxyHip.forward, proxyHip.up, tempMarker, proxyToeF, proxyHeelF, targetFoot, targetToeF, targetHeelF);
|
||||
this.ScaleAndAlignAlongAxis(proxyHip, proxyHip.right, proxyHip.up, tempMarker, isLeft ? proxySideMin : proxySideMax, isLeft ? proxySideMax : proxySideMin, targetFoot, isLeft ? targetSideMin : targetSideMax, isLeft ? targetSideMax : targetSideMin);
|
||||
this.ScaleAndAlignAlongAxis(proxyHip, proxyHip.up, proxyHip.forward, tempMarker, 0.0f, proxySoleY, targetFoot, 0.0f, targetSoleY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ScalingFoot(
|
||||
GameObject proxyObject,
|
||||
IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap,
|
||||
GameObject targetObject,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
bool isLeft)
|
||||
{
|
||||
if (Object.op_Equality((Object)proxyObject, (Object)null) || Object.op_Equality((Object)targetObject, (Object)null))
|
||||
throw new AutoMorpherException("Proxy or Target Object is Missing", "[BodyPoseMatch_Leg] ScalingFoot\n - proxyObject or targetObject is null");
|
||||
HumanBodyBones humanBodyBones = isLeft ? (HumanBodyBones)5 : (HumanBodyBones)6;
|
||||
Transform boneFromBoneMap1 = this.poseMatchCommonUtil.GetBoneFromBoneMap(proxyBoneMap, humanBodyBones);
|
||||
Transform boneFromBoneMap2 = this.poseMatchCommonUtil.GetBoneFromBoneMap(targetBoneMap, humanBodyBones);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap1, (Object)null) || Object.op_Equality((Object)boneFromBoneMap2, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] ScalingFoot: proxyFoot or targetFoot is null");
|
||||
}
|
||||
else
|
||||
{
|
||||
float footMinUp1;
|
||||
float heelF1;
|
||||
float toeF1;
|
||||
float sideMin1;
|
||||
float sideMax1;
|
||||
float footMinUp2;
|
||||
float heelF2;
|
||||
float toeF2;
|
||||
float sideMin2;
|
||||
float sideMax2;
|
||||
if (!this.TryGetFootSpatialData(proxyObject.transform, proxyBakedBodyMeshes, proxyBoneMap, isLeft, out float _, out footMinUp1, out heelF1, out toeF1, out sideMin1, out sideMax1) || !this.TryGetFootSpatialData(targetObject.transform, targetBakedBodyMeshes, targetBoneMap, isLeft, out float _, out footMinUp2, out heelF2, out toeF2, out sideMin2, out sideMax2))
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] ScalingFoot: foot spatial data 계산 실패");
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform boneFromBoneMap3 = this.poseMatchCommonUtil.GetBoneFromBoneMap(proxyBoneMap, (HumanBodyBones)0);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap3, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] ScalingFoot: proxyHip is null");
|
||||
}
|
||||
else
|
||||
{
|
||||
HashSet<Transform> footBoneSet;
|
||||
if (proxyBoneMap == null || !proxyBoneMap.TryGetValue(humanBodyBones, out footBoneSet) || footBoneSet == null || footBoneSet.Count == 0)
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] ScalingFoot: footBoneSet is missing");
|
||||
else
|
||||
this.ScalingFootCore(boneFromBoneMap3, boneFromBoneMap2, isLeft, footBoneSet, toeF1, heelF1, sideMin1, sideMax1, footMinUp1, toeF2, heelF2, sideMin2, sideMax2, footMinUp2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ScalingFoot(
|
||||
ProfileData profileData,
|
||||
Vector3 comprehensiveScale,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothBoneMap,
|
||||
Transform targetTransform,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap,
|
||||
bool isLeft)
|
||||
{
|
||||
if (Object.op_Equality((Object)targetTransform, (Object)null))
|
||||
throw new AutoMorpherException("Target Transform is Missing", "[BodyPoseMatch_Leg] ScalingFoot\n - targetTransform is null");
|
||||
HumanBodyBones humanBodyBones = isLeft ? (HumanBodyBones)5 : (HumanBodyBones)6;
|
||||
Transform boneFromBoneMap1 = this.poseMatchCommonUtil.GetBoneFromBoneMap(clothBoneMap, humanBodyBones);
|
||||
Transform boneFromBoneMap2 = this.poseMatchCommonUtil.GetBoneFromBoneMap(targetBoneMap, humanBodyBones);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap1, (Object)null) || Object.op_Equality((Object)boneFromBoneMap2, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] ScalingFoot: proxyFoot or targetFoot is null");
|
||||
}
|
||||
else
|
||||
{
|
||||
float footMinUp;
|
||||
float heelF;
|
||||
float toeF;
|
||||
float sideMin;
|
||||
float sideMax;
|
||||
if (!this.TryGetFootSpatialData(((Component)targetTransform).transform, targetBakedBodyMeshes, targetBoneMap, isLeft, out float _, out footMinUp, out heelF, out toeF, out sideMin, out sideMax))
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] ScalingFoot: foot spatial data 계산 실패");
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform boneFromBoneMap3 = this.poseMatchCommonUtil.GetBoneFromBoneMap(clothBoneMap, (HumanBodyBones)0);
|
||||
BoneSpatialData spatialData = isLeft ? profileData.LeftFootSpatialData : profileData.RightFootSpatialData;
|
||||
if (spatialData == null)
|
||||
{
|
||||
Debug.LogWarning((object)"[AvatarBodyMatchUtil] AlignNeckCenterByPcaWithHipZ: Profile FootSpatialData Data is Not exist.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform boneFromBoneMap4 = this.poseMatchCommonUtil.GetBoneFromBoneMap(clothBoneMap, spatialData.refBone);
|
||||
if (Object.op_Equality((Object)boneFromBoneMap4, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] ScalingFoot: clothRefBone is null");
|
||||
}
|
||||
else
|
||||
{
|
||||
BodyPoseMatch_CommonUtil poseMatchCommonUtil = new BodyPoseMatch_CommonUtil();
|
||||
float proxyToeF = Vector3.Distance(boneFromBoneMap4.position, poseMatchCommonUtil.GetProfileVolumeMaxWorld(clothBoneMap, spatialData, 0, comprehensiveScale));
|
||||
float proxyHeelF = -Vector3.Distance(boneFromBoneMap4.position, poseMatchCommonUtil.GetProfileVolumeMinWorld(clothBoneMap, spatialData, 0, comprehensiveScale));
|
||||
float proxySideMax = Vector3.Distance(boneFromBoneMap4.position, poseMatchCommonUtil.GetProfileVolumeMaxWorld(clothBoneMap, spatialData, 1, comprehensiveScale));
|
||||
float proxySideMin = -Vector3.Distance(boneFromBoneMap4.position, poseMatchCommonUtil.GetProfileVolumeMinWorld(clothBoneMap, spatialData, 1, comprehensiveScale));
|
||||
float proxySoleY = -Vector3.Distance(boneFromBoneMap4.position, poseMatchCommonUtil.GetProfileVolumeMinWorld(clothBoneMap, spatialData, 2, comprehensiveScale));
|
||||
HashSet<Transform> footBoneSet;
|
||||
if (clothBoneMap == null || !clothBoneMap.TryGetValue(humanBodyBones, out footBoneSet) || footBoneSet == null || footBoneSet.Count == 0)
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] ScalingFoot: cloth footBoneSet is missing");
|
||||
else
|
||||
this.ScalingFootCore(boneFromBoneMap3, boneFromBoneMap2, isLeft, footBoneSet, proxyToeF, proxyHeelF, proxySideMin, proxySideMax, proxySoleY, toeF, heelF, sideMin, sideMax, footMinUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ScaleAndAlignAlongAxis(
|
||||
Transform baseTransform,
|
||||
Vector3 targetWorldAxis,
|
||||
Vector3 targetWorldUpAxis,
|
||||
Transform proxyFoot,
|
||||
float proxyMaxF,
|
||||
float proxyMinF,
|
||||
Transform targetFoot,
|
||||
float targetMaxF,
|
||||
float targetMinF)
|
||||
{
|
||||
float num1 = proxyMaxF - proxyMinF;
|
||||
float num2 = targetMaxF - targetMinF;
|
||||
if ((double)Mathf.Abs(num1) < 9.9999997473787516E-05 || (double)Mathf.Abs(num2) < 9.9999997473787516E-05)
|
||||
{
|
||||
Debug.LogWarning((object)"[AdjustFootForwardScale] foot span too small.");
|
||||
}
|
||||
else
|
||||
{
|
||||
float num3 = num2 / num1;
|
||||
if (!float.IsFinite(num3) || (double)num3 <= 0.0)
|
||||
{
|
||||
Debug.LogWarning((object)$"[ScaleAndAlignAlongAxis] invalid scaleF: {num3}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 vector3_1 = Vector3.op_Addition(proxyFoot.position, Vector3.op_Multiply(targetWorldAxis, proxyMinF));
|
||||
Vector3 vector3_2 = Vector3.op_Addition(targetFoot.position, Vector3.op_Multiply(targetWorldAxis, targetMinF));
|
||||
GameObject gameObject1 = new GameObject("proxyAnchor");
|
||||
gameObject1.transform.SetParent(proxyFoot);
|
||||
gameObject1.transform.position = vector3_1;
|
||||
GameObject gameObject2 = new GameObject("targetAnchor");
|
||||
gameObject2.transform.SetParent(targetFoot);
|
||||
gameObject2.transform.position = vector3_2;
|
||||
Transform parent = proxyFoot.parent;
|
||||
Vector3 position = proxyFoot.position;
|
||||
Transform transform1 = new GameObject("ScaleParnet").transform;
|
||||
transform1.SetParent(parent);
|
||||
transform1.position = position;
|
||||
transform1.rotation = Quaternion.LookRotation(targetWorldAxis, targetWorldUpAxis);
|
||||
proxyFoot.SetParent(transform1, true);
|
||||
proxyFoot.localPosition = Vector3.zero;
|
||||
Vector3 localScale = transform1.localScale;
|
||||
localScale.z *= num3;
|
||||
transform1.localScale = localScale;
|
||||
proxyFoot.SetParent(parent, true);
|
||||
proxyFoot.position = position;
|
||||
float num4 = Vector3.Dot(Vector3.op_Subtraction(gameObject2.transform.position, gameObject1.transform.position), targetWorldAxis);
|
||||
Vector3 vector3_3 = Vector3.op_Multiply(targetWorldAxis, num4);
|
||||
Transform transform2 = proxyFoot;
|
||||
transform2.position = Vector3.op_Addition(transform2.position, vector3_3);
|
||||
Object.DestroyImmediate((Object)((Component)transform1).gameObject);
|
||||
Object.DestroyImmediate((Object)gameObject1);
|
||||
Object.DestroyImmediate((Object)gameObject2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetFootSpatialData(
|
||||
Transform avatarTransform,
|
||||
IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap,
|
||||
bool isLeft,
|
||||
out float footMaxUp,
|
||||
out float footMinUp,
|
||||
out float heelF,
|
||||
out float toeF,
|
||||
out float sideMin,
|
||||
out float sideMax,
|
||||
float weightThreshold = 0.15f,
|
||||
int sampleStep = 1)
|
||||
{
|
||||
footMaxUp = float.NegativeInfinity;
|
||||
footMinUp = float.PositiveInfinity;
|
||||
heelF = float.PositiveInfinity;
|
||||
toeF = float.NegativeInfinity;
|
||||
sideMin = float.PositiveInfinity;
|
||||
sideMax = float.NegativeInfinity;
|
||||
if (Object.op_Equality((Object)avatarTransform, (Object)null) || avatarBakedBodyMeshes == null || avatarBoneMap == null || avatarBoneMap.Count == 0)
|
||||
return false;
|
||||
HumanBodyBones key = isLeft ? (HumanBodyBones)5 : (HumanBodyBones)6;
|
||||
HashSet<Transform> transformSet;
|
||||
if (!avatarBoneMap.TryGetValue(key, out transformSet) || transformSet == null || transformSet.Count == 0)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Leg] TryGetFootSpatialData\n - foot bone set is missing");
|
||||
return false;
|
||||
}
|
||||
Vector3 up = Vector3.up;
|
||||
Vector3 forward = Vector3.forward;
|
||||
Vector3 right = Vector3.right;
|
||||
HashSet<Transform> targetBoneSet = new HashSet<Transform>();
|
||||
Transform transform1 = (Transform)null;
|
||||
foreach (Transform transform2 in transformSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform2, (Object)null))
|
||||
{
|
||||
if (Object.op_Equality((Object)transform1, (Object)null))
|
||||
transform1 = transform2;
|
||||
Stack<Transform> transformStack = new Stack<Transform>();
|
||||
transformStack.Push(transform2);
|
||||
while (transformStack.Count > 0)
|
||||
{
|
||||
Transform transform3 = transformStack.Pop();
|
||||
if (!Object.op_Equality((Object)transform3, (Object)null) && targetBoneSet.Add(transform3))
|
||||
{
|
||||
for (int index = 0; index < transform3.childCount; ++index)
|
||||
transformStack.Push(transform3.GetChild(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.op_Equality((Object)transform1, (Object)null) || targetBoneSet.Count == 0)
|
||||
return false;
|
||||
List<Vector3> vector3List = this.poseMatchCommonUtil.CollectWeightedVerticesWorld(avatarBakedBodyMeshes, targetBoneSet, weightThreshold, sampleStep);
|
||||
if (vector3List == null || vector3List.Count == 0)
|
||||
return false;
|
||||
for (int index = 0; index < vector3List.Count; ++index)
|
||||
{
|
||||
Vector3 vector3 = Vector3.op_Subtraction(vector3List[index], transform1.position);
|
||||
float num1 = Vector3.Dot(vector3, up);
|
||||
if ((double)num1 < (double)footMinUp)
|
||||
footMinUp = num1;
|
||||
if ((double)num1 > (double)footMaxUp)
|
||||
footMaxUp = num1;
|
||||
float num2 = Vector3.Dot(vector3, forward);
|
||||
if ((double)num2 < (double)heelF)
|
||||
heelF = num2;
|
||||
if ((double)num2 > (double)toeF)
|
||||
toeF = num2;
|
||||
float num3 = Vector3.Dot(vector3, right);
|
||||
if ((double)num3 < (double)sideMin)
|
||||
sideMin = num3;
|
||||
if ((double)num3 > (double)sideMax)
|
||||
sideMax = num3;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void DrawLegPcaDebug(
|
||||
GameObject avatarObject,
|
||||
IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap,
|
||||
bool isLeft,
|
||||
Color centerColor,
|
||||
Color axisColor,
|
||||
float axisScale = 1f,
|
||||
float duration = 1f)
|
||||
{
|
||||
if (Object.op_Equality((Object)avatarObject, (Object)null))
|
||||
return;
|
||||
RegionStats legRegionStats = this.ComputeLegRegionStats(avatarObject.transform, avatarBakedBodyMeshes, avatarBoneMap, isLeft);
|
||||
if ((double)legRegionStats.length < 9.9999997473787516E-05)
|
||||
{
|
||||
Debug.LogWarning((object)$"[AvatarBodyMatchUtil] DrawLegPcaDebug: PCA length too small (avatar={((Object)avatarObject).name}, isLeft={isLeft})");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 center = legRegionStats.center;
|
||||
Vector3 normalized = ((Vector3)ref legRegionStats.principalAxis).normalized;
|
||||
float num1 = 0.03f * axisScale;
|
||||
Debug.DrawLine(Vector3.op_Addition(center, Vector3.op_Multiply(Vector3.up, num1)), Vector3.op_Subtraction(center, Vector3.op_Multiply(Vector3.up, num1)), centerColor, duration);
|
||||
Debug.DrawLine(Vector3.op_Addition(center, Vector3.op_Multiply(Vector3.right, num1)), Vector3.op_Subtraction(center, Vector3.op_Multiply(Vector3.right, num1)), centerColor, duration);
|
||||
Debug.DrawLine(Vector3.op_Addition(center, Vector3.op_Multiply(Vector3.forward, num1)), Vector3.op_Subtraction(center, Vector3.op_Multiply(Vector3.forward, num1)), centerColor, duration);
|
||||
float num2 = legRegionStats.length * 0.5f * axisScale;
|
||||
Debug.DrawLine(Vector3.op_Subtraction(center, Vector3.op_Multiply(normalized, num2)), Vector3.op_Addition(center, Vector3.op_Multiply(normalized, num2)), axisColor, duration);
|
||||
Debug.Log((object)($"[DrawLegPcaDebug] avatar={((Object)avatarObject).name}, isLeft={isLeft}, " + $"center={center}, axis={normalized}, len={legRegionStats.length}, avgRadius={legRegionStats.avgRadius}"));
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawFootSpatialDebug(
|
||||
GameObject avatarObject,
|
||||
IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap,
|
||||
bool isLeft,
|
||||
Color centerColor,
|
||||
Color axisColor,
|
||||
Color boxColor,
|
||||
float axisScale = 0.1f,
|
||||
float duration = 1f,
|
||||
float weightThreshold = 0.15f,
|
||||
int sampleStep = 1)
|
||||
{
|
||||
if (Object.op_Equality((Object)avatarObject, (Object)null))
|
||||
return;
|
||||
float footMaxUp;
|
||||
float footMinUp;
|
||||
float heelF;
|
||||
float toeF;
|
||||
float sideMin;
|
||||
float sideMax;
|
||||
if (!this.TryGetFootSpatialData(avatarObject.transform, avatarBakedBodyMeshes, avatarBoneMap, isLeft, out footMaxUp, out footMinUp, out heelF, out toeF, out sideMin, out sideMax, weightThreshold, sampleStep))
|
||||
{
|
||||
Debug.LogWarning((object)("[BodyPoseMatch_Leg] DrawFootSpatialDebug" + $"\n - Failed to compute Foot Spatial Data (avatar={((Object)avatarObject).name}, isLeft={isLeft})"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (avatarBoneMap == null || avatarBoneMap.Count == 0)
|
||||
return;
|
||||
HumanBodyBones key = isLeft ? (HumanBodyBones)5 : (HumanBodyBones)6;
|
||||
HashSet<Transform> transformSet;
|
||||
if (!avatarBoneMap.TryGetValue(key, out transformSet) || transformSet == null || transformSet.Count == 0)
|
||||
return;
|
||||
Transform transform1 = (Transform)null;
|
||||
foreach (Transform transform2 in transformSet)
|
||||
{
|
||||
if (Object.op_Inequality((Object)transform2, (Object)null))
|
||||
{
|
||||
transform1 = transform2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Object.op_Equality((Object)transform1, (Object)null))
|
||||
return;
|
||||
Vector3 position = transform1.position;
|
||||
Transform boneFromBoneMap = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, (HumanBodyBones)0);
|
||||
Vector3 vector3_1 = Object.op_Inequality((Object)boneFromBoneMap, (Object)null) ? boneFromBoneMap.forward : avatarObject.transform.forward;
|
||||
vector3_1.y = 0.0f;
|
||||
if ((double)((Vector3)ref vector3_1).sqrMagnitude < 9.9999999747524271E-07)
|
||||
vector3_1 = Vector3.forward;
|
||||
((Vector3)ref vector3_1).Normalize();
|
||||
Vector3 vector3_2 = Vector3.Cross(Vector3.up, vector3_1);
|
||||
if ((double)((Vector3)ref vector3_2).sqrMagnitude < 9.9999999747524271E-07)
|
||||
vector3_2 = Vector3.right;
|
||||
((Vector3)ref vector3_2).Normalize();
|
||||
Vector3 vector3_3 = Object.op_Inequality((Object)boneFromBoneMap, (Object)null) ? boneFromBoneMap.up : avatarObject.transform.up;
|
||||
if ((double)((Vector3)ref vector3_3).sqrMagnitude < 9.9999999747524271E-07)
|
||||
vector3_3 = Vector3.up;
|
||||
((Vector3)ref vector3_3).Normalize();
|
||||
float size1 = Mathf.Max(0.0001f, axisScale * 0.5f);
|
||||
DrawCross(position, vector3_3, vector3_2, centerColor, size1, duration);
|
||||
DrawCross(position, vector3_3, vector3_1, centerColor, size1, duration);
|
||||
float len = Mathf.Max(0.0001f, axisScale * 2f);
|
||||
DrawAxisLine(position, vector3_3, len, axisColor, duration);
|
||||
DrawAxisLine(position, vector3_1, len, axisColor, duration);
|
||||
DrawAxisLine(position, vector3_2, len, axisColor, duration);
|
||||
Vector3[] c = new Vector3[8];
|
||||
int num1 = 0;
|
||||
for (int index1 = 0; index1 < 2; ++index1)
|
||||
{
|
||||
float num2 = index1 == 0 ? footMinUp : footMaxUp;
|
||||
for (int index2 = 0; index2 < 2; ++index2)
|
||||
{
|
||||
float num3 = index2 == 0 ? heelF : toeF;
|
||||
for (int index3 = 0; index3 < 2; ++index3)
|
||||
{
|
||||
float num4 = index3 == 0 ? sideMin : sideMax;
|
||||
c[num1++] = Vector3.op_Addition(Vector3.op_Addition(Vector3.op_Addition(position, Vector3.op_Multiply(vector3_3, num2)), Vector3.op_Multiply(vector3_1, num3)), Vector3.op_Multiply(vector3_2, num4));
|
||||
}
|
||||
}
|
||||
}
|
||||
DrawBoxEdges(c, boxColor, duration);
|
||||
float size2 = Mathf.Max(5E-05f, size1 * 0.6f);
|
||||
for (int index = 0; index < c.Length; ++index)
|
||||
DrawCross(c[index], vector3_1, vector3_2, boxColor, size2, duration);
|
||||
Debug.Log((object)($"[DrawFootSpatialDebug] avatar={((Object)avatarObject).name}, isLeft={isLeft}\n" + $" - footBone={key}, footRoot={((Object)transform1).name}\n" + $" - up(min,max)=({footMinUp:F4},{footMaxUp:F4})\n" + $" - forward(heel,toe)=({heelF:F4},{toeF:F4})\n" + $" - side(min,max)=({sideMin:F4},{sideMax:F4})\n" + $" - forwardDir={vector3_1}, rightDir={vector3_2}, upDir={vector3_3}"));
|
||||
}
|
||||
|
||||
static void DrawCross(
|
||||
Vector3 pos,
|
||||
Vector3 axisA,
|
||||
Vector3 axisB,
|
||||
Color color,
|
||||
float size,
|
||||
float d)
|
||||
{
|
||||
if ((double)((Vector3)ref axisA).sqrMagnitude < 1.000000013351432E-10)
|
||||
axisA = Vector3.up;
|
||||
if ((double)((Vector3)ref axisB).sqrMagnitude < 1.000000013351432E-10)
|
||||
axisB = Vector3.right;
|
||||
((Vector3)ref axisA).Normalize();
|
||||
((Vector3)ref axisB).Normalize();
|
||||
Debug.DrawLine(Vector3.op_Subtraction(pos, Vector3.op_Multiply(axisA, size)), Vector3.op_Addition(pos, Vector3.op_Multiply(axisA, size)), color, d);
|
||||
Debug.DrawLine(Vector3.op_Subtraction(pos, Vector3.op_Multiply(axisB, size)), Vector3.op_Addition(pos, Vector3.op_Multiply(axisB, size)), color, d);
|
||||
}
|
||||
|
||||
static void DrawAxisLine(Vector3 start, Vector3 dir, float len, Color color, float d)
|
||||
{
|
||||
if ((double)((Vector3)ref dir).sqrMagnitude < 1.000000013351432E-10)
|
||||
return;
|
||||
((Vector3)ref dir).Normalize();
|
||||
Debug.DrawLine(start, Vector3.op_Addition(start, Vector3.op_Multiply(dir, len)), color, d);
|
||||
}
|
||||
|
||||
static void DrawSegment(Vector3 p0, Vector3 p1, Color color, float d)
|
||||
{
|
||||
Debug.DrawLine(p0, p1, color, d);
|
||||
}
|
||||
|
||||
static void DrawBoxEdges(Vector3[] c, Color color, float d)
|
||||
{
|
||||
DrawSegment(c[0], c[1], color, d);
|
||||
DrawSegment(c[1], c[3], color, d);
|
||||
DrawSegment(c[3], c[2], color, d);
|
||||
DrawSegment(c[2], c[0], color, d);
|
||||
DrawSegment(c[4], c[5], color, d);
|
||||
DrawSegment(c[5], c[7], color, d);
|
||||
DrawSegment(c[7], c[6], color, d);
|
||||
DrawSegment(c[6], c[4], color, d);
|
||||
DrawSegment(c[0], c[4], color, d);
|
||||
DrawSegment(c[1], c[5], color, d);
|
||||
DrawSegment(c[2], c[6], color, d);
|
||||
DrawSegment(c[3], c[7], color, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7326179703ed48e489335a16b7d53a33
|
||||
@@ -0,0 +1,158 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BodyPoseMatch_Torso
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BodyPoseMatch_Torso
|
||||
{
|
||||
private readonly BodyPoseMatch_CommonUtil poseMatchCommonUtil;
|
||||
|
||||
public BodyPoseMatch_Torso() => this.poseMatchCommonUtil = new BodyPoseMatch_CommonUtil();
|
||||
|
||||
public void AlignTorsoByNeck(
|
||||
IReadOnlyCollection<Transform> sourceHipSet,
|
||||
Vector3 sourceNeckCenterWorld,
|
||||
Vector3 targetNeckCenterWorld)
|
||||
{
|
||||
Transform transform1 = sourceHipSet != null && sourceHipSet.Count != 0 ? sourceHipSet.FirstOrDefault<Transform>((Func<Transform, bool>)(t => Object.op_Inequality((Object)t, (Object)null))) : throw new AutoMorpherException("Source Hip Set is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - sourceHipSet is null or empty");
|
||||
if (Object.op_Equality((Object)transform1, (Object)null))
|
||||
throw new AutoMorpherException("Source Hip Transform is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - sourceHipSet has no valid Transform");
|
||||
Vector3 vector3_1 = Vector3.op_Subtraction(targetNeckCenterWorld, sourceNeckCenterWorld);
|
||||
Vector3 forward = transform1.forward;
|
||||
Vector3 vector3_2 = forward;
|
||||
float num = Vector3.Dot(vector3_1, vector3_2);
|
||||
Vector3 vector3_3 = Vector3.op_Multiply(forward, num);
|
||||
foreach (Transform sourceHip in (IEnumerable<Transform>)sourceHipSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)sourceHip, (Object)null))
|
||||
{
|
||||
Transform transform2 = sourceHip;
|
||||
transform2.position = Vector3.op_Addition(transform2.position, vector3_3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AlignTorsoByNeck(
|
||||
GameObject proxyObject,
|
||||
IReadOnlyList<BakedBodyMesh> proxyBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> proxyBoneMap,
|
||||
GameObject targetObject,
|
||||
IReadOnlyList<BakedBodyMesh> targetBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> targetBoneMap)
|
||||
{
|
||||
if (Object.op_Equality((Object)proxyObject, (Object)null) || Object.op_Equality((Object)targetObject, (Object)null))
|
||||
throw new AutoMorpherException("Proxy/Target Object is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - proxyObject or targetObject is null");
|
||||
RegionStats neckRegionStats1 = this.ComputeNeckRegionStats(proxyObject.transform, proxyBakedBodyMeshes, proxyBoneMap);
|
||||
RegionStats neckRegionStats2 = this.ComputeNeckRegionStats(targetObject.transform, targetBakedBodyMeshes, targetBoneMap);
|
||||
if ((double)neckRegionStats1.length < 9.9999997473787516E-05 || (double)neckRegionStats2.length < 9.9999997473787516E-05)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Torso] AlignTorsoByNeck: Neck PCA 통계가 비정상입니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
HashSet<Transform> sourceHipSet;
|
||||
if (proxyBoneMap == null || !proxyBoneMap.TryGetValue((HumanBodyBones)0, out sourceHipSet) || sourceHipSet == null || sourceHipSet.Count == 0)
|
||||
throw new AutoMorpherException("Proxy Hip Set is Missing", "[BodyPoseMatch_Torso] AlignTorsoByNeck\n - proxyBoneMap has no Hips bone set");
|
||||
this.AlignTorsoByNeck((IReadOnlyCollection<Transform>)sourceHipSet, neckRegionStats1.center, neckRegionStats2.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 (Object.op_Equality((Object)targetTransform, (Object)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 neckRegionStats = this.ComputeNeckRegionStats(targetTransform, targetBakedBodyMeshes, targetBoneMap);
|
||||
if ((double)neckRegionStats.length < 9.9999997473787516E-05)
|
||||
{
|
||||
Debug.LogWarning((object)"[BodyPoseMatch_Torso] AlignTorsoByNeck: Neck PCA 통계가 비정상입니다.");
|
||||
}
|
||||
else
|
||||
{
|
||||
HashSet<Transform> sourceHipSet;
|
||||
if (clothBoneMap == null || !clothBoneMap.TryGetValue((HumanBodyBones)0, out sourceHipSet) || sourceHipSet == null || sourceHipSet.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((IReadOnlyCollection<Transform>)sourceHipSet, profilePcaCenterWorld, neckRegionStats.center);
|
||||
}
|
||||
}
|
||||
|
||||
public RegionStats ComputeNeckRegionStats(
|
||||
Transform avatarTransform,
|
||||
IReadOnlyList<BakedBodyMesh> avatarBakedBodyMeshes,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> avatarBoneMap)
|
||||
{
|
||||
List<Vector3> points = this.poseMatchCommonUtil.CollectHumanoidVerticesWorld((IReadOnlyList<HumanBodyBones>)new HumanBodyBones[1]
|
||||
{
|
||||
(HumanBodyBones) 9
|
||||
}, avatarBakedBodyMeshes, avatarBoneMap);
|
||||
if (points == null || points.Count == 0)
|
||||
{
|
||||
Debug.LogWarning((object)("[AvatarBodyMatchUtil] ComputeNeckRegionStats: neck vertices 0개. avatar=" + ((Object)avatarTransform)?.name));
|
||||
return new RegionStats();
|
||||
}
|
||||
RegionStats regionStats = new PcaUtil().ComputeRegionStats((IList<Vector3>)points);
|
||||
Vector3 vector3 = avatarTransform.up;
|
||||
Transform boneFromBoneMap1 = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, (HumanBodyBones)10);
|
||||
Transform boneFromBoneMap2 = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, (HumanBodyBones)54);
|
||||
Transform boneFromBoneMap3 = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, (HumanBodyBones)8);
|
||||
Transform boneFromBoneMap4 = this.poseMatchCommonUtil.GetBoneFromBoneMap(avatarBoneMap, (HumanBodyBones)0);
|
||||
Transform transform = Object.op_Inequality((Object)boneFromBoneMap2, (Object)null) ? boneFromBoneMap2 : boneFromBoneMap3;
|
||||
if (Object.op_Inequality((Object)boneFromBoneMap1, (Object)null) && Object.op_Inequality((Object)transform, (Object)null))
|
||||
vector3 = Vector3.op_Subtraction(boneFromBoneMap1.position, transform.position);
|
||||
else if (Object.op_Inequality((Object)boneFromBoneMap1, (Object)null) && Object.op_Inequality((Object)boneFromBoneMap4, (Object)null))
|
||||
vector3 = Vector3.op_Subtraction(boneFromBoneMap1.position, boneFromBoneMap4.position);
|
||||
if ((double)((Vector3)ref vector3).sqrMagnitude > 9.99999993922529E-09)
|
||||
((Vector3)ref vector3).Normalize();
|
||||
if ((double)Vector3.Dot(vector3, ((Component)avatarTransform).transform.up) < 0.0)
|
||||
vector3 = Vector3.op_UnaryNegation(vector3);
|
||||
regionStats.principalAxis = vector3;
|
||||
return regionStats;
|
||||
}
|
||||
|
||||
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 (Object.op_Equality((Object)avatarObject, (Object)null))
|
||||
return;
|
||||
RegionStats neckRegionStats = this.ComputeNeckRegionStats(avatarObject.transform, avatarBakedBodyMeshes, avatarBoneMap);
|
||||
if ((double)neckRegionStats.length < 9.9999997473787516E-05)
|
||||
{
|
||||
Debug.LogWarning((object)$"[AvatarBodyMatchUtil] DrawNeckPcaDebug: neck.length가 너무 작음. avatar={((Object)avatarObject).name}, length={neckRegionStats.length}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 center = neckRegionStats.center;
|
||||
Vector3 normalized = ((Vector3)ref neckRegionStats.principalAxis).normalized;
|
||||
float num1 = 0.02f * axisScale;
|
||||
Debug.DrawLine(Vector3.op_Addition(center, Vector3.op_Multiply(Vector3.up, num1)), Vector3.op_Subtraction(center, Vector3.op_Multiply(Vector3.up, num1)), centerColor, duration);
|
||||
Debug.DrawLine(Vector3.op_Addition(center, Vector3.op_Multiply(Vector3.right, num1)), Vector3.op_Subtraction(center, Vector3.op_Multiply(Vector3.right, num1)), centerColor, duration);
|
||||
float num2 = neckRegionStats.length * 0.5f * axisScale;
|
||||
Debug.DrawLine(center, Vector3.op_Addition(center, Vector3.op_Multiply(normalized, num2)), axisColor, duration);
|
||||
Debug.Log((object)$"[AvatarBodyMatchUtil] DrawNeckPcaDebug: avatar={((Object)avatarObject).name}, center={center}, axis={normalized}, halfLen={num2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d84554c6dcbe7b42b908fabb48c3d66
|
||||
@@ -0,0 +1,208 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BodyPoseToClothApplier
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BodyPoseToClothApplier
|
||||
{
|
||||
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 (Object.op_Equality((Object)bodyProxyRoot, (Object)null))
|
||||
throw new AutoMorpherException("Body Proxy Root is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - bodyProxyRoot is null");
|
||||
if (Object.op_Equality((Object)clothesRoot, (Object)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 = ((Component)bodyProxyRoot).GetComponent<Animator>();
|
||||
Transform transform = !Object.op_Equality((Object)component, (Object)null) ? ((Component)component).transform : throw new AutoMorpherException("Body Proxy Animator is Missing", "[BodyToClothPoseApplier] ApplyDeformedProxyPoseToCloth\n - bodyProxyRoot has no Animator");
|
||||
Dictionary<Transform, int> proxyDepthMap = this.BuildDepthMap(transform);
|
||||
Dictionary<Transform, Transform> proxyToCloth = new Dictionary<Transform, Transform>();
|
||||
List<BodyPoseToClothApplier.BoneMapping> boneMappingList = new List<BodyPoseToClothApplier.BoneMapping>();
|
||||
HashSet<Transform> transformSet = new HashSet<Transform>();
|
||||
foreach (KeyValuePair<Transform, BoneMatchUtil.BoneRootLocalData> keyValuePair in clothToBodyMatched)
|
||||
{
|
||||
Transform key1 = keyValuePair.Key;
|
||||
BoneMatchUtil.BoneRootLocalData boneRootLocalData = keyValuePair.Value;
|
||||
if (!Object.op_Equality((Object)key1, (Object)null) && boneRootLocalData != null)
|
||||
{
|
||||
Transform t = boneRootLocalData.t;
|
||||
Transform key2;
|
||||
if (!Object.op_Equality((Object)t, (Object)null) && sourceToProxy.TryGetValue(t, out key2) && !Object.op_Equality((Object)key2, (Object)null))
|
||||
{
|
||||
HumanBodyBones hBone = boneRootLocalData.hBone;
|
||||
if (transformSet.Add(key1))
|
||||
{
|
||||
int num1 = 999;
|
||||
int num2;
|
||||
if (proxyDepthMap != null && proxyDepthMap.TryGetValue(key2, out num2))
|
||||
num1 = num2;
|
||||
boneMappingList.Add(new BodyPoseToClothApplier.BoneMapping()
|
||||
{
|
||||
proxyBone = key2,
|
||||
clothBone = key1,
|
||||
depth = num1,
|
||||
humanBone = hBone != 55 ? new HumanBodyBones?(hBone) : new HumanBodyBones?()
|
||||
});
|
||||
}
|
||||
if (!proxyToCloth.ContainsKey(key2))
|
||||
proxyToCloth.Add(key2, key1);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.MirrorBoneMarkers(transform, proxyToCloth, proxyDepthMap, boneMappingList);
|
||||
foreach (BodyPoseToClothApplier.BoneMapping boneMapping in boneMappingList.Where<BodyPoseToClothApplier.BoneMapping>((Func<BodyPoseToClothApplier.BoneMapping, bool>)(m => m != null && Object.op_Inequality((Object)m.proxyBone, (Object)null) && Object.op_Inequality((Object)m.clothBone, (Object)null))).OrderBy<BodyPoseToClothApplier.BoneMapping, int>((Func<BodyPoseToClothApplier.BoneMapping, int>)(m => m.depth)).ToList<BodyPoseToClothApplier.BoneMapping>())
|
||||
{
|
||||
if (!Object.op_Equality((Object)boneMapping.proxyBone, (Object)null) && !Object.op_Equality((Object)boneMapping.clothBone, (Object)null))
|
||||
{
|
||||
if (copyPosition)
|
||||
boneMapping.clothBone.position = boneMapping.proxyBone.position;
|
||||
if (copyRotation)
|
||||
boneMapping.clothBone.rotation = boneMapping.proxyBone.rotation;
|
||||
if (copyScale)
|
||||
boneMapping.clothBone.localScale = boneMapping.proxyBone.localScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<Transform, int> BuildDepthMap(Transform root)
|
||||
{
|
||||
Dictionary<Transform, int> dictionary = new Dictionary<Transform, int>();
|
||||
if (Object.op_Equality((Object)root, (Object)null))
|
||||
return dictionary;
|
||||
foreach (Transform componentsInChild in ((Component)root).GetComponentsInChildren<Transform>(true))
|
||||
{
|
||||
if (!Object.op_Equality((Object)componentsInChild, (Object)null))
|
||||
dictionary[componentsInChild] = this.GetDepthFromRoot(componentsInChild, root);
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
private int GetDepthFromRoot(Transform t, Transform root)
|
||||
{
|
||||
int depthFromRoot = 0;
|
||||
for (Transform transform = t; Object.op_Inequality((Object)transform, (Object)null) && Object.op_Inequality((Object)transform, (Object)root); transform = transform.parent)
|
||||
++depthFromRoot;
|
||||
return depthFromRoot;
|
||||
}
|
||||
|
||||
private void MirrorBoneMarkers(
|
||||
Transform proxyArmature,
|
||||
Dictionary<Transform, Transform> proxyToCloth,
|
||||
Dictionary<Transform, int> proxyDepthMap,
|
||||
List<BodyPoseToClothApplier.BoneMapping> mappings)
|
||||
{
|
||||
if (Object.op_Equality((Object)proxyArmature, (Object)null) || proxyToCloth == null || mappings == null)
|
||||
return;
|
||||
TempBoneMarker[] componentsInChildren = ((Component)proxyArmature).GetComponentsInChildren<TempBoneMarker>(true);
|
||||
if (componentsInChildren == null || componentsInChildren.Length == 0)
|
||||
return;
|
||||
HashSet<Transform> transformSet = new HashSet<Transform>();
|
||||
for (int index = 0; index < mappings.Count; ++index)
|
||||
{
|
||||
BodyPoseToClothApplier.BoneMapping mapping = mappings[index];
|
||||
if (mapping != null && Object.op_Inequality((Object)mapping.proxyBone, (Object)null))
|
||||
transformSet.Add(mapping.proxyBone);
|
||||
}
|
||||
int num1;
|
||||
foreach (TempBoneMarker tempBoneMarker1 in ((IEnumerable<TempBoneMarker>)componentsInChildren).Where<TempBoneMarker>((Func<TempBoneMarker, bool>)(bm => Object.op_Inequality((Object)bm, (Object)null) && Object.op_Inequality((Object)((Component)bm).transform, (Object)null))).OrderBy<TempBoneMarker, int>((Func<TempBoneMarker, int>)(bm => proxyDepthMap != null && proxyDepthMap.TryGetValue(((Component)bm).transform, out num1) ? num1 : int.MaxValue)).ToList<TempBoneMarker>())
|
||||
{
|
||||
Transform transform1 = ((Component)tempBoneMarker1).transform;
|
||||
if (!Object.op_Equality((Object)transform1, (Object)null))
|
||||
{
|
||||
Transform originalParent = tempBoneMarker1.originalParent;
|
||||
Transform transform2;
|
||||
if (!Object.op_Equality((Object)originalParent, (Object)null) && proxyToCloth.TryGetValue(originalParent, out transform2) && !Object.op_Equality((Object)transform2, (Object)null))
|
||||
{
|
||||
List<Transform> transformList = this.CollectDirectChilds(transform2);
|
||||
Transform transform3 = this.FindMarkerInChild(transform2);
|
||||
TempBoneMarker tempBoneMarker2;
|
||||
if (Object.op_Equality((Object)transform3, (Object)null))
|
||||
{
|
||||
transform3 = new GameObject(((Object)transform1).name).transform;
|
||||
transform3.SetParent(transform2, true);
|
||||
tempBoneMarker2 = ((Component)transform3).gameObject.AddComponent<TempBoneMarker>();
|
||||
}
|
||||
else
|
||||
tempBoneMarker2 = ((Component)transform3).GetComponent<TempBoneMarker>();
|
||||
transform3.position = transform1.position;
|
||||
transform3.rotation = transform1.rotation;
|
||||
transform3.localScale = transform1.localScale;
|
||||
tempBoneMarker2.originalParent = transform2;
|
||||
tempBoneMarker2.additionalInfo = tempBoneMarker1.additionalInfo;
|
||||
tempBoneMarker2.wrappedChildNames = tempBoneMarker1.wrappedChildNames;
|
||||
for (int index = 0; index < transformList.Count; ++index)
|
||||
{
|
||||
Transform transform4 = transformList[index];
|
||||
if (!Object.op_Equality((Object)transform4, (Object)null) && !Object.op_Equality((Object)transform4, (Object)transform3))
|
||||
transform4.SetParent(transform3, true);
|
||||
}
|
||||
if (!proxyToCloth.ContainsKey(transform1))
|
||||
proxyToCloth.Add(transform1, transform3);
|
||||
if (transformSet.Add(transform1))
|
||||
{
|
||||
int num2 = 999;
|
||||
int num3;
|
||||
if (proxyDepthMap != null && proxyDepthMap.TryGetValue(transform1, out num3))
|
||||
num2 = num3;
|
||||
mappings.Add(new BodyPoseToClothApplier.BoneMapping()
|
||||
{
|
||||
proxyBone = transform1,
|
||||
clothBone = transform3,
|
||||
depth = num2,
|
||||
humanBone = new HumanBodyBones?()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Transform FindMarkerInChild(Transform parent)
|
||||
{
|
||||
if (Object.op_Equality((Object)parent, (Object)null))
|
||||
return (Transform)null;
|
||||
for (int index = 0; index < parent.childCount; ++index)
|
||||
{
|
||||
Transform child = parent.GetChild(index);
|
||||
if (!Object.op_Equality((Object)child, (Object)null) && Object.op_Inequality((Object)((Component)child).GetComponent<TempBoneMarker>(), (Object)null))
|
||||
return child;
|
||||
}
|
||||
return (Transform)null;
|
||||
}
|
||||
|
||||
private List<Transform> CollectDirectChilds(Transform parentTransform)
|
||||
{
|
||||
int childCount = parentTransform.childCount;
|
||||
List<Transform> transformList = new List<Transform>(childCount);
|
||||
for (int index = 0; index < childCount; ++index)
|
||||
transformList.Add(parentTransform.GetChild(index));
|
||||
return transformList;
|
||||
}
|
||||
|
||||
private class BoneMapping
|
||||
{
|
||||
public Transform proxyBone;
|
||||
public Transform clothBone;
|
||||
public int depth;
|
||||
public HumanBodyBones? humanBone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 95106b6438eaf82418391056865c4a34
|
||||
143
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs
Normal file
143
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BoneAlignmentUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BoneAlignmentUtil
|
||||
{
|
||||
public void AlignClothBonesToAvatar(ClothInstance cloth, Animator targetAvatarAnimator)
|
||||
{
|
||||
if (cloth == null || Object.op_Equality((Object)targetAvatarAnimator, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[BoneAlignmentUtil] cloth 또는 targetAvatarAnimator 가 null.");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> humanoidMatchedBone in cloth.humanoidMatchedBones)
|
||||
{
|
||||
HumanBodyBones key = humanoidMatchedBone.Key;
|
||||
foreach (Transform transform in humanoidMatchedBone.Value)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform, (Object)null))
|
||||
{
|
||||
Transform boneTransform = targetAvatarAnimator.GetBoneTransform(key);
|
||||
if (!Object.op_Equality((Object)boneTransform, (Object)null))
|
||||
{
|
||||
transform.position = boneTransform.position;
|
||||
transform.localScale = Vector3.one;
|
||||
((Object)transform).name = ((Object)boneTransform).name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ReparentAccessoryBonesToAvatar(EdenAutoMorpherConfig config)
|
||||
{
|
||||
if (config.clothBoneTypeMap == null || Object.op_Equality((Object)config.targetAvatarObject, (Object)null))
|
||||
return;
|
||||
Animator component = config.targetAvatarObject.GetComponent<Animator>();
|
||||
if (Object.op_Equality((Object)component, (Object)null) || !component.isHuman)
|
||||
return;
|
||||
Dictionary<Transform, Transform> dictionary = new Dictionary<Transform, Transform>();
|
||||
if (config.clothesHumanoidMatchedBones != null)
|
||||
{
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> humanoidMatchedBone in config.clothesHumanoidMatchedBones)
|
||||
{
|
||||
HumanBodyBones key1 = humanoidMatchedBone.Key;
|
||||
foreach (Transform key2 in humanoidMatchedBone.Value)
|
||||
{
|
||||
Transform boneTransform = component.GetBoneTransform(key1);
|
||||
if (Object.op_Inequality((Object)key2, (Object)null) && Object.op_Inequality((Object)boneTransform, (Object)null))
|
||||
dictionary[key2] = boneTransform;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<Transform, ClothBoneType> clothBoneType1 in config.clothBoneTypeMap)
|
||||
{
|
||||
if (clothBoneType1.Value == ClothBoneType.Accessory)
|
||||
{
|
||||
Transform key3 = clothBoneType1.Key;
|
||||
if (!Object.op_Equality((Object)key3, (Object)null) && key3.IsChildOf(config.targetClothesObject.transform))
|
||||
{
|
||||
Transform parent = key3.parent;
|
||||
Transform key4 = (Transform)null;
|
||||
for (; Object.op_Inequality((Object)parent, (Object)null); parent = parent.parent)
|
||||
{
|
||||
ClothBoneType clothBoneType2;
|
||||
if (config.clothBoneTypeMap.TryGetValue(parent, out clothBoneType2) && clothBoneType2 == ClothBoneType.Body)
|
||||
{
|
||||
key4 = parent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Transform transform;
|
||||
if (!Object.op_Equality((Object)key4, (Object)null) && dictionary.TryGetValue(key4, out transform))
|
||||
key3.SetParent(transform, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<Transform, Transform> keyValuePair in dictionary)
|
||||
{
|
||||
Transform key5 = keyValuePair.Key;
|
||||
Transform transform1 = keyValuePair.Value;
|
||||
if (!Object.op_Equality((Object)key5, (Object)null) && !Object.op_Equality((Object)transform1, (Object)null))
|
||||
{
|
||||
List<Transform> transformList = new List<Transform>();
|
||||
foreach (Transform transform2 in key5)
|
||||
transformList.Add(transform2);
|
||||
foreach (Transform key6 in transformList)
|
||||
{
|
||||
if (!Object.op_Equality((Object)key6, (Object)null) && !config.clothBoneTypeMap.ContainsKey(key6))
|
||||
key6.SetParent(transform1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CleanupTempBones(Transform root)
|
||||
{
|
||||
if (Object.op_Equality((Object)root, (Object)null))
|
||||
return;
|
||||
TempBoneMarker[] componentsInChildren = ((Component)root).GetComponentsInChildren<TempBoneMarker>(true);
|
||||
if (componentsInChildren == null || componentsInChildren.Length == 0)
|
||||
return;
|
||||
foreach (TempBoneMarker tempBoneMarker in ((IEnumerable<TempBoneMarker>)componentsInChildren).Where<TempBoneMarker>((Func<TempBoneMarker, bool>)(m => Object.op_Inequality((Object)m, (Object)null))).OrderByDescending<TempBoneMarker, int>((Func<TempBoneMarker, int>)(m => GetDepth(((Component)m).transform))).ToArray<TempBoneMarker>())
|
||||
{
|
||||
if (!Object.op_Equality((Object)tempBoneMarker, (Object)null))
|
||||
{
|
||||
Transform transform1 = ((Component)tempBoneMarker).transform;
|
||||
Transform transform2 = tempBoneMarker.originalParent;
|
||||
if (Object.op_Equality((Object)transform2, (Object)null))
|
||||
transform2 = transform1.parent;
|
||||
if (Object.op_Inequality((Object)transform2, (Object)null))
|
||||
{
|
||||
while (transform1.childCount > 0)
|
||||
transform1.GetChild(0).SetParent(transform2, true);
|
||||
}
|
||||
if (!Application.isPlaying)
|
||||
Object.DestroyImmediate((Object)((Component)transform1).gameObject);
|
||||
else
|
||||
Object.Destroy((Object)((Component)transform1).gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
static int GetDepth(Transform t)
|
||||
{
|
||||
int depth = 0;
|
||||
for (; Object.op_Inequality((Object)t, (Object)null); t = t.parent)
|
||||
++depth;
|
||||
return depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51afb8fce54e96444b9da90ac17f1983
|
||||
@@ -0,0 +1,158 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BoneCorrespondenceUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BoneCorrespondenceUtil
|
||||
{
|
||||
private char[] nameDelims = new char[8]
|
||||
{
|
||||
' ',
|
||||
'-',
|
||||
'_',
|
||||
':',
|
||||
'.',
|
||||
'|',
|
||||
'\\',
|
||||
'/'
|
||||
};
|
||||
|
||||
public float ComputeDistanceScore(float d, float near, float mid, float far)
|
||||
{
|
||||
if ((double)d < (double)near)
|
||||
return 120f;
|
||||
if ((double)d < (double)mid)
|
||||
return 90f;
|
||||
return (double)d < (double)far ? 50f : 0.0f;
|
||||
}
|
||||
|
||||
public float ComputeRotationScore(float ang, float RotTolDeg)
|
||||
{
|
||||
return Mathf.Clamp01((float)(1.0 - (double)ang / (double)RotTolDeg));
|
||||
}
|
||||
|
||||
public float ComputeNameScore(
|
||||
string bodyName,
|
||||
string bodyPath,
|
||||
string clothesName,
|
||||
string clothesPath)
|
||||
{
|
||||
string str1 = this.StripDigits(this.NormalizeName(bodyName));
|
||||
string str2 = this.StripDigits(this.NormalizeName(clothesName));
|
||||
string str3 = this.StripDigits(this.NormalizePath(bodyPath));
|
||||
string str4 = this.StripDigits(this.NormalizePath(clothesPath));
|
||||
if (!string.IsNullOrEmpty(str3) && str3 == str4)
|
||||
return 80f;
|
||||
if (!string.IsNullOrEmpty(str1) && str1 == str2)
|
||||
return 70f;
|
||||
return !string.IsNullOrEmpty(str1) && !string.IsNullOrEmpty(str2) && (str1.Contains(str2) || str2.Contains(str1)) ? 40f : this.SubsequenceCoverage(bodyName, clothesName) * 10f;
|
||||
}
|
||||
|
||||
private float SubsequenceCoverage(string bodyRaw, string clothesRaw)
|
||||
{
|
||||
string a = this.StripDigits(this.NormalizeName(bodyRaw));
|
||||
string b = this.StripDigits(this.NormalizeName(clothesRaw));
|
||||
return string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b) ? 0.0f : (float)this.SubNameMatchBest(a, b) / (float)a.Length;
|
||||
}
|
||||
|
||||
private int SubNameMatchBest(string a, string b, int minMatchCount = 3)
|
||||
{
|
||||
if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b) || a.Length < minMatchCount || b.Length < minMatchCount)
|
||||
return 0;
|
||||
int num1 = 0;
|
||||
for (int startA = 0; startA <= a.Length - minMatchCount; ++startA)
|
||||
{
|
||||
int num2 = this.SubNameMatch(a, startA, b, minMatchCount);
|
||||
if (num2 > num1)
|
||||
num1 = num2;
|
||||
}
|
||||
return num1;
|
||||
}
|
||||
|
||||
private int SubNameMatch(string a, int startA, string b, int minMatchCount = 3)
|
||||
{
|
||||
int length1 = a.Length;
|
||||
int length2 = b.Length;
|
||||
int num1 = 0;
|
||||
int num2 = 0;
|
||||
int num3 = 0;
|
||||
int num4 = 0;
|
||||
for (int index1 = startA; index1 < length1; ++index1)
|
||||
{
|
||||
for (int index2 = num3; index2 < length2; ++index2)
|
||||
{
|
||||
num3 = index2 + 1;
|
||||
if ((int)a[index1] == (int)b[index2])
|
||||
{
|
||||
num4 = index1 + 1;
|
||||
++num2;
|
||||
if (num2 > num1)
|
||||
{
|
||||
num1 = num2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (num2 > num1)
|
||||
num1 = num2;
|
||||
num2 = 0;
|
||||
}
|
||||
if (num3 >= length2)
|
||||
break;
|
||||
}
|
||||
if (num2 > num1)
|
||||
num1 = num2;
|
||||
return num1 < minMatchCount ? 0 : num4 - startA;
|
||||
}
|
||||
|
||||
public string GetHierarchyPath(Transform root, Transform t)
|
||||
{
|
||||
if (Object.op_Equality((Object)t, (Object)null))
|
||||
return "";
|
||||
Stack<string> values = new Stack<string>();
|
||||
for (Transform transform = t; Object.op_Inequality((Object)transform, (Object)null) && Object.op_Inequality((Object)transform, (Object)root); transform = transform.parent)
|
||||
values.Push(((Object)transform).name);
|
||||
return string.Join("/", (IEnumerable<string>)values);
|
||||
}
|
||||
|
||||
public string NormalizeName(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
return "";
|
||||
s = s.ToLowerInvariant();
|
||||
s = s.Replace("left", "l").Replace("right", "r");
|
||||
foreach (char nameDelim in this.nameDelims)
|
||||
s = s.Replace(nameDelim.ToString(), "");
|
||||
s = this.StripDigits(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
public string NormalizePath(string p)
|
||||
{
|
||||
return string.IsNullOrEmpty(p) ? "" : string.Join("/", ((IEnumerable<string>)p.Split('/', StringSplitOptions.None)).Where<string>((Func<string, bool>)(x => !string.IsNullOrEmpty(x))).Select<string, string>(new Func<string, string>(this.NormalizeName)));
|
||||
}
|
||||
|
||||
public string StripDigits(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
return "";
|
||||
StringBuilder stringBuilder = new StringBuilder(s.Length);
|
||||
for (int index = 0; index < s.Length; ++index)
|
||||
{
|
||||
char c = s[index];
|
||||
if (!char.IsDigit(c))
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e62c972f6f7fb242aaf2e7182fc85bb
|
||||
516
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs
Normal file
516
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs
Normal file
@@ -0,0 +1,516 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BoneMatchUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\git\Spy\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BoneMatchUtil
|
||||
{
|
||||
private const float PosTolNear = 0.0001f;
|
||||
private const float PosTolMid = 0.0005f;
|
||||
private const float PosTolFar = 0.002f;
|
||||
private const float RotTolDeg = 30f;
|
||||
private const float eps = 1E-06f;
|
||||
|
||||
public List<BoneMatchUtil.BoneRootLocalData> ConvertProfileBoneDataToRootLocalData(
|
||||
List<BoneData> boneDataList)
|
||||
{
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalData = boneDataList != null && boneDataList.Count != 0 ? new List<BoneMatchUtil.BoneRootLocalData>(boneDataList.Count) : throw new AutoMorpherException("Profile Bone Data is Missing", "[BoneMatchUtil] ConvertProfileBoneDataToRootLocalData\n - boneDataList is null or empty");
|
||||
foreach (BoneData boneData in boneDataList)
|
||||
{
|
||||
if (boneData != null)
|
||||
{
|
||||
BoneMatchUtil.BoneRootLocalData boneRootLocalData = new BoneMatchUtil.BoneRootLocalData()
|
||||
{
|
||||
t = (Transform)null,
|
||||
name = boneData.boneName ?? string.Empty,
|
||||
path = boneData.hierarchyPath ?? string.Empty,
|
||||
rootLocalPos = boneData.rootLocalPosition,
|
||||
rootLocalRot = boneData.rootLocalRotation,
|
||||
hBone = boneData.hBone
|
||||
};
|
||||
rootLocalData.Add(boneRootLocalData);
|
||||
}
|
||||
}
|
||||
return rootLocalData;
|
||||
}
|
||||
|
||||
public HashSet<Transform> GetMeshBones(List<SkinnedMeshRenderer> meshRenderers)
|
||||
{
|
||||
HashSet<Transform> meshBones = new HashSet<Transform>();
|
||||
if (meshRenderers != null)
|
||||
{
|
||||
foreach (SkinnedMeshRenderer meshRenderer in meshRenderers)
|
||||
{
|
||||
if (!Object.op_Equality((Object)meshRenderer, (Object)null) && meshRenderer.bones != null)
|
||||
{
|
||||
foreach (Transform bone in meshRenderer.bones)
|
||||
{
|
||||
if (Object.op_Inequality((Object)bone, (Object)null))
|
||||
meshBones.Add(bone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return meshBones;
|
||||
}
|
||||
|
||||
public List<BoneMatchUtil.BoneRootLocalData> GetRootLocalBones(
|
||||
Transform rootT,
|
||||
HashSet<Transform> boneList)
|
||||
{
|
||||
BoneCorrespondenceUtil correspondenceUtil = new BoneCorrespondenceUtil();
|
||||
return boneList.Where<Transform>((Func<Transform, bool>)(t => Object.op_Inequality((Object)t, (Object)null))).Distinct<Transform>().Select<Transform, BoneMatchUtil.BoneRootLocalData>((Func<Transform, BoneMatchUtil.BoneRootLocalData>)(t => new BoneMatchUtil.BoneRootLocalData()
|
||||
{
|
||||
t = t,
|
||||
name = ((Object)t).name,
|
||||
path = correspondenceUtil.GetHierarchyPath(rootT, t),
|
||||
rootLocalPos = rootT.InverseTransformPoint(t.position),
|
||||
rootLocalRot = Quaternion.op_Multiply(Quaternion.Inverse(rootT.rotation), t.rotation)
|
||||
})).ToList<BoneMatchUtil.BoneRootLocalData>();
|
||||
}
|
||||
|
||||
public List<BoneMatchUtil.BoneRootLocalData> GetBodyRootLocalBones(
|
||||
Transform bodyTransform,
|
||||
Animator bodyAnimator,
|
||||
List<SkinnedMeshRenderer> bodyMeshes)
|
||||
{
|
||||
if (Object.op_Equality((Object)bodyTransform, (Object)null))
|
||||
throw new AutoMorpherException("Body Transform is Missing", "[BoneMatchUtil] GetBodyRootLocalBones\n - bodyTransform is null");
|
||||
Dictionary<Transform, HumanBodyBones> dictionary1 = !Object.op_Equality((Object)bodyAnimator, (Object)null) ? this.GetHumanoidBoneList(bodyAnimator) : throw new AutoMorpherException("Body Animator is Missing", "[BoneMatchUtil] GetBodyRootLocalBones\n - animator is null");
|
||||
if (dictionary1 == null || dictionary1.Count == 0)
|
||||
throw new AutoMorpherException("Humanoid Bone Map is Missing", "[BoneMatchUtil] GetBodyRootLocalBones\n - Can't find Humanoid Bone List");
|
||||
HashSet<Transform> transformSet1 = bodyMeshes != null && bodyMeshes.Count != 0 ? this.GetMeshBones(bodyMeshes) : throw new AutoMorpherException("Body Meshes are Missing", "[BoneMatchUtil] GetBodyRootLocalBones\n - bodyMeshes is null or empty");
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary2 = new MeshClassifier().MeshHumanoidBoneMatcher(bodyAnimator, (IReadOnlyList<SkinnedMeshRenderer>)bodyMeshes);
|
||||
HashSet<Transform> boneList = new HashSet<Transform>();
|
||||
HashSet<Transform> transformSet2 = new HashSet<Transform>();
|
||||
foreach (KeyValuePair<Transform, HumanBodyBones> keyValuePair in dictionary1)
|
||||
{
|
||||
if (keyValuePair.Value != 55 && !Object.op_Equality((Object)keyValuePair.Key, (Object)null))
|
||||
{
|
||||
HashSet<Transform> transformSet3;
|
||||
if (!dictionary2.TryGetValue(keyValuePair.Value, out transformSet3) || transformSet3 == null)
|
||||
{
|
||||
transformSet3 = new HashSet<Transform>();
|
||||
dictionary2[keyValuePair.Value] = transformSet3;
|
||||
}
|
||||
transformSet3.Add(keyValuePair.Key);
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> keyValuePair in dictionary2)
|
||||
{
|
||||
HumanBodyBones key = keyValuePair.Key;
|
||||
if (key != 55)
|
||||
{
|
||||
HashSet<Transform> source = keyValuePair.Value;
|
||||
if (source != null && source.Count != 0)
|
||||
{
|
||||
Transform transform1 = bodyAnimator.GetBoneTransform(key);
|
||||
if (Object.op_Equality((Object)transform1, (Object)null))
|
||||
transform1 = source.First<Transform>();
|
||||
if (!Object.op_Equality((Object)transform1, (Object)null))
|
||||
{
|
||||
boneList.Add(transform1);
|
||||
foreach (Transform transform2 in source)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform2, (Object)transform1) && !Object.op_Equality((Object)transform2, (Object)null))
|
||||
transformSet2.Add(transform2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Transform transform in transformSet1)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform, (Object)null) && !transformSet2.Contains(transform))
|
||||
boneList.Add(transform);
|
||||
}
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalBones = this.GetRootLocalBones(bodyTransform, boneList);
|
||||
foreach (BoneMatchUtil.BoneRootLocalData boneRootLocalData in rootLocalBones)
|
||||
{
|
||||
if (boneRootLocalData != null && !Object.op_Equality((Object)boneRootLocalData.t, (Object)null))
|
||||
{
|
||||
HumanBodyBones humanBodyBones;
|
||||
boneRootLocalData.hBone = !dictionary1.TryGetValue(boneRootLocalData.t, out humanBodyBones) ? (HumanBodyBones)55 : humanBodyBones;
|
||||
}
|
||||
}
|
||||
return rootLocalBones;
|
||||
}
|
||||
|
||||
private Dictionary<Transform, HumanBodyBones> GetHumanoidBoneList(Animator bodyAnimator)
|
||||
{
|
||||
Dictionary<Transform, HumanBodyBones> humanoidBoneList = new Dictionary<Transform, HumanBodyBones>();
|
||||
if (Object.op_Equality((Object)bodyAnimator, (Object)null) || Object.op_Equality((Object)bodyAnimator.avatar, (Object)null) || !bodyAnimator.avatar.isHuman)
|
||||
return humanoidBoneList;
|
||||
foreach (HumanBodyBones humanBodyBones in Enum.GetValues(typeof(HumanBodyBones)))
|
||||
{
|
||||
if (humanBodyBones != 55)
|
||||
{
|
||||
Transform boneTransform = bodyAnimator.GetBoneTransform(humanBodyBones);
|
||||
if (!Object.op_Equality((Object)boneTransform, (Object)null))
|
||||
humanoidBoneList.TryAdd(boneTransform, humanBodyBones);
|
||||
}
|
||||
}
|
||||
return humanoidBoneList;
|
||||
}
|
||||
|
||||
public void MatchClothesToBodyBones(
|
||||
List<BoneMatchUtil.BoneRootLocalData> bodyBones,
|
||||
List<BoneMatchUtil.BoneRootLocalData> clothesBones,
|
||||
out Dictionary<HumanBodyBones, HashSet<Transform>> clothHumanBones,
|
||||
out Dictionary<Transform, ClothBoneType> clothBoneTypeMap,
|
||||
out Dictionary<Transform, BoneMatchUtil.BoneRootLocalData> clothToBodyMatched)
|
||||
{
|
||||
clothHumanBones = new Dictionary<HumanBodyBones, HashSet<Transform>>();
|
||||
clothBoneTypeMap = new Dictionary<Transform, ClothBoneType>();
|
||||
clothToBodyMatched = new Dictionary<Transform, BoneMatchUtil.BoneRootLocalData>();
|
||||
if (bodyBones == null || bodyBones.Count == 0)
|
||||
throw new AutoMorpherException("Body Bones are Missing", "[BoneMatchUtil] MatchClothesToBodyBones\n - bodyBones is null or empty");
|
||||
if (clothesBones == null || clothesBones.Count == 0)
|
||||
throw new AutoMorpherException("Clothes Bones are Missing", "[BoneMatchUtil] MatchClothesToBodyBones\n - clothesBones is null or empty");
|
||||
List<(BoneMatchUtil.BoneRootLocalData, BoneMatchUtil.BoneRootLocalData, float, float, float, float, float)> source1 = new List<(BoneMatchUtil.BoneRootLocalData, BoneMatchUtil.BoneRootLocalData, float, float, float, float, float)>();
|
||||
BoneCorrespondenceUtil correspondenceUtil = new BoneCorrespondenceUtil();
|
||||
foreach (BoneMatchUtil.BoneRootLocalData clothesBone in clothesBones)
|
||||
{
|
||||
BoneMatchUtil.BoneRootLocalData boneRootLocalData = (BoneMatchUtil.BoneRootLocalData)null;
|
||||
float bestDistScore = float.NegativeInfinity;
|
||||
float bestRotScore = float.NegativeInfinity;
|
||||
float bestNameScore = float.NegativeInfinity;
|
||||
float bestD = float.PositiveInfinity;
|
||||
float bestAng = float.PositiveInfinity;
|
||||
foreach (BoneMatchUtil.BoneRootLocalData bodyBone in bodyBones)
|
||||
{
|
||||
float num1 = Vector3.Distance(clothesBone.rootLocalPos, bodyBone.rootLocalPos);
|
||||
float distanceScore = correspondenceUtil.ComputeDistanceScore(num1, 0.0001f, 0.0005f, 1f / 500f);
|
||||
if ((double)distanceScore != 0.0)
|
||||
{
|
||||
float nameScore = correspondenceUtil.ComputeNameScore(bodyBone.name, bodyBone.path, clothesBone.name, clothesBone.path);
|
||||
if ((double)nameScore != 0.0)
|
||||
{
|
||||
float num2 = Quaternion.Angle(bodyBone.rootLocalRot, clothesBone.rootLocalRot);
|
||||
float candRotScore = correspondenceUtil.ComputeRotationScore(num2, 30f) * 1f;
|
||||
if (this.IsBetterCandidate(distanceScore, bestDistScore, candRotScore, bestRotScore, nameScore, bestNameScore, num1, bestD, num2, bestAng))
|
||||
{
|
||||
boneRootLocalData = bodyBone;
|
||||
bestDistScore = distanceScore;
|
||||
bestRotScore = candRotScore;
|
||||
bestNameScore = nameScore;
|
||||
bestD = num1;
|
||||
bestAng = num2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (boneRootLocalData != null)
|
||||
source1.Add((clothesBone, boneRootLocalData, bestDistScore, bestRotScore, bestNameScore, bestD, bestAng));
|
||||
}
|
||||
Dictionary<Transform, BoneMatchUtil.BoneRootLocalData> dictionary = new Dictionary<Transform, BoneMatchUtil.BoneRootLocalData>();
|
||||
foreach (IGrouping<BoneMatchUtil.BoneRootLocalData, (BoneMatchUtil.BoneRootLocalData, BoneMatchUtil.BoneRootLocalData, float, float, float, float, float)> source2 in source1.GroupBy<(BoneMatchUtil.BoneRootLocalData, BoneMatchUtil.BoneRootLocalData, float, float, float, float, float), BoneMatchUtil.BoneRootLocalData>((Func<(BoneMatchUtil.BoneRootLocalData, BoneMatchUtil.BoneRootLocalData, float, float, float, float, float), BoneMatchUtil.BoneRootLocalData>)(x => x.body)))
|
||||
{
|
||||
if (source2.Key != null)
|
||||
{
|
||||
List<(BoneMatchUtil.BoneRootLocalData, BoneMatchUtil.BoneRootLocalData, float, float, float, float, float)> list = source2.ToList<(BoneMatchUtil.BoneRootLocalData, BoneMatchUtil.BoneRootLocalData, float, float, float, float, float)>();
|
||||
if (list.Count != 0)
|
||||
{
|
||||
(BoneMatchUtil.BoneRootLocalData, BoneMatchUtil.BoneRootLocalData, float, float, float, float, float) valueTuple = list[0];
|
||||
for (int index = 1; index < list.Count; ++index)
|
||||
{
|
||||
(BoneMatchUtil.BoneRootLocalData, BoneMatchUtil.BoneRootLocalData, float, float, float, float, float) tuple = list[index];
|
||||
if (this.IsBetterCandidate(tuple.Item3, valueTuple.Item3, tuple.Item4, valueTuple.Item4, tuple.Item5, valueTuple.Item5, tuple.Item6, valueTuple.Item6, tuple.Item7, valueTuple.Item7))
|
||||
valueTuple = tuple;
|
||||
}
|
||||
if (valueTuple.Item1 != null && Object.op_Inequality((Object)valueTuple.Item1.t, (Object)null) && valueTuple.Item2 != null)
|
||||
dictionary[valueTuple.Item1.t] = valueTuple.Item2;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (BoneMatchUtil.BoneRootLocalData clothesBone in clothesBones)
|
||||
{
|
||||
if (!Object.op_Equality((Object)clothesBone?.t, (Object)null))
|
||||
{
|
||||
BoneMatchUtil.BoneRootLocalData boneRootLocalData;
|
||||
if (dictionary.TryGetValue(clothesBone.t, out boneRootLocalData))
|
||||
{
|
||||
clothBoneTypeMap[clothesBone.t] = ClothBoneType.Body;
|
||||
clothToBodyMatched[clothesBone.t] = boneRootLocalData;
|
||||
HumanBodyBones hBone = boneRootLocalData.hBone;
|
||||
if (hBone != 55)
|
||||
{
|
||||
HashSet<Transform> transformSet;
|
||||
if (!clothHumanBones.TryGetValue(hBone, out transformSet))
|
||||
{
|
||||
transformSet = new HashSet<Transform>();
|
||||
clothHumanBones[hBone] = transformSet;
|
||||
}
|
||||
transformSet.Add(clothesBone.t);
|
||||
}
|
||||
}
|
||||
else
|
||||
clothBoneTypeMap[clothesBone.t] = ClothBoneType.Accessory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsBetterCandidate(
|
||||
float candDistScore,
|
||||
float bestDistScore,
|
||||
float candRotScore,
|
||||
float bestRotScore,
|
||||
float candNameScore,
|
||||
float bestNameScore,
|
||||
float candD,
|
||||
float bestD,
|
||||
float candAng,
|
||||
float bestAng)
|
||||
{
|
||||
if ((double)candDistScore > (double)bestDistScore)
|
||||
return true;
|
||||
if ((double)candDistScore < (double)bestDistScore)
|
||||
return false;
|
||||
if ((double)candNameScore > (double)bestNameScore)
|
||||
return true;
|
||||
if ((double)candNameScore < (double)bestNameScore)
|
||||
return false;
|
||||
if ((double)Mathf.Abs(candRotScore - bestRotScore) > 9.9999999747524271E-07)
|
||||
{
|
||||
if ((double)candRotScore > (double)bestRotScore)
|
||||
return true;
|
||||
if ((double)candRotScore < (double)bestRotScore)
|
||||
return false;
|
||||
}
|
||||
if ((double)Mathf.Abs(candD - bestD) > 9.9999999747524271E-07)
|
||||
{
|
||||
if ((double)candD < (double)bestD)
|
||||
return true;
|
||||
if ((double)candD > (double)bestD)
|
||||
return false;
|
||||
}
|
||||
if ((double)Mathf.Abs(candAng - bestAng) <= 9.9999999747524271E-07)
|
||||
return false;
|
||||
if ((double)candAng < (double)bestAng)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public Dictionary<Transform, Transform> BuildTransformMatchMap(
|
||||
List<BoneMatchUtil.BoneRootLocalData> sourceBones,
|
||||
List<BoneMatchUtil.BoneRootLocalData> destBones,
|
||||
bool resultReverse = false)
|
||||
{
|
||||
if (sourceBones == null || sourceBones.Count == 0)
|
||||
throw new AutoMorpherException("Source Bones are Missing", "[BoneMatchUtil] BuildTransformMatchMap\n - sourceBones is null or empty");
|
||||
if (destBones == null || destBones.Count == 0)
|
||||
throw new AutoMorpherException("Destination Bones are Missing", "[BoneMatchUtil] BuildTransformMatchMap\n - destBones is null or empty");
|
||||
BoneCorrespondenceUtil correspondenceUtil = new BoneCorrespondenceUtil();
|
||||
Dictionary<Transform, Transform> dictionary1 = new Dictionary<Transform, Transform>();
|
||||
Dictionary<string, BoneMatchUtil.BoneRootLocalData> dictionary2 = new Dictionary<string, BoneMatchUtil.BoneRootLocalData>();
|
||||
Dictionary<string, BoneMatchUtil.BoneRootLocalData> dictionary3 = new Dictionary<string, BoneMatchUtil.BoneRootLocalData>();
|
||||
Dictionary<string, List<BoneMatchUtil.BoneRootLocalData>> dictionary4 = new Dictionary<string, List<BoneMatchUtil.BoneRootLocalData>>();
|
||||
foreach (BoneMatchUtil.BoneRootLocalData destBone in destBones)
|
||||
{
|
||||
if (destBone != null && !Object.op_Equality((Object)destBone.t, (Object)null))
|
||||
{
|
||||
string str = destBone.path ?? "";
|
||||
if (str.Length > 0 && !dictionary2.ContainsKey(str))
|
||||
dictionary2.Add(str, destBone);
|
||||
if (str.Length > 0)
|
||||
{
|
||||
string key = correspondenceUtil.NormalizePath(str);
|
||||
if (key.Length > 0 && !dictionary3.ContainsKey(key))
|
||||
dictionary3.Add(key, destBone);
|
||||
}
|
||||
string key1 = destBone.name ?? ((Object)destBone.t).name;
|
||||
if (!string.IsNullOrEmpty(key1))
|
||||
{
|
||||
List<BoneMatchUtil.BoneRootLocalData> boneRootLocalDataList;
|
||||
if (!dictionary4.TryGetValue(key1, out boneRootLocalDataList))
|
||||
{
|
||||
boneRootLocalDataList = new List<BoneMatchUtil.BoneRootLocalData>();
|
||||
dictionary4[key1] = boneRootLocalDataList;
|
||||
}
|
||||
boneRootLocalDataList.Add(destBone);
|
||||
}
|
||||
}
|
||||
}
|
||||
HashSet<Transform> transformSet = new HashSet<Transform>();
|
||||
foreach (BoneMatchUtil.BoneRootLocalData sourceBone in sourceBones)
|
||||
{
|
||||
if (sourceBone != null && !Object.op_Equality((Object)sourceBone.t, (Object)null))
|
||||
{
|
||||
Transform key2 = (Transform)null;
|
||||
string str = sourceBone.path ?? "";
|
||||
BoneMatchUtil.BoneRootLocalData boneRootLocalData1;
|
||||
if (str.Length > 0 && dictionary2.TryGetValue(str, out boneRootLocalData1) && boneRootLocalData1 != null && Object.op_Inequality((Object)boneRootLocalData1.t, (Object)null) && !transformSet.Contains(boneRootLocalData1.t))
|
||||
key2 = boneRootLocalData1.t;
|
||||
if (Object.op_Equality((Object)key2, (Object)null) && str.Length > 0)
|
||||
{
|
||||
string key3 = correspondenceUtil.NormalizePath(str);
|
||||
BoneMatchUtil.BoneRootLocalData boneRootLocalData2;
|
||||
if (key3.Length > 0 && dictionary3.TryGetValue(key3, out boneRootLocalData2) && boneRootLocalData2 != null && Object.op_Inequality((Object)boneRootLocalData2.t, (Object)null) && !transformSet.Contains(boneRootLocalData2.t))
|
||||
key2 = boneRootLocalData2.t;
|
||||
}
|
||||
if (Object.op_Equality((Object)key2, (Object)null))
|
||||
{
|
||||
string key4 = sourceBone.name ?? ((Object)sourceBone.t).name;
|
||||
List<BoneMatchUtil.BoneRootLocalData> boneRootLocalDataList;
|
||||
if (!string.IsNullOrEmpty(key4) && dictionary4.TryGetValue(key4, out boneRootLocalDataList))
|
||||
{
|
||||
float num1 = float.PositiveInfinity;
|
||||
Transform transform = (Transform)null;
|
||||
for (int index = 0; index < boneRootLocalDataList.Count; ++index)
|
||||
{
|
||||
BoneMatchUtil.BoneRootLocalData boneRootLocalData3 = boneRootLocalDataList[index];
|
||||
if (boneRootLocalData3 != null && !Object.op_Equality((Object)boneRootLocalData3.t, (Object)null) && !transformSet.Contains(boneRootLocalData3.t))
|
||||
{
|
||||
float num2 = Vector3.SqrMagnitude(Vector3.op_Subtraction(boneRootLocalData3.rootLocalPos, sourceBone.rootLocalPos));
|
||||
if ((double)num2 < (double)num1)
|
||||
{
|
||||
num1 = num2;
|
||||
transform = boneRootLocalData3.t;
|
||||
}
|
||||
}
|
||||
}
|
||||
key2 = transform;
|
||||
}
|
||||
}
|
||||
if (Object.op_Inequality((Object)key2, (Object)null))
|
||||
{
|
||||
if (resultReverse)
|
||||
dictionary1[key2] = sourceBone.t;
|
||||
else
|
||||
dictionary1[sourceBone.t] = key2;
|
||||
transformSet.Add(key2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dictionary1;
|
||||
}
|
||||
|
||||
public void RemapSourceClothMatchToTargetCloth(
|
||||
Transform sourceClothRoot,
|
||||
Transform targetClothRoot,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> sourceClothHumanBones,
|
||||
Dictionary<Transform, ClothBoneType> sourceClothBoneTypeMap,
|
||||
out Dictionary<HumanBodyBones, HashSet<Transform>> targetClothHumanBones,
|
||||
out Dictionary<Transform, ClothBoneType> targetClothBoneTypeMap)
|
||||
{
|
||||
targetClothHumanBones = new Dictionary<HumanBodyBones, HashSet<Transform>>();
|
||||
targetClothBoneTypeMap = new Dictionary<Transform, ClothBoneType>();
|
||||
if (Object.op_Equality((Object)sourceClothRoot, (Object)null) || Object.op_Equality((Object)targetClothRoot, (Object)null))
|
||||
throw new AutoMorpherException("Cloth Root is Missing", "[BoneMatchUtil] RemapClothMatchResultToTargetCloth\n - sourceClothRoot or targetClothRoot is null");
|
||||
if (sourceClothHumanBones == null || sourceClothBoneTypeMap == null)
|
||||
throw new AutoMorpherException("Source Cloth Match Data is Missing", "[BoneMatchUtil] RemapClothMatchResultToTargetCloth\n - sourceClothHumanBones or sourceClothBoneTypeMap is null");
|
||||
HashSet<Transform> boneList = new HashSet<Transform>();
|
||||
foreach (KeyValuePair<Transform, ClothBoneType> sourceClothBoneType in sourceClothBoneTypeMap)
|
||||
{
|
||||
if (Object.op_Inequality((Object)sourceClothBoneType.Key, (Object)null))
|
||||
boneList.Add(sourceClothBoneType.Key);
|
||||
}
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> sourceClothHumanBone in sourceClothHumanBones)
|
||||
{
|
||||
HashSet<Transform> transformSet = sourceClothHumanBone.Value;
|
||||
if (transformSet != null && transformSet.Count != 0)
|
||||
{
|
||||
foreach (Transform transform in transformSet)
|
||||
{
|
||||
if (Object.op_Inequality((Object)transform, (Object)null))
|
||||
boneList.Add(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (boneList.Count == 0)
|
||||
throw new AutoMorpherException("Source Cloth Bone Candidates are Missing", "[BoneMatchUtil] RemapClothMatchResultToTargetCloth\n - sourceBoneSet is empty (no bones found in sourceClothBoneTypeMap/sourceClothHumanBones)");
|
||||
HashSet<Transform> meshBones = this.GetMeshBones(((IEnumerable<SkinnedMeshRenderer>)((Component)targetClothRoot).GetComponentsInChildren<SkinnedMeshRenderer>(true)).ToList<SkinnedMeshRenderer>());
|
||||
if (meshBones == null || meshBones.Count == 0)
|
||||
throw new AutoMorpherException("Target Cloth Bone Candidates are Missing", "[BoneMatchUtil] RemapClothMatchResultToTargetCloth\n - targetBoneSet is null or empty (GetMeshBones returned no bones)");
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalBones1 = this.GetRootLocalBones(sourceClothRoot, boneList);
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalBones2 = this.GetRootLocalBones(targetClothRoot, meshBones);
|
||||
if (rootLocalBones1 == null || rootLocalBones1.Count == 0)
|
||||
throw new AutoMorpherException("Source RootLocal Bones are Missing", "[BoneMatchUtil] RemapClothMatchResultToTargetCloth\n - sourceRootLocalBones is null or empty");
|
||||
Dictionary<Transform, Transform> dictionary = rootLocalBones2 != null && rootLocalBones2.Count != 0 ? this.BuildTransformMatchMap(rootLocalBones1, rootLocalBones2) : throw new AutoMorpherException("Target RootLocal Bones are Missing", "[BoneMatchUtil] RemapClothMatchResultToTargetCloth\n - targetRootLocalBones is null or empty");
|
||||
foreach (KeyValuePair<Transform, ClothBoneType> sourceClothBoneType in sourceClothBoneTypeMap)
|
||||
{
|
||||
Transform key1 = sourceClothBoneType.Key;
|
||||
ClothBoneType clothBoneType1 = sourceClothBoneType.Value;
|
||||
Transform key2;
|
||||
if (!Object.op_Equality((Object)key1, (Object)null) && dictionary.TryGetValue(key1, out key2) && !Object.op_Equality((Object)key2, (Object)null))
|
||||
{
|
||||
ClothBoneType clothBoneType2;
|
||||
if (targetClothBoneTypeMap.TryGetValue(key2, out clothBoneType2))
|
||||
{
|
||||
if (clothBoneType2 == ClothBoneType.Accessory && clothBoneType1 == ClothBoneType.Body)
|
||||
targetClothBoneTypeMap[key2] = ClothBoneType.Body;
|
||||
}
|
||||
else
|
||||
targetClothBoneTypeMap.Add(key2, clothBoneType1);
|
||||
}
|
||||
}
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> sourceClothHumanBone in sourceClothHumanBones)
|
||||
{
|
||||
HumanBodyBones key3 = sourceClothHumanBone.Key;
|
||||
HashSet<Transform> transformSet1 = sourceClothHumanBone.Value;
|
||||
if (transformSet1 != null && transformSet1.Count != 0)
|
||||
{
|
||||
foreach (Transform key4 in transformSet1)
|
||||
{
|
||||
Transform transform;
|
||||
if (!Object.op_Equality((Object)key4, (Object)null) && dictionary.TryGetValue(key4, out transform) && !Object.op_Equality((Object)transform, (Object)null))
|
||||
{
|
||||
HashSet<Transform> transformSet2;
|
||||
if (!targetClothHumanBones.TryGetValue(key3, out transformSet2))
|
||||
{
|
||||
transformSet2 = new HashSet<Transform>();
|
||||
targetClothHumanBones[key3] = transformSet2;
|
||||
}
|
||||
transformSet2.Add(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BuildSourceToProxyBoneMap(
|
||||
Animator sourceAvatar,
|
||||
Animator proxyAvatar,
|
||||
out Dictionary<Transform, Transform> sourceToProxy)
|
||||
{
|
||||
sourceToProxy = new Dictionary<Transform, Transform>();
|
||||
if (Object.op_Equality((Object)sourceAvatar, (Object)null))
|
||||
throw new AutoMorpherException("Source Avatar is Missing", "[AvatarBodyMatchUtil] BuildSourceToProxyBoneMap\n - sourceAvatar is null");
|
||||
if (Object.op_Equality((Object)proxyAvatar, (Object)null))
|
||||
throw new AutoMorpherException("Proxy Avatar is Missing", "[AvatarBodyMatchUtil] BuildSourceToProxyBoneMap\n - proxyAvatar is null");
|
||||
Transform transform1 = ((Component)sourceAvatar).transform;
|
||||
Transform transform2 = ((Component)proxyAvatar).transform;
|
||||
HashSet<Transform> meshBones1 = this.GetMeshBones(((IEnumerable<SkinnedMeshRenderer>)((Component)transform2).GetComponentsInChildren<SkinnedMeshRenderer>(true)).ToList<SkinnedMeshRenderer>());
|
||||
if (meshBones1 == null || meshBones1.Count == 0)
|
||||
throw new AutoMorpherException("Proxy Body Bone Candidates are Missing", "[AvatarBodyMatchUtil] BuildSourceToProxyBoneMap\n - proxyBoneSet is null or empty (GetMeshBones returned no bones)");
|
||||
HashSet<Transform> meshBones2 = this.GetMeshBones(((IEnumerable<SkinnedMeshRenderer>)((Component)transform1).GetComponentsInChildren<SkinnedMeshRenderer>(true)).ToList<SkinnedMeshRenderer>());
|
||||
if (meshBones2 == null || meshBones2.Count == 0)
|
||||
throw new AutoMorpherException("Source Body Bone Candidates are Missing", "[AvatarBodyMatchUtil] BuildSourceToProxyBoneMap\n - sourceBoneSet is null or empty (GetMeshBones returned no bones)");
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalBones1 = this.GetRootLocalBones(transform2, meshBones1);
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalBones2 = this.GetRootLocalBones(transform1, meshBones2);
|
||||
if (rootLocalBones1 == null || rootLocalBones1.Count == 0)
|
||||
throw new AutoMorpherException("Proxy RootLocal Bones are Missing", "[AvatarBodyMatchUtil] BuildSourceToProxyBoneMap\n - proxyRootLocalBones is null or empty");
|
||||
sourceToProxy = rootLocalBones2 != null && rootLocalBones2.Count != 0 ? this.BuildTransformMatchMap(rootLocalBones1, rootLocalBones2, true) : throw new AutoMorpherException("Source RootLocal Bones are Missing", "[AvatarBodyMatchUtil] BuildSourceToProxyBoneMap\n - sourceRootLocalBones is null or empty");
|
||||
if (sourceToProxy == null)
|
||||
throw new AutoMorpherException("Source To Proxy Map Build Failed", "[AvatarBodyMatchUtil] BuildSourceToProxyBoneMap\n - BuildTransformMatchMap returned null");
|
||||
}
|
||||
|
||||
public class BoneRootLocalData
|
||||
{
|
||||
public Transform t;
|
||||
public string name;
|
||||
public string path;
|
||||
public Vector3 rootLocalPos;
|
||||
public Quaternion rootLocalRot;
|
||||
public HumanBodyBones hBone = (HumanBodyBones)55;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39ce956a348f7e24095c2239c465fb1e
|
||||
20
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs
Normal file
20
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BvhNode
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public struct BvhNode
|
||||
{
|
||||
public Bounds bounds;
|
||||
public int leftChild;
|
||||
public int rightChild;
|
||||
public int start;
|
||||
public int count;
|
||||
public bool isLeaf;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10c3a2ab07ede5146a5d92236e6735b6
|
||||
19
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs
Normal file
19
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BvhTriangle
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public struct BvhTriangle
|
||||
{
|
||||
public Vector3 a;
|
||||
public Vector3 b;
|
||||
public Vector3 c;
|
||||
public Vector3 normal;
|
||||
public HumanBodyBones mainHumanBone;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4947000410991e449b49bad5e74aec76
|
||||
701
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs
Normal file
701
Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs
Normal file
@@ -0,0 +1,701 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.BvhTriangleMesh
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class BvhTriangleMesh
|
||||
{
|
||||
private TriangleUtil triangleUtil;
|
||||
private HumanBodyBones[] humanBones;
|
||||
public BvhTriangle[] triangles;
|
||||
public BvhNode[] nodes;
|
||||
public int[] triIndices;
|
||||
private const int LeafMaxTriangles = 4;
|
||||
|
||||
public BvhTriangleMesh()
|
||||
{
|
||||
// ISSUE: unable to decompile the method.
|
||||
}
|
||||
|
||||
private HumanBodyBones[] BuildVertexMainHumanBone(
|
||||
SkinnedMeshRenderer smr,
|
||||
Animator animator,
|
||||
HumanBodyBones[] bodyBones)
|
||||
{
|
||||
Mesh sharedMesh = smr.sharedMesh;
|
||||
BoneWeight[] boneWeights = sharedMesh.boneWeights;
|
||||
int[] boneToBodyIndex = this.BuildBoneToBodyIndexMap(smr, animator, bodyBones);
|
||||
HumanBodyBones[] humanBodyBonesArray = new HumanBodyBones[sharedMesh.vertexCount];
|
||||
for (int index = 0; index < sharedMesh.vertexCount; ++index)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[index];
|
||||
int bestBodyIdx = -1;
|
||||
float bestWeight = 0.0f;
|
||||
Try(((BoneWeight)ref boneWeight).boneIndex0, ((BoneWeight)ref boneWeight).weight0);
|
||||
Try(((BoneWeight)ref boneWeight).boneIndex1, ((BoneWeight)ref boneWeight).weight1);
|
||||
Try(((BoneWeight)ref boneWeight).boneIndex2, ((BoneWeight)ref boneWeight).weight2);
|
||||
Try(((BoneWeight)ref boneWeight).boneIndex3, ((BoneWeight)ref boneWeight).weight3);
|
||||
humanBodyBonesArray[index] = bestBodyIdx >= 0 ? (HumanBodyBones)(int)bodyBones[bestBodyIdx] : (HumanBodyBones)55;
|
||||
|
||||
void Try(int boneIdx, float w)
|
||||
{
|
||||
if ((double)w <= 0.0 || boneIdx < 0 || boneIdx >= boneToBodyIndex.Length)
|
||||
return;
|
||||
int num = boneToBodyIndex[boneIdx];
|
||||
if (num < 0 || (double)w <= (double)bestWeight)
|
||||
return;
|
||||
bestWeight = w;
|
||||
bestBodyIdx = num;
|
||||
}
|
||||
}
|
||||
return humanBodyBonesArray;
|
||||
}
|
||||
|
||||
public BvhTriangleMesh BuildFromSkinnedMeshes(
|
||||
IReadOnlyList<SkinnedMeshRenderer> renderers,
|
||||
Animator animator)
|
||||
{
|
||||
if (renderers == null || renderers.Count == 0)
|
||||
return (BvhTriangleMesh)null;
|
||||
BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh();
|
||||
int length = 0;
|
||||
foreach (SkinnedMeshRenderer renderer in (IEnumerable<SkinnedMeshRenderer>)renderers)
|
||||
{
|
||||
if (!Object.op_Equality((Object)renderer, (Object)null) && !Object.op_Equality((Object)renderer.sharedMesh, (Object)null))
|
||||
length += renderer.sharedMesh.triangles.Length / 3;
|
||||
}
|
||||
if (length == 0)
|
||||
return (BvhTriangleMesh)null;
|
||||
bvhTriangleMesh.triangles = new BvhTriangle[length];
|
||||
int num1 = 0;
|
||||
Mesh mesh = new Mesh();
|
||||
foreach (SkinnedMeshRenderer renderer in (IEnumerable<SkinnedMeshRenderer>)renderers)
|
||||
{
|
||||
if (!Object.op_Equality((Object)renderer, (Object)null) && !Object.op_Equality((Object)renderer.sharedMesh, (Object)null))
|
||||
{
|
||||
mesh.Clear();
|
||||
renderer.BakeMesh(mesh);
|
||||
Vector3[] vertices = mesh.vertices;
|
||||
int[] triangles = renderer.sharedMesh.triangles;
|
||||
BoneWeight[] boneWeights = renderer.sharedMesh.boneWeights;
|
||||
int[] bodyIndexMap = this.BuildBoneToBodyIndexMap(renderer, animator, this.humanBones);
|
||||
int num2 = triangles.Length / 3;
|
||||
Transform transform = ((Component)renderer).transform;
|
||||
Vector3 lossyScale = transform.lossyScale;
|
||||
Vector3 vector3_1;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3)ref vector3_1).\u002Ector(1f / Mathf.Max(lossyScale.x, 1E-08f), 1f / Mathf.Max(lossyScale.y, 1E-08f), 1f / Mathf.Max(lossyScale.z, 1E-08f));
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.op_Multiply(transform.localToWorldMatrix, Matrix4x4.Scale(vector3_1));
|
||||
for (int index = 0; index < num2; ++index)
|
||||
{
|
||||
int vi0 = triangles[index * 3];
|
||||
int vi1 = triangles[index * 3 + 1];
|
||||
int vi2 = triangles[index * 3 + 2];
|
||||
Vector3 vector3_2 = ((Matrix4x4)ref matrix4x4).MultiplyPoint3x4(vertices[vi0]);
|
||||
Vector3 vector3_3 = ((Matrix4x4)ref matrix4x4).MultiplyPoint3x4(vertices[vi1]);
|
||||
Vector3 vector3_4 = ((Matrix4x4)ref matrix4x4).MultiplyPoint3x4(vertices[vi2]);
|
||||
Vector3 vector3_5 = Vector3.Cross(Vector3.op_Subtraction(vector3_3, vector3_2), Vector3.op_Subtraction(vector3_4, vector3_2));
|
||||
float magnitude = ((Vector3)ref vector3_5).magnitude;
|
||||
Vector3 vector3_6 = (double)magnitude <= 9.99999993922529E-09 ? Vector3.up : Vector3.op_Division(vector3_5, magnitude);
|
||||
int mainHumanBoneIndex = this.ComputeTriangleMainHumanBoneIndex(vi0, vi1, vi2, boneWeights, bodyIndexMap, this.humanBones.Length);
|
||||
HumanBodyBones humanBodyBones = mainHumanBoneIndex >= 0 ? (HumanBodyBones)(int)this.humanBones[mainHumanBoneIndex] : (HumanBodyBones)55;
|
||||
bvhTriangleMesh.triangles[num1++] = new BvhTriangle()
|
||||
{
|
||||
a = vector3_2,
|
||||
b = vector3_3,
|
||||
c = vector3_4,
|
||||
normal = vector3_6,
|
||||
mainHumanBone = humanBodyBones
|
||||
};
|
||||
mesh.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
int count = length;
|
||||
int[] triIndices = new int[count];
|
||||
for (int index = 0; index < count; ++index)
|
||||
triIndices[index] = index;
|
||||
bvhTriangleMesh.triIndices = triIndices;
|
||||
List<BvhNode> outNodes = new List<BvhNode>();
|
||||
this.BuildRecursive(bvhTriangleMesh.triangles, triIndices, 0, count, outNodes);
|
||||
bvhTriangleMesh.nodes = outNodes.ToArray();
|
||||
return bvhTriangleMesh;
|
||||
}
|
||||
|
||||
private int[] BuildBoneToBodyIndexMap(
|
||||
SkinnedMeshRenderer smr,
|
||||
Animator animator,
|
||||
HumanBodyBones[] bodyBones)
|
||||
{
|
||||
Transform[] bones = smr.bones;
|
||||
int[] bodyIndexMap = new int[bones.Length];
|
||||
for (int index = 0; index < bodyIndexMap.Length; ++index)
|
||||
bodyIndexMap[index] = -1;
|
||||
if (Object.op_Equality((Object)animator, (Object)null) || bodyBones == null || bones == null)
|
||||
return bodyIndexMap;
|
||||
Dictionary<Transform, int> dictionary1 = new Dictionary<Transform, int>();
|
||||
for (int index = 0; index < bones.Length; ++index)
|
||||
{
|
||||
if (!Object.op_Equality((Object)bones[index], (Object)null) && !dictionary1.ContainsKey(bones[index]))
|
||||
dictionary1.Add(bones[index], index);
|
||||
}
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary2 = new MeshClassifier().MeshHumanoidBoneMatcher(animator, (IReadOnlyList<SkinnedMeshRenderer>)new SkinnedMeshRenderer[1]
|
||||
{
|
||||
smr
|
||||
});
|
||||
for (int index1 = 0; index1 < bodyBones.Length; ++index1)
|
||||
{
|
||||
HumanBodyBones bodyBone = (HumanBodyBones)(int)bodyBones[index1];
|
||||
HashSet<Transform> transformSet;
|
||||
if (dictionary2.TryGetValue(bodyBone, out transformSet) && transformSet != null)
|
||||
{
|
||||
foreach (Transform key in transformSet)
|
||||
{
|
||||
int index2;
|
||||
if (!Object.op_Equality((Object)key, (Object)null) && dictionary1.TryGetValue(key, out index2))
|
||||
bodyIndexMap[index2] = index1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int index3 = 0; index3 < bones.Length; ++index3)
|
||||
{
|
||||
if (bodyIndexMap[index3] == -1)
|
||||
{
|
||||
Transform transform = bones[index3];
|
||||
if (!Object.op_Equality((Object)transform, (Object)null))
|
||||
{
|
||||
Transform parent = transform.parent;
|
||||
int index4;
|
||||
if (!Object.op_Equality((Object)parent, (Object)null) && dictionary1.TryGetValue(parent, out index4))
|
||||
{
|
||||
int num = bodyIndexMap[index4];
|
||||
if (num != -1)
|
||||
bodyIndexMap[index3] = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bodyIndexMap;
|
||||
}
|
||||
|
||||
private int ComputeTriangleMainHumanBoneIndex(
|
||||
int vi0,
|
||||
int vi1,
|
||||
int vi2,
|
||||
BoneWeight[] weights,
|
||||
int[] boneToBodyIndex,
|
||||
int bodyBonesCount)
|
||||
{
|
||||
if (weights == null || weights.Length == 0 || boneToBodyIndex == null || boneToBodyIndex.Length == 0)
|
||||
return -1;
|
||||
float[] scores = new float[bodyBonesCount];
|
||||
Accumulate(vi0);
|
||||
Accumulate(vi1);
|
||||
Accumulate(vi2);
|
||||
int mainHumanBoneIndex = -1;
|
||||
float num = 0.0f;
|
||||
for (int index = 0; index < scores.Length; ++index)
|
||||
{
|
||||
if ((double)scores[index] > (double)num)
|
||||
{
|
||||
num = scores[index];
|
||||
mainHumanBoneIndex = index;
|
||||
}
|
||||
}
|
||||
return mainHumanBoneIndex;
|
||||
|
||||
void Accumulate(int v)
|
||||
{
|
||||
if (v < 0 || v >= weights.Length)
|
||||
return;
|
||||
BoneWeight weight = weights[v];
|
||||
Add(((BoneWeight)ref weight).boneIndex0, ((BoneWeight)ref weight).weight0);
|
||||
Add(((BoneWeight)ref weight).boneIndex1, ((BoneWeight)ref weight).weight1);
|
||||
Add(((BoneWeight)ref weight).boneIndex2, ((BoneWeight)ref weight).weight2);
|
||||
Add(((BoneWeight)ref weight).boneIndex3, ((BoneWeight)ref weight).weight3);
|
||||
}
|
||||
|
||||
void Add(int boneIdx, float w)
|
||||
{
|
||||
if ((double)w <= 0.0 || boneIdx < 0 || boneIdx >= boneToBodyIndex.Length)
|
||||
return;
|
||||
int index = boneToBodyIndex[boneIdx];
|
||||
if (index < 0)
|
||||
return;
|
||||
scores[index] += w;
|
||||
}
|
||||
}
|
||||
|
||||
public BvhTriangleMesh BuildFromSkinnedMeshes(IList<SkinnedMeshRenderer> renderers)
|
||||
{
|
||||
if (renderers == null || renderers.Count == 0)
|
||||
return (BvhTriangleMesh)null;
|
||||
BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh();
|
||||
int length = 0;
|
||||
foreach (SkinnedMeshRenderer renderer in (IEnumerable<SkinnedMeshRenderer>)renderers)
|
||||
{
|
||||
if (!Object.op_Equality((Object)renderer, (Object)null) && !Object.op_Equality((Object)renderer.sharedMesh, (Object)null))
|
||||
length += renderer.sharedMesh.triangles.Length / 3;
|
||||
}
|
||||
if (length == 0)
|
||||
return (BvhTriangleMesh)null;
|
||||
bvhTriangleMesh.triangles = new BvhTriangle[length];
|
||||
int num1 = 0;
|
||||
foreach (SkinnedMeshRenderer renderer in (IEnumerable<SkinnedMeshRenderer>)renderers)
|
||||
{
|
||||
if (!Object.op_Equality((Object)renderer, (Object)null) && !Object.op_Equality((Object)renderer.sharedMesh, (Object)null))
|
||||
{
|
||||
Mesh sharedMesh = renderer.sharedMesh;
|
||||
Vector3[] vertices = sharedMesh.vertices;
|
||||
int[] triangles = sharedMesh.triangles;
|
||||
int num2 = triangles.Length / 3;
|
||||
for (int index1 = 0; index1 < num2; ++index1)
|
||||
{
|
||||
int index2 = triangles[index1 * 3];
|
||||
int index3 = triangles[index1 * 3 + 1];
|
||||
int index4 = triangles[index1 * 3 + 2];
|
||||
Vector3 vector3_1 = ((Component)renderer).transform.TransformPoint(vertices[index2]);
|
||||
Vector3 vector3_2 = ((Component)renderer).transform.TransformPoint(vertices[index3]);
|
||||
Vector3 vector3_3 = ((Component)renderer).transform.TransformPoint(vertices[index4]);
|
||||
Vector3 vector3_4 = Vector3.Cross(Vector3.op_Subtraction(vector3_2, vector3_1), Vector3.op_Subtraction(vector3_3, vector3_1));
|
||||
float magnitude = ((Vector3)ref vector3_4).magnitude;
|
||||
Vector3 vector3_5 = (double)magnitude <= 9.99999993922529E-09 ? Vector3.up : Vector3.op_Division(vector3_4, magnitude);
|
||||
bvhTriangleMesh.triangles[num1++] = new BvhTriangle()
|
||||
{
|
||||
a = vector3_1,
|
||||
b = vector3_2,
|
||||
c = vector3_3,
|
||||
normal = vector3_5
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
int count = length;
|
||||
int[] triIndices = new int[count];
|
||||
for (int index = 0; index < count; ++index)
|
||||
triIndices[index] = index;
|
||||
bvhTriangleMesh.triIndices = triIndices;
|
||||
List<BvhNode> outNodes = new List<BvhNode>();
|
||||
this.BuildRecursive(bvhTriangleMesh.triangles, triIndices, 0, count, outNodes);
|
||||
bvhTriangleMesh.nodes = outNodes.ToArray();
|
||||
return bvhTriangleMesh;
|
||||
}
|
||||
|
||||
public BvhTriangleMesh BuildFromMesh(Mesh mesh, Transform transform)
|
||||
{
|
||||
BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh();
|
||||
Vector3[] vertices = mesh.vertices;
|
||||
int[] triangles = mesh.triangles;
|
||||
int count = triangles.Length / 3;
|
||||
bvhTriangleMesh.triangles = new BvhTriangle[count];
|
||||
for (int index1 = 0; index1 < count; ++index1)
|
||||
{
|
||||
int index2 = triangles[index1 * 3];
|
||||
int index3 = triangles[index1 * 3 + 1];
|
||||
int index4 = triangles[index1 * 3 + 2];
|
||||
Vector3 vector3_1 = transform.TransformPoint(vertices[index2]);
|
||||
Vector3 vector3_2 = transform.TransformPoint(vertices[index3]);
|
||||
Vector3 vector3_3 = transform.TransformPoint(vertices[index4]);
|
||||
Vector3 vector3_4 = Vector3.Cross(Vector3.op_Subtraction(vector3_2, vector3_1), Vector3.op_Subtraction(vector3_3, vector3_1));
|
||||
float magnitude = ((Vector3)ref vector3_4).magnitude;
|
||||
vector3_4 = (double)magnitude <= 9.99999993922529E-09 ? Vector3.up : Vector3.op_Division(vector3_4, magnitude);
|
||||
bvhTriangleMesh.triangles[index1] = new BvhTriangle()
|
||||
{
|
||||
a = vector3_1,
|
||||
b = vector3_2,
|
||||
c = vector3_3,
|
||||
normal = vector3_4
|
||||
};
|
||||
}
|
||||
int[] triIndices = new int[count];
|
||||
for (int index = 0; index < count; ++index)
|
||||
triIndices[index] = index;
|
||||
bvhTriangleMesh.triIndices = triIndices;
|
||||
List<BvhNode> outNodes = new List<BvhNode>();
|
||||
this.BuildRecursive(bvhTriangleMesh.triangles, triIndices, 0, count, outNodes);
|
||||
bvhTriangleMesh.nodes = outNodes.ToArray();
|
||||
return bvhTriangleMesh;
|
||||
}
|
||||
|
||||
private int BuildRecursive(
|
||||
BvhTriangle[] tris,
|
||||
int[] triIndices,
|
||||
int start,
|
||||
int count,
|
||||
List<BvhNode> outNodes)
|
||||
{
|
||||
int count1 = outNodes.Count;
|
||||
BvhNode bvhNode = new BvhNode();
|
||||
Bounds bounds = new Bounds();
|
||||
bool flag = true;
|
||||
for (int index = start; index < start + count; ++index)
|
||||
{
|
||||
BvhTriangle tri = tris[triIndices[index]];
|
||||
if (flag)
|
||||
{
|
||||
// ISSUE: explicit constructor call
|
||||
((Bounds)ref bounds).\u002Ector(tri.a, Vector3.zero);
|
||||
((Bounds)ref bounds).Encapsulate(tri.b);
|
||||
((Bounds)ref bounds).Encapsulate(tri.c);
|
||||
flag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
((Bounds)ref bounds).Encapsulate(tri.a);
|
||||
((Bounds)ref bounds).Encapsulate(tri.b);
|
||||
((Bounds)ref bounds).Encapsulate(tri.c);
|
||||
}
|
||||
}
|
||||
bvhNode.bounds = bounds;
|
||||
if (count <= 4)
|
||||
{
|
||||
bvhNode.isLeaf = true;
|
||||
bvhNode.start = start;
|
||||
bvhNode.count = count;
|
||||
bvhNode.leftChild = -1;
|
||||
bvhNode.rightChild = -1;
|
||||
outNodes.Add(bvhNode);
|
||||
return count1;
|
||||
}
|
||||
Vector3 size = ((Bounds)ref bounds).size;
|
||||
int axis = 0;
|
||||
if ((double)size.y > (double)size.x && (double)size.y > (double)size.z)
|
||||
axis = 1;
|
||||
else if ((double)size.z > (double)size.x && (double)size.z > (double)size.y)
|
||||
axis = 2;
|
||||
float num1 = 0.0f;
|
||||
for (int index = start; index < start + count; ++index)
|
||||
{
|
||||
BvhTriangle tri = tris[triIndices[index]];
|
||||
Vector3 vector3 = Vector3.op_Division(Vector3.op_Addition(Vector3.op_Addition(tri.a, tri.b), tri.c), 3f);
|
||||
num1 += ((Vector3)ref vector3)[axis];
|
||||
}
|
||||
float splitPos = num1 / (float)count;
|
||||
int start1 = this.Partition(tris, triIndices, start, count, axis, splitPos);
|
||||
if (start1 == start || start1 == start + count)
|
||||
start1 = start + count / 2;
|
||||
bvhNode.isLeaf = false;
|
||||
bvhNode.start = -1;
|
||||
bvhNode.count = 0;
|
||||
outNodes.Add(bvhNode);
|
||||
int num2 = this.BuildRecursive(tris, triIndices, start, start1 - start, outNodes);
|
||||
int num3 = this.BuildRecursive(tris, triIndices, start1, start + count - start1, outNodes);
|
||||
bvhNode.leftChild = num2;
|
||||
bvhNode.rightChild = num3;
|
||||
outNodes[count1] = bvhNode;
|
||||
return count1;
|
||||
}
|
||||
|
||||
private int Partition(
|
||||
BvhTriangle[] tris,
|
||||
int[] triIndices,
|
||||
int start,
|
||||
int count,
|
||||
int axis,
|
||||
float splitPos)
|
||||
{
|
||||
int index1 = start;
|
||||
int index2 = start + count - 1;
|
||||
while (index1 <= index2)
|
||||
{
|
||||
BvhTriangle tri1 = tris[triIndices[index1]];
|
||||
BvhTriangle tri2 = tris[triIndices[index2]];
|
||||
double num1 = ((double)((Vector3)ref tri1.a)[axis] + (double)((Vector3)ref tri1.b)[axis] + (double)((Vector3)ref tri1.c)[axis]) / 3.0;
|
||||
double num2 = ((double)((Vector3)ref tri2.a)[axis] + (double)((Vector3)ref tri2.b)[axis] + (double)((Vector3)ref tri2.c)[axis]) / 3.0;
|
||||
double num3 = (double)splitPos;
|
||||
if (num1 < num3)
|
||||
{
|
||||
++index1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int triIndex = triIndices[index1];
|
||||
triIndices[index1] = triIndices[index2];
|
||||
triIndices[index2] = triIndex;
|
||||
--index2;
|
||||
}
|
||||
}
|
||||
return index1;
|
||||
}
|
||||
|
||||
public BvhTriangleMesh.ClosestHit QueryClosest(Vector3 point)
|
||||
{
|
||||
BvhTriangleMesh.ClosestHit best = new BvhTriangleMesh.ClosestHit()
|
||||
{
|
||||
triangleIndex = -1,
|
||||
sqrDistance = float.MaxValue
|
||||
};
|
||||
if (this.nodes == null || this.nodes.Length == 0)
|
||||
return best;
|
||||
this.QueryClosestRecursive(0, point, ref best);
|
||||
return best;
|
||||
}
|
||||
|
||||
public BvhTriangleMesh.ClosestHit QueryClosest(
|
||||
Vector3 point,
|
||||
HashSet<HumanBodyBones> allowedBones)
|
||||
{
|
||||
BvhTriangleMesh.ClosestHit best = new BvhTriangleMesh.ClosestHit()
|
||||
{
|
||||
triangleIndex = -1,
|
||||
sqrDistance = float.MaxValue
|
||||
};
|
||||
if (this.nodes == null || this.nodes.Length == 0)
|
||||
return best;
|
||||
if (allowedBones == null || allowedBones.Count == 0)
|
||||
this.QueryClosestRecursive(0, point, ref best);
|
||||
else
|
||||
this.QueryClosestRecursiveFiltered(0, point, ref best, allowedBones);
|
||||
return best;
|
||||
}
|
||||
|
||||
private void QueryClosestRecursiveFiltered(
|
||||
int nodeIndex,
|
||||
Vector3 p,
|
||||
ref BvhTriangleMesh.ClosestHit best,
|
||||
HashSet<HumanBodyBones> allowedBones)
|
||||
{
|
||||
BvhNode node = this.nodes[nodeIndex];
|
||||
if ((double)this.DistanceSqPointAABB(p, node.bounds) > (double)best.sqrDistance)
|
||||
return;
|
||||
if (node.isLeaf)
|
||||
{
|
||||
int num = node.start + node.count;
|
||||
for (int start = node.start; start < num; ++start)
|
||||
{
|
||||
int triIndex = this.triIndices[start];
|
||||
BvhTriangle triangle = this.triangles[triIndex];
|
||||
if (allowedBones.Contains(triangle.mainHumanBone))
|
||||
{
|
||||
Vector3 vector3_1 = this.triangleUtil.ClosestPointOnTriangle(p, triangle.a, triangle.b, triangle.c);
|
||||
Vector3 vector3_2 = Vector3.op_Subtraction(p, vector3_1);
|
||||
float sqrMagnitude = ((Vector3)ref vector3_2).sqrMagnitude;
|
||||
if ((double)sqrMagnitude < (double)best.sqrDistance)
|
||||
{
|
||||
best.sqrDistance = sqrMagnitude;
|
||||
best.triangleIndex = triIndex;
|
||||
best.closestPoint = vector3_1;
|
||||
best.normal = triangle.normal;
|
||||
best.mainHumanBone = triangle.mainHumanBone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int leftChild = node.leftChild;
|
||||
int rightChild = node.rightChild;
|
||||
if ((double)this.DistanceSqPointAABB(p, this.nodes[leftChild].bounds) < (double)this.DistanceSqPointAABB(p, this.nodes[rightChild].bounds))
|
||||
{
|
||||
this.QueryClosestRecursiveFiltered(leftChild, p, ref best, allowedBones);
|
||||
this.QueryClosestRecursiveFiltered(rightChild, p, ref best, allowedBones);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.QueryClosestRecursiveFiltered(rightChild, p, ref best, allowedBones);
|
||||
this.QueryClosestRecursiveFiltered(leftChild, p, ref best, allowedBones);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void QueryClosestRecursive(int nodeIndex, Vector3 p, ref BvhTriangleMesh.ClosestHit best)
|
||||
{
|
||||
BvhNode node = this.nodes[nodeIndex];
|
||||
if ((double)this.DistanceSqPointAABB(p, node.bounds) > (double)best.sqrDistance)
|
||||
return;
|
||||
if (node.isLeaf)
|
||||
{
|
||||
int num = node.start + node.count;
|
||||
for (int start = node.start; start < num; ++start)
|
||||
{
|
||||
int triIndex = this.triIndices[start];
|
||||
BvhTriangle triangle = this.triangles[triIndex];
|
||||
Vector3 vector3_1 = this.triangleUtil.ClosestPointOnTriangle(p, triangle.a, triangle.b, triangle.c);
|
||||
Vector3 vector3_2 = Vector3.op_Subtraction(p, vector3_1);
|
||||
float sqrMagnitude = ((Vector3)ref vector3_2).sqrMagnitude;
|
||||
if ((double)sqrMagnitude < (double)best.sqrDistance)
|
||||
{
|
||||
best.sqrDistance = sqrMagnitude;
|
||||
best.triangleIndex = triIndex;
|
||||
best.closestPoint = vector3_1;
|
||||
best.normal = triangle.normal;
|
||||
best.mainHumanBone = triangle.mainHumanBone;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int leftChild = node.leftChild;
|
||||
int rightChild = node.rightChild;
|
||||
if ((double)this.DistanceSqPointAABB(p, this.nodes[leftChild].bounds) < (double)this.DistanceSqPointAABB(p, this.nodes[rightChild].bounds))
|
||||
{
|
||||
this.QueryClosestRecursive(leftChild, p, ref best);
|
||||
this.QueryClosestRecursive(rightChild, p, ref best);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.QueryClosestRecursive(rightChild, p, ref best);
|
||||
this.QueryClosestRecursive(leftChild, p, ref best);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float DistanceSqPointAABB(Vector3 p, Bounds b)
|
||||
{
|
||||
float num1 = Mathf.Max(new float[3]
|
||||
{
|
||||
((Bounds) ref b).min.x - p.x,
|
||||
0.0f,
|
||||
p.x - ((Bounds) ref b).max.x
|
||||
});
|
||||
float num2 = Mathf.Max(new float[3]
|
||||
{
|
||||
((Bounds) ref b).min.y - p.y,
|
||||
0.0f,
|
||||
p.y - ((Bounds) ref b).max.y
|
||||
});
|
||||
float num3 = Mathf.Max(new float[3]
|
||||
{
|
||||
((Bounds) ref b).min.z - p.z,
|
||||
0.0f,
|
||||
p.z - ((Bounds) ref b).max.z
|
||||
});
|
||||
return (float)((double)num1 * (double)num1 + (double)num2 * (double)num2 + (double)num3 * (double)num3);
|
||||
}
|
||||
|
||||
public int QueryClosestN(
|
||||
Vector3 point,
|
||||
int maxCount,
|
||||
float maxDistance,
|
||||
List<BvhTriangleMesh.ClosestHit> results)
|
||||
{
|
||||
results.Clear();
|
||||
if (this.nodes == null || this.nodes.Length == 0 || maxCount <= 0)
|
||||
return 0;
|
||||
float maxDistanceSq = maxDistance * maxDistance;
|
||||
float currentMaxSq = maxDistanceSq;
|
||||
this.QueryClosestNRecursive(0, point, maxCount, maxDistanceSq, results, ref currentMaxSq);
|
||||
return results.Count;
|
||||
}
|
||||
|
||||
private void QueryClosestNRecursive(
|
||||
int nodeIndex,
|
||||
Vector3 p,
|
||||
int maxCount,
|
||||
float maxDistanceSq,
|
||||
List<BvhTriangleMesh.ClosestHit> bestHits,
|
||||
ref float currentMaxSq)
|
||||
{
|
||||
BvhNode node = this.nodes[nodeIndex];
|
||||
if ((double)this.DistanceSqPointAABB(p, node.bounds) > (double)currentMaxSq)
|
||||
return;
|
||||
if (node.isLeaf)
|
||||
{
|
||||
int num1 = node.start + node.count;
|
||||
for (int start = node.start; start < num1; ++start)
|
||||
{
|
||||
int triIndex = this.triIndices[start];
|
||||
BvhTriangle triangle = this.triangles[triIndex];
|
||||
Vector3 vector3_1 = this.triangleUtil.ClosestPointOnTriangle(p, triangle.a, triangle.b, triangle.c);
|
||||
Vector3 vector3_2 = Vector3.op_Subtraction(p, vector3_1);
|
||||
float sqrMagnitude = ((Vector3)ref vector3_2).sqrMagnitude;
|
||||
BvhTriangleMesh.ClosestHit closestHit1;
|
||||
if ((double)sqrMagnitude <= (double)maxDistanceSq)
|
||||
{
|
||||
if (bestHits.Count < maxCount)
|
||||
{
|
||||
List<BvhTriangleMesh.ClosestHit> closestHitList = bestHits;
|
||||
closestHit1 = new BvhTriangleMesh.ClosestHit();
|
||||
closestHit1.triangleIndex = triIndex;
|
||||
closestHit1.closestPoint = vector3_1;
|
||||
closestHit1.normal = triangle.normal;
|
||||
closestHit1.sqrDistance = sqrMagnitude;
|
||||
closestHit1.mainHumanBone = triangle.mainHumanBone;
|
||||
BvhTriangleMesh.ClosestHit closestHit2 = closestHit1;
|
||||
closestHitList.Add(closestHit2);
|
||||
if (bestHits.Count == maxCount)
|
||||
currentMaxSq = this.GetMaxSqrDistance(bestHits, maxDistanceSq);
|
||||
}
|
||||
else if ((double)sqrMagnitude < (double)currentMaxSq)
|
||||
{
|
||||
int num2 = 0;
|
||||
float sqrDistance = bestHits[0].sqrDistance;
|
||||
for (int index = 1; index < bestHits.Count; ++index)
|
||||
{
|
||||
if ((double)bestHits[index].sqrDistance > (double)sqrDistance)
|
||||
{
|
||||
sqrDistance = bestHits[index].sqrDistance;
|
||||
num2 = index;
|
||||
}
|
||||
}
|
||||
List<BvhTriangleMesh.ClosestHit> closestHitList = bestHits;
|
||||
int index1 = num2;
|
||||
closestHit1 = new BvhTriangleMesh.ClosestHit();
|
||||
closestHit1.triangleIndex = triIndex;
|
||||
closestHit1.closestPoint = vector3_1;
|
||||
closestHit1.normal = triangle.normal;
|
||||
closestHit1.sqrDistance = sqrMagnitude;
|
||||
BvhTriangleMesh.ClosestHit closestHit3 = closestHit1;
|
||||
closestHitList[index1] = closestHit3;
|
||||
currentMaxSq = this.GetMaxSqrDistance(bestHits, maxDistanceSq);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int leftChild = node.leftChild;
|
||||
int rightChild = node.rightChild;
|
||||
if ((double)this.DistanceSqPointAABB(p, this.nodes[leftChild].bounds) < (double)this.DistanceSqPointAABB(p, this.nodes[rightChild].bounds))
|
||||
{
|
||||
this.QueryClosestNRecursive(leftChild, p, maxCount, maxDistanceSq, bestHits, ref currentMaxSq);
|
||||
this.QueryClosestNRecursive(rightChild, p, maxCount, maxDistanceSq, bestHits, ref currentMaxSq);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.QueryClosestNRecursive(rightChild, p, maxCount, maxDistanceSq, bestHits, ref currentMaxSq);
|
||||
this.QueryClosestNRecursive(leftChild, p, maxCount, maxDistanceSq, bestHits, ref currentMaxSq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float GetMaxSqrDistance(List<BvhTriangleMesh.ClosestHit> bestHits, float maxDistanceSq)
|
||||
{
|
||||
if (bestHits.Count == 0)
|
||||
return maxDistanceSq;
|
||||
float sqrDistance = bestHits[0].sqrDistance;
|
||||
for (int index = 1; index < bestHits.Count; ++index)
|
||||
{
|
||||
if ((double)bestHits[index].sqrDistance > (double)sqrDistance)
|
||||
sqrDistance = bestHits[index].sqrDistance;
|
||||
}
|
||||
return Mathf.Min(sqrDistance, maxDistanceSq);
|
||||
}
|
||||
|
||||
public Vector3 ComputeMoveVectorToSurface(Vector3 p, float targetGap = 0.0f)
|
||||
{
|
||||
BvhTriangleMesh.ClosestHit closestHit = this.QueryClosest(p);
|
||||
if (closestHit.triangleIndex < 0)
|
||||
return Vector3.zero;
|
||||
Vector3 moveVectorToSurface = Vector3.op_Subtraction(closestHit.closestPoint, p);
|
||||
if ((double)targetGap > 0.0)
|
||||
moveVectorToSurface = Vector3.op_Addition(moveVectorToSurface, Vector3.op_Multiply(((Vector3)ref closestHit.normal).normalized, targetGap));
|
||||
return moveVectorToSurface;
|
||||
}
|
||||
|
||||
public struct ClosestHit
|
||||
{
|
||||
public int triangleIndex;
|
||||
public Vector3 closestPoint;
|
||||
public Vector3 normal;
|
||||
public float sqrDistance;
|
||||
public HumanBodyBones mainHumanBone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: feac9ce49c744e7458ea3f9a49d761d9
|
||||
14
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs
Normal file
14
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.ClothBoneType
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public enum ClothBoneType
|
||||
{
|
||||
Body,
|
||||
Accessory,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d1467eb46bc3ce4abdcee64c9422a25
|
||||
@@ -0,0 +1,285 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.ClothHumanoidMaskUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class ClothHumanoidMaskUtil
|
||||
{
|
||||
public void BuildExcludedVertexMaskForHandsAndHead(
|
||||
ClothInstance clothInstance,
|
||||
bool excludeHandRoot = false,
|
||||
bool excludeThumbRoot = false)
|
||||
{
|
||||
if (clothInstance == null || Object.op_Equality((Object)clothInstance.smr, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[ClothHumanoidMaskUtil] clothInstance / smr 가 null");
|
||||
}
|
||||
else
|
||||
{
|
||||
SkinnedMeshRenderer smr = clothInstance.smr;
|
||||
Mesh mesh = clothInstance.editableMesh ?? smr.sharedMesh;
|
||||
if (Object.op_Equality((Object)mesh, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[ClothHumanoidMaskUtil] mesh 가 null");
|
||||
}
|
||||
else
|
||||
{
|
||||
BoneWeight[] boneWeights = mesh.boneWeights;
|
||||
Transform[] bones = smr.bones;
|
||||
if (boneWeights == null || boneWeights.Length == 0 || bones == null || bones.Length == 0)
|
||||
Debug.LogWarning((object)"[ClothHumanoidMaskUtil] boneWeights 또는 bones 비어있음");
|
||||
else if (clothInstance.humanoidMatchedBones == null || clothInstance.humanoidMatchedBones.Count == 0)
|
||||
{
|
||||
Debug.LogWarning((object)"[ClothHumanoidMaskUtil] humanoidMatchedBones 가 비어있음 (BodyToClothPoseApplier에서 매칭 안 되었을 가능성)");
|
||||
}
|
||||
else
|
||||
{
|
||||
int length = mesh.vertexCount;
|
||||
if (boneWeights.Length != length)
|
||||
length = Mathf.Min(length, boneWeights.Length);
|
||||
HashSet<Transform> excludedBones = new HashSet<Transform>();
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanoidMatchedBones = clothInstance.humanoidMatchedBones;
|
||||
HashSet<Transform> transformSet1;
|
||||
if (humanoidMatchedBones.TryGetValue((HumanBodyBones)10, out transformSet1) && transformSet1 != null)
|
||||
{
|
||||
foreach (Transform root in transformSet1)
|
||||
{
|
||||
if (!Object.op_Equality((Object)root, (Object)null))
|
||||
AddHierarchy(root, true);
|
||||
}
|
||||
}
|
||||
HashSet<Transform> transformSet2;
|
||||
if (humanoidMatchedBones.TryGetValue((HumanBodyBones)17, out transformSet2) && transformSet2 != null)
|
||||
{
|
||||
foreach (Transform root in transformSet2)
|
||||
{
|
||||
if (!Object.op_Equality((Object)root, (Object)null))
|
||||
AddHierarchy(root, excludeHandRoot);
|
||||
}
|
||||
}
|
||||
HashSet<Transform> transformSet3;
|
||||
if (humanoidMatchedBones.TryGetValue((HumanBodyBones)18, out transformSet3) && transformSet3 != null)
|
||||
{
|
||||
foreach (Transform root in transformSet3)
|
||||
{
|
||||
if (!Object.op_Equality((Object)root, (Object)null))
|
||||
AddHierarchy(root, excludeHandRoot);
|
||||
}
|
||||
}
|
||||
HashSet<Transform> transformSet4;
|
||||
if (humanoidMatchedBones.TryGetValue((HumanBodyBones)24, out transformSet4) && transformSet4 != null)
|
||||
{
|
||||
foreach (Transform transform in transformSet4)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform, (Object)null))
|
||||
{
|
||||
if (excludeThumbRoot)
|
||||
excludedBones.Add(transform);
|
||||
else
|
||||
excludedBones.Remove(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
HashSet<Transform> transformSet5;
|
||||
if (humanoidMatchedBones.TryGetValue((HumanBodyBones)39, out transformSet5) && transformSet5 != null)
|
||||
{
|
||||
foreach (Transform transform in transformSet5)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform, (Object)null))
|
||||
{
|
||||
if (excludeThumbRoot)
|
||||
excludedBones.Add(transform);
|
||||
else
|
||||
excludedBones.Remove(transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool[] boneIndexExcluded = new bool[bones.Length];
|
||||
for (int index = 0; index < bones.Length; ++index)
|
||||
{
|
||||
Transform transform = bones[index];
|
||||
if (Object.op_Inequality((Object)transform, (Object)null) && excludedBones.Contains(transform))
|
||||
boneIndexExcluded[index] = true;
|
||||
}
|
||||
bool[] flagArray = new bool[length];
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[index];
|
||||
float excludedWeightSum = 0.0f;
|
||||
AddExcludedWeight(((BoneWeight)ref boneWeight).weight0, ((BoneWeight)ref boneWeight).boneIndex0);
|
||||
AddExcludedWeight(((BoneWeight)ref boneWeight).weight1, ((BoneWeight)ref boneWeight).boneIndex1);
|
||||
AddExcludedWeight(((BoneWeight)ref boneWeight).weight2, ((BoneWeight)ref boneWeight).boneIndex2);
|
||||
AddExcludedWeight(((BoneWeight)ref boneWeight).weight3, ((BoneWeight)ref boneWeight).boneIndex3);
|
||||
flagArray[index] = (double)excludedWeightSum >= 0.800000011920929;
|
||||
|
||||
void AddExcludedWeight(float w, int bi)
|
||||
{
|
||||
if ((double)w <= 0.0 || bi < 0 || bi >= boneIndexExcluded.Length || !boneIndexExcluded[bi])
|
||||
return;
|
||||
excludedWeightSum += w;
|
||||
}
|
||||
}
|
||||
clothInstance.excludedVertices = flagArray;
|
||||
this.BuildLegVertexMasks(clothInstance);
|
||||
|
||||
void AddHierarchy(Transform root, bool includeRoot)
|
||||
{
|
||||
if (Object.op_Equality((Object)root, (Object)null))
|
||||
return;
|
||||
Stack<Transform> transformStack = new Stack<Transform>();
|
||||
if (includeRoot)
|
||||
{
|
||||
transformStack.Push(root);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index = 0; index < root.childCount; ++index)
|
||||
transformStack.Push(root.GetChild(index));
|
||||
}
|
||||
while (transformStack.Count > 0)
|
||||
{
|
||||
Transform transform = transformStack.Pop();
|
||||
if (!Object.op_Equality((Object)transform, (Object)null) && excludedBones.Add(transform))
|
||||
{
|
||||
for (int index = 0; index < transform.childCount; ++index)
|
||||
transformStack.Push(transform.GetChild(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BuildLegVertexMasks(ClothInstance clothInstance)
|
||||
{
|
||||
if (clothInstance == null || Object.op_Equality((Object)clothInstance.smr, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[ClothHumanoidMaskUtil] clothInstance / smr 가 null");
|
||||
}
|
||||
else
|
||||
{
|
||||
SkinnedMeshRenderer smr = clothInstance.smr;
|
||||
Mesh mesh = clothInstance.editableMesh ?? smr.sharedMesh;
|
||||
if (Object.op_Equality((Object)mesh, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[ClothHumanoidMaskUtil] mesh 가 null");
|
||||
}
|
||||
else
|
||||
{
|
||||
BoneWeight[] boneWeights = mesh.boneWeights;
|
||||
Transform[] bones = smr.bones;
|
||||
if (boneWeights == null || boneWeights.Length == 0 || bones == null || bones.Length == 0)
|
||||
Debug.LogWarning((object)"[ClothHumanoidMaskUtil] boneWeights 또는 bones 비어있음");
|
||||
else if (clothInstance.humanoidMatchedBones == null || clothInstance.humanoidMatchedBones.Count == 0)
|
||||
{
|
||||
Debug.LogWarning((object)"[ClothHumanoidMaskUtil] humanoidMatchedBones 가 비어있음 (BodyToClothPoseApplier에서 매칭 필요)");
|
||||
}
|
||||
else
|
||||
{
|
||||
int length = mesh.vertexCount;
|
||||
if (boneWeights.Length != length)
|
||||
length = Mathf.Min(length, boneWeights.Length);
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanoidMatchedBones = clothInstance.humanoidMatchedBones;
|
||||
HashSet<Transform> set1 = new HashSet<Transform>();
|
||||
HashSet<Transform> set2 = new HashSet<Transform>();
|
||||
HashSet<Transform> transformSet1;
|
||||
if (humanoidMatchedBones.TryGetValue((HumanBodyBones)1, out transformSet1) && transformSet1 != null)
|
||||
{
|
||||
foreach (Transform root in transformSet1)
|
||||
{
|
||||
if (!Object.op_Equality((Object)root, (Object)null))
|
||||
CollectHierarchy(root, set1);
|
||||
}
|
||||
}
|
||||
HashSet<Transform> transformSet2;
|
||||
if (humanoidMatchedBones.TryGetValue((HumanBodyBones)2, out transformSet2) && transformSet2 != null)
|
||||
{
|
||||
foreach (Transform root in transformSet2)
|
||||
{
|
||||
if (!Object.op_Equality((Object)root, (Object)null))
|
||||
CollectHierarchy(root, set2);
|
||||
}
|
||||
}
|
||||
bool[] boneIsLeftLeg = new bool[bones.Length];
|
||||
bool[] boneIsRightLeg = new bool[bones.Length];
|
||||
for (int index = 0; index < bones.Length; ++index)
|
||||
{
|
||||
Transform transform = bones[index];
|
||||
if (!Object.op_Equality((Object)transform, (Object)null))
|
||||
{
|
||||
if (set1.Contains(transform))
|
||||
boneIsLeftLeg[index] = true;
|
||||
if (set2.Contains(transform))
|
||||
boneIsRightLeg[index] = true;
|
||||
}
|
||||
}
|
||||
bool[] flagArray1 = new bool[length];
|
||||
bool[] flagArray2 = new bool[length];
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
BoneWeight boneWeight = boneWeights[index];
|
||||
float leftWeight = 0.0f;
|
||||
float rightWeight = 0.0f;
|
||||
Check(((BoneWeight)ref boneWeight).boneIndex0, ((BoneWeight)ref boneWeight).weight0);
|
||||
Check(((BoneWeight)ref boneWeight).boneIndex1, ((BoneWeight)ref boneWeight).weight1);
|
||||
Check(((BoneWeight)ref boneWeight).boneIndex2, ((BoneWeight)ref boneWeight).weight2);
|
||||
Check(((BoneWeight)ref boneWeight).boneIndex3, ((BoneWeight)ref boneWeight).weight3);
|
||||
if ((double)leftWeight > 0.800000011920929)
|
||||
{
|
||||
flagArray1[index] = true;
|
||||
flagArray2[index] = false;
|
||||
}
|
||||
else if ((double)rightWeight > 0.800000011920929)
|
||||
{
|
||||
flagArray1[index] = false;
|
||||
flagArray2[index] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
flagArray1[index] = false;
|
||||
flagArray2[index] = false;
|
||||
}
|
||||
|
||||
void Check(int bi, float w)
|
||||
{
|
||||
if (bi < 0 || bi >= bones.Length || (double)w <= 0.0)
|
||||
return;
|
||||
if (boneIsLeftLeg[bi])
|
||||
leftWeight += w;
|
||||
if (!boneIsRightLeg[bi])
|
||||
return;
|
||||
rightWeight += w;
|
||||
}
|
||||
}
|
||||
clothInstance.isLeftLegVertex = flagArray1;
|
||||
clothInstance.isRightLegVertex = flagArray2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CollectHierarchy(Transform root, HashSet<Transform> set)
|
||||
{
|
||||
if (Object.op_Equality((Object)root, (Object)null))
|
||||
return;
|
||||
Stack<Transform> transformStack = new Stack<Transform>();
|
||||
transformStack.Push(root);
|
||||
while (transformStack.Count > 0)
|
||||
{
|
||||
Transform transform = transformStack.Pop();
|
||||
if (!Object.op_Equality((Object)transform, (Object)null) && set.Add(transform))
|
||||
{
|
||||
for (int index = 0; index < transform.childCount; ++index)
|
||||
transformStack.Push(transform.GetChild(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e30cb89b417c4648ab8278d89cce772
|
||||
518
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs
Normal file
518
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs
Normal file
@@ -0,0 +1,518 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.ClothInstance
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
[Serializable]
|
||||
public class ClothInstance
|
||||
{
|
||||
public SkinnedMeshRenderer smr;
|
||||
public Mesh editableMesh;
|
||||
public Mesh bakedMesh;
|
||||
public Matrix4x4 worldNoScale;
|
||||
public Vector3[] worldVertices;
|
||||
public Vector3[] minDistanceVector;
|
||||
public float[] minDistance;
|
||||
public Vector3[] deltas;
|
||||
public Vector3[] deltasLocal;
|
||||
public List<int>[] vertexAdjacency;
|
||||
public List<List<int>> equivalentVertices;
|
||||
public bool[] isInsideVertex;
|
||||
public bool[] excludedVertices;
|
||||
public bool[] isLeftLegVertex;
|
||||
public bool[] isRightLegVertex;
|
||||
public Vector3[] bakedWorldNormals;
|
||||
public Vector4[] bakedWorldTangents;
|
||||
public Dictionary<HumanBodyBones, HashSet<Transform>> humanoidMatchedBones;
|
||||
|
||||
public ClothInstance(SkinnedMeshRenderer clotheSMR, bool duplicateMesh = true)
|
||||
{
|
||||
this.smr = clotheSMR;
|
||||
if (duplicateMesh)
|
||||
{
|
||||
string name = ((Object)this.smr.sharedMesh).name;
|
||||
this.editableMesh = Object.Instantiate<Mesh>(clotheSMR.sharedMesh);
|
||||
((Object)this.editableMesh).name = name + "_EditableMesh";
|
||||
this.smr.sharedMesh = this.editableMesh;
|
||||
}
|
||||
else
|
||||
this.editableMesh = this.smr.sharedMesh;
|
||||
this.UpdateWorldVertices();
|
||||
int vertexCount = this.editableMesh.vertexCount;
|
||||
this.minDistanceVector = new Vector3[vertexCount];
|
||||
this.deltas = new Vector3[vertexCount];
|
||||
this.minDistance = new float[vertexCount];
|
||||
this.isInsideVertex = new bool[vertexCount];
|
||||
this.excludedVertices = new bool[vertexCount];
|
||||
this.isLeftLegVertex = new bool[vertexCount];
|
||||
this.isRightLegVertex = new bool[vertexCount];
|
||||
this.humanoidMatchedBones = new Dictionary<HumanBodyBones, HashSet<Transform>>();
|
||||
this.vertexAdjacency = this.BuildVertexAdjacency(this.editableMesh);
|
||||
this.BuildEquivalentVerticesFromWorld();
|
||||
}
|
||||
|
||||
public void UpdateWorldVertices()
|
||||
{
|
||||
if (Object.op_Equality((Object)this.bakedMesh, (Object)null))
|
||||
this.bakedMesh = new Mesh();
|
||||
else
|
||||
this.bakedMesh.Clear();
|
||||
this.smr.BakeMesh(this.bakedMesh);
|
||||
int vertexCount = this.editableMesh.vertexCount;
|
||||
Vector3 lossyScale = ((Component)this.smr).transform.lossyScale;
|
||||
Vector3 vector3_1;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3)ref vector3_1).\u002Ector(1f / Mathf.Max(lossyScale.x, 1E-08f), 1f / Mathf.Max(lossyScale.y, 1E-08f), 1f / Mathf.Max(lossyScale.z, 1E-08f));
|
||||
this.worldNoScale = Matrix4x4.op_Multiply(((Component)this.smr).transform.localToWorldMatrix, Matrix4x4.Scale(vector3_1));
|
||||
this.worldVertices = new Vector3[vertexCount];
|
||||
this.deltasLocal = new Vector3[vertexCount];
|
||||
for (int index = 0; index < vertexCount; ++index)
|
||||
{
|
||||
this.worldVertices[index] = ((Matrix4x4)ref this.worldNoScale).MultiplyPoint3x4(this.bakedMesh.vertices[index]);
|
||||
this.deltasLocal[index] = Vector3.zero;
|
||||
}
|
||||
Vector3[] normals = this.bakedMesh.normals;
|
||||
Vector4[] tangents = this.bakedMesh.tangents;
|
||||
this.bakedWorldNormals = new Vector3[vertexCount];
|
||||
this.bakedWorldTangents = tangents == null || tangents.Length != vertexCount ? (Vector4[])null : new Vector4[vertexCount];
|
||||
for (int index1 = 0; index1 < vertexCount; ++index1)
|
||||
{
|
||||
Vector3[] bakedWorldNormals = this.bakedWorldNormals;
|
||||
int index2 = index1;
|
||||
Vector3 vector3_2 = ((Component)this.smr).transform.TransformDirection(normals[index1]);
|
||||
Vector3 normalized1 = ((Vector3)ref vector3_2).normalized;
|
||||
bakedWorldNormals[index2] = normalized1;
|
||||
if (this.bakedWorldTangents != null)
|
||||
{
|
||||
vector3_2 = ((Component)this.smr).transform.TransformDirection(new Vector3(tangents[index1].x, tangents[index1].y, tangents[index1].z));
|
||||
Vector3 normalized2 = ((Vector3)ref vector3_2).normalized;
|
||||
this.bakedWorldTangents[index1] = new Vector4(normalized2.x, normalized2.y, normalized2.z, tangents[index1].w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<int>[] BuildVertexAdjacency(Mesh mesh, float seamThreshold = 0.0001f, float proximityThreshold = 0.0f)
|
||||
{
|
||||
int length = !Object.op_Equality((Object)mesh, (Object)null) ? mesh.vertexCount : throw new AutoMorpherException("Mesh is Missing", "[VertexAdjacencyUtil] BuildVertexAdjacency\n - mesh is null");
|
||||
int[] triangles = mesh.triangles;
|
||||
Vector3[] vertices = mesh.vertices;
|
||||
List<int>[] adj = new List<int>[length];
|
||||
for (int index = 0; index < length; ++index)
|
||||
adj[index] = new List<int>();
|
||||
int num1 = triangles.Length / 3;
|
||||
for (int index = 0; index < num1; ++index)
|
||||
{
|
||||
int num2 = triangles[index * 3];
|
||||
int num3 = triangles[index * 3 + 1];
|
||||
int num4 = triangles[index * 3 + 2];
|
||||
AddNeighbor(adj, num2, num3);
|
||||
AddNeighbor(adj, num3, num2);
|
||||
AddNeighbor(adj, num3, num4);
|
||||
AddNeighbor(adj, num4, num3);
|
||||
AddNeighbor(adj, num4, num2);
|
||||
AddNeighbor(adj, num2, num4);
|
||||
}
|
||||
if ((double)seamThreshold > 0.0)
|
||||
{
|
||||
float num5 = seamThreshold * 2f;
|
||||
float num6 = seamThreshold * seamThreshold;
|
||||
Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>();
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
Vector3 vector3 = vertices[index];
|
||||
Vector3Int key;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3Int)ref key).\u002Ector(Mathf.FloorToInt(vector3.x / num5), Mathf.FloorToInt(vector3.y / num5), Mathf.FloorToInt(vector3.z / num5));
|
||||
List<int> intList;
|
||||
if (!dictionary.TryGetValue(key, out intList))
|
||||
{
|
||||
intList = new List<int>();
|
||||
dictionary[key] = intList;
|
||||
}
|
||||
intList.Add(index);
|
||||
}
|
||||
foreach (KeyValuePair<Vector3Int, List<int>> keyValuePair in dictionary)
|
||||
{
|
||||
Vector3Int key1 = keyValuePair.Key;
|
||||
List<int> intList1 = keyValuePair.Value;
|
||||
for (int index1 = -1; index1 <= 1; ++index1)
|
||||
{
|
||||
for (int index2 = -1; index2 <= 1; ++index2)
|
||||
{
|
||||
for (int index3 = -1; index3 <= 1; ++index3)
|
||||
{
|
||||
if (index1 >= 0 && (index1 != 0 || index2 >= 0) && (index1 != 0 || index2 != 0 || index3 >= 0))
|
||||
{
|
||||
Vector3Int key2;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3Int)ref key2).\u002Ector(((Vector3Int)ref key1).x + index1, ((Vector3Int)ref key1).y + index2, ((Vector3Int)ref key1).z + index3);
|
||||
List<int> intList2;
|
||||
Vector3 vector3_1;
|
||||
if (dictionary.TryGetValue(key2, out intList2))
|
||||
{
|
||||
if (Vector3Int.op_Equality(key2, key1))
|
||||
{
|
||||
for (int index4 = 0; index4 < intList1.Count; ++index4)
|
||||
{
|
||||
int index5 = intList1[index4];
|
||||
Vector3 vector3_2 = vertices[index5];
|
||||
for (int index6 = index4 + 1; index6 < intList1.Count; ++index6)
|
||||
{
|
||||
int index7 = intList1[index6];
|
||||
vector3_1 = Vector3.op_Subtraction(vertices[index7], vector3_2);
|
||||
if ((double)((Vector3)ref vector3_1).sqrMagnitude <= (double)num6)
|
||||
{
|
||||
AddNeighbor(adj, index5, index7);
|
||||
AddNeighbor(adj, index7, index5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index8 = 0; index8 < intList1.Count; ++index8)
|
||||
{
|
||||
int index9 = intList1[index8];
|
||||
Vector3 vector3_3 = vertices[index9];
|
||||
for (int index10 = 0; index10 < intList2.Count; ++index10)
|
||||
{
|
||||
int index11 = intList2[index10];
|
||||
vector3_1 = Vector3.op_Subtraction(vertices[index11], vector3_3);
|
||||
if ((double)((Vector3)ref vector3_1).sqrMagnitude <= (double)num6)
|
||||
{
|
||||
AddNeighbor(adj, index9, index11);
|
||||
AddNeighbor(adj, index11, index9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((double)proximityThreshold > 0.0)
|
||||
{
|
||||
float num7 = proximityThreshold * 2f;
|
||||
float num8 = proximityThreshold * proximityThreshold;
|
||||
Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>();
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
Vector3 vector3 = vertices[index];
|
||||
Vector3Int key;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3Int)ref key).\u002Ector(Mathf.FloorToInt(vector3.x / num7), Mathf.FloorToInt(vector3.y / num7), Mathf.FloorToInt(vector3.z / num7));
|
||||
List<int> intList;
|
||||
if (!dictionary.TryGetValue(key, out intList))
|
||||
{
|
||||
intList = new List<int>();
|
||||
dictionary[key] = intList;
|
||||
}
|
||||
intList.Add(index);
|
||||
}
|
||||
foreach (KeyValuePair<Vector3Int, List<int>> keyValuePair in dictionary)
|
||||
{
|
||||
Vector3Int key3 = keyValuePair.Key;
|
||||
List<int> intList3 = keyValuePair.Value;
|
||||
for (int index12 = -1; index12 <= 1; ++index12)
|
||||
{
|
||||
for (int index13 = -1; index13 <= 1; ++index13)
|
||||
{
|
||||
for (int index14 = -1; index14 <= 1; ++index14)
|
||||
{
|
||||
if (index12 >= 0 && (index12 != 0 || index13 >= 0) && (index12 != 0 || index13 != 0 || index14 >= 0))
|
||||
{
|
||||
Vector3Int key4;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3Int)ref key4).\u002Ector(((Vector3Int)ref key3).x + index12, ((Vector3Int)ref key3).y + index13, ((Vector3Int)ref key3).z + index14);
|
||||
List<int> intList4;
|
||||
Vector3 vector3_4;
|
||||
if (dictionary.TryGetValue(key4, out intList4))
|
||||
{
|
||||
if (Vector3Int.op_Equality(key4, key3))
|
||||
{
|
||||
for (int index15 = 0; index15 < intList3.Count; ++index15)
|
||||
{
|
||||
int index16 = intList3[index15];
|
||||
Vector3 vector3_5 = vertices[index16];
|
||||
for (int index17 = index15 + 1; index17 < intList3.Count; ++index17)
|
||||
{
|
||||
int index18 = intList3[index17];
|
||||
vector3_4 = Vector3.op_Subtraction(vertices[index18], vector3_5);
|
||||
if ((double)((Vector3)ref vector3_4).sqrMagnitude <= (double)num8)
|
||||
{
|
||||
AddNeighbor(adj, index16, index18);
|
||||
AddNeighbor(adj, index18, index16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index19 = 0; index19 < intList3.Count; ++index19)
|
||||
{
|
||||
int index20 = intList3[index19];
|
||||
Vector3 vector3_6 = vertices[index20];
|
||||
for (int index21 = 0; index21 < intList4.Count; ++index21)
|
||||
{
|
||||
int index22 = intList4[index21];
|
||||
vector3_4 = Vector3.op_Subtraction(vertices[index22], vector3_6);
|
||||
if ((double)((Vector3)ref vector3_4).sqrMagnitude <= (double)num8)
|
||||
{
|
||||
AddNeighbor(adj, index20, index22);
|
||||
AddNeighbor(adj, index22, index20);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return adj;
|
||||
|
||||
static void AddNeighbor(List<int>[] adj, int from, int to)
|
||||
{
|
||||
List<int> intList = adj[from];
|
||||
if (intList.Contains(to))
|
||||
return;
|
||||
intList.Add(to);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyWorldVerticesToMesh()
|
||||
{
|
||||
if (Object.op_Equality((Object)this.editableMesh, (Object)null) || Object.op_Equality((Object)this.smr, (Object)null) || this.worldVertices == null)
|
||||
return;
|
||||
Mesh editableMesh = this.editableMesh;
|
||||
int vertexCount = editableMesh.vertexCount;
|
||||
Vector3[] vertices = editableMesh.vertices;
|
||||
SkinningUtil skinningUtil = new SkinningUtil();
|
||||
Vector3[] vector3Array1 = (Vector3[])null;
|
||||
int blendShapeCount = editableMesh.blendShapeCount;
|
||||
if (blendShapeCount > 0)
|
||||
{
|
||||
vector3Array1 = new Vector3[vertexCount];
|
||||
Vector3[] vector3Array2 = new Vector3[vertexCount];
|
||||
Vector3[] vector3Array3 = new Vector3[vertexCount];
|
||||
Vector3[] vector3Array4 = new Vector3[vertexCount];
|
||||
for (int index1 = 0; index1 < blendShapeCount; ++index1)
|
||||
{
|
||||
float blendShapeWeight = this.smr.GetBlendShapeWeight(index1);
|
||||
if (!Mathf.Approximately(blendShapeWeight, 0.0f))
|
||||
{
|
||||
int num1 = editableMesh.GetBlendShapeFrameCount(index1) - 1;
|
||||
float shapeFrameWeight = editableMesh.GetBlendShapeFrameWeight(index1, num1);
|
||||
editableMesh.GetBlendShapeFrameVertices(index1, num1, vector3Array2, vector3Array3, vector3Array4);
|
||||
float num2 = (double)shapeFrameWeight != 0.0 ? blendShapeWeight / shapeFrameWeight : 0.0f;
|
||||
if (!Mathf.Approximately(num2, 0.0f))
|
||||
{
|
||||
for (int index2 = 0; index2 < vertexCount; ++index2)
|
||||
{
|
||||
ref Vector3 local = ref vector3Array1[index2];
|
||||
local = Vector3.op_Addition(local, Vector3.op_Multiply(vector3Array2[index2], num2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex)
|
||||
{
|
||||
Vector3 vector3 = skinningUtil.WorldPosToBindPos_Full(this.smr, editableMesh, vertexIndex, this.worldVertices[vertexIndex]);
|
||||
if (vector3Array1 != null)
|
||||
vector3 = Vector3.op_Subtraction(vector3, vector3Array1[vertexIndex]);
|
||||
vertices[vertexIndex] = vector3;
|
||||
}
|
||||
editableMesh.vertices = vertices;
|
||||
Vector3[] vector3Array5 = (Vector3[])null;
|
||||
Vector3[] vector3Array6 = (Vector3[])null;
|
||||
if (blendShapeCount > 0)
|
||||
{
|
||||
vector3Array5 = new Vector3[vertexCount];
|
||||
vector3Array6 = new Vector3[vertexCount];
|
||||
Vector3[] vector3Array7 = new Vector3[vertexCount];
|
||||
Vector3[] vector3Array8 = new Vector3[vertexCount];
|
||||
Vector3[] vector3Array9 = new Vector3[vertexCount];
|
||||
for (int index3 = 0; index3 < blendShapeCount; ++index3)
|
||||
{
|
||||
float blendShapeWeight = this.smr.GetBlendShapeWeight(index3);
|
||||
if (!Mathf.Approximately(blendShapeWeight, 0.0f))
|
||||
{
|
||||
int num3 = editableMesh.GetBlendShapeFrameCount(index3) - 1;
|
||||
float shapeFrameWeight = editableMesh.GetBlendShapeFrameWeight(index3, num3);
|
||||
editableMesh.GetBlendShapeFrameVertices(index3, num3, vector3Array7, vector3Array8, vector3Array9);
|
||||
float num4 = (double)shapeFrameWeight != 0.0 ? blendShapeWeight / shapeFrameWeight : 0.0f;
|
||||
if (!Mathf.Approximately(num4, 0.0f))
|
||||
{
|
||||
for (int index4 = 0; index4 < vertexCount; ++index4)
|
||||
{
|
||||
ref Vector3 local1 = ref vector3Array5[index4];
|
||||
local1 = Vector3.op_Addition(local1, Vector3.op_Multiply(vector3Array8[index4], num4));
|
||||
ref Vector3 local2 = ref vector3Array6[index4];
|
||||
local2 = Vector3.op_Addition(local2, Vector3.op_Multiply(vector3Array9[index4], num4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.bakedWorldNormals == null || this.bakedWorldNormals.Length != vertexCount)
|
||||
return;
|
||||
Vector3[] vector3Array10 = new Vector3[vertexCount];
|
||||
bool flag = this.bakedWorldTangents != null && this.bakedWorldTangents.Length == vertexCount;
|
||||
Vector4[] vector4Array = flag ? new Vector4[vertexCount] : (Vector4[])null;
|
||||
for (int vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex)
|
||||
{
|
||||
Vector3 vector3_1 = skinningUtil.WorldDirToBindDir_Full(this.smr, editableMesh, vertexIndex, this.bakedWorldNormals[vertexIndex]);
|
||||
if (vector3Array5 != null)
|
||||
vector3_1 = Vector3.op_Subtraction(vector3_1, vector3Array5[vertexIndex]);
|
||||
vector3Array10[vertexIndex] = ((Vector3)ref vector3_1).normalized;
|
||||
if (flag)
|
||||
{
|
||||
Vector3 targetWorldDir;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3)ref targetWorldDir).\u002Ector(this.bakedWorldTangents[vertexIndex].x, this.bakedWorldTangents[vertexIndex].y, this.bakedWorldTangents[vertexIndex].z);
|
||||
Vector3 vector3_2 = skinningUtil.WorldDirToBindDir_Full(this.smr, editableMesh, vertexIndex, targetWorldDir);
|
||||
if (vector3Array6 != null)
|
||||
vector3_2 = Vector3.op_Subtraction(vector3_2, vector3Array6[vertexIndex]);
|
||||
vector3_2 = ((Vector3)ref vector3_2).normalized;
|
||||
vector4Array[vertexIndex] = new Vector4(vector3_2.x, vector3_2.y, vector3_2.z, this.bakedWorldTangents[vertexIndex].w);
|
||||
}
|
||||
}
|
||||
editableMesh.normals = vector3Array10;
|
||||
if (vector4Array == null)
|
||||
return;
|
||||
editableMesh.tangents = vector4Array;
|
||||
}
|
||||
|
||||
public void BuildEquivalentVerticesFromWorld(float maxDistance = 1E-05f)
|
||||
{
|
||||
if (this.worldVertices == null || this.worldVertices.Length == 0)
|
||||
{
|
||||
Debug.LogWarning((object)"[ClothInstance] BuildEquivalentVerticesFromWorld: worldVertices is null or empty. Call UpdateWorldVertices() first.");
|
||||
}
|
||||
else
|
||||
{
|
||||
int length = this.worldVertices.Length;
|
||||
if (this.equivalentVertices == null)
|
||||
this.equivalentVertices = new List<List<int>>();
|
||||
else
|
||||
this.equivalentVertices.Clear();
|
||||
float num1 = maxDistance;
|
||||
float num2 = maxDistance * maxDistance;
|
||||
Dictionary<Vector3Int, List<int>> dictionary1 = new Dictionary<Vector3Int, List<int>>();
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
Vector3 worldVertex = this.worldVertices[index];
|
||||
Vector3Int key;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3Int)ref key).\u002Ector(Mathf.FloorToInt(worldVertex.x / num1), Mathf.FloorToInt(worldVertex.y / num1), Mathf.FloorToInt(worldVertex.z / num1));
|
||||
List<int> intList;
|
||||
if (!dictionary1.TryGetValue(key, out intList))
|
||||
{
|
||||
intList = new List<int>();
|
||||
dictionary1[key] = intList;
|
||||
}
|
||||
intList.Add(index);
|
||||
}
|
||||
foreach (KeyValuePair<Vector3Int, List<int>> keyValuePair in dictionary1)
|
||||
{
|
||||
List<int> intList1 = keyValuePair.Value;
|
||||
int count = intList1.Count;
|
||||
if (count >= 2)
|
||||
{
|
||||
int[] parent = new int[count];
|
||||
for (int index = 0; index < count; ++index)
|
||||
parent[index] = index;
|
||||
for (int index1 = 0; index1 < count; ++index1)
|
||||
{
|
||||
Vector3 worldVertex1 = this.worldVertices[intList1[index1]];
|
||||
for (int index2 = index1 + 1; index2 < count; ++index2)
|
||||
{
|
||||
Vector3 worldVertex2 = this.worldVertices[intList1[index2]];
|
||||
Vector3 vector3 = Vector3.op_Subtraction(worldVertex1, worldVertex2);
|
||||
if ((double)((Vector3)ref vector3).sqrMagnitude <= (double)num2)
|
||||
Union(index1, index2);
|
||||
}
|
||||
}
|
||||
Dictionary<int, List<int>> dictionary2 = new Dictionary<int, List<int>>();
|
||||
for (int index = 0; index < count; ++index)
|
||||
{
|
||||
int key = Find(index);
|
||||
List<int> intList2;
|
||||
if (!dictionary2.TryGetValue(key, out intList2))
|
||||
{
|
||||
intList2 = new List<int>();
|
||||
dictionary2[key] = intList2;
|
||||
}
|
||||
intList2.Add(intList1[index]);
|
||||
}
|
||||
foreach (List<int> intList3 in dictionary2.Values)
|
||||
{
|
||||
if (intList3.Count >= 2)
|
||||
this.equivalentVertices.Add(intList3);
|
||||
}
|
||||
|
||||
int Find(int x)
|
||||
{
|
||||
if (parent[x] != x)
|
||||
parent[x] = Find(parent[x]);
|
||||
return parent[x];
|
||||
}
|
||||
|
||||
void Union(int a, int b)
|
||||
{
|
||||
int num = Find(a);
|
||||
int index = Find(b);
|
||||
if (num == index)
|
||||
return;
|
||||
parent[index] = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~ClothInstance() => this.Dispose();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Object.op_Inequality((Object)this.bakedMesh, (Object)null))
|
||||
{
|
||||
Object.DestroyImmediate((Object)this.bakedMesh);
|
||||
this.bakedMesh = (Mesh)null;
|
||||
}
|
||||
this.worldVertices = (Vector3[])null;
|
||||
this.minDistanceVector = (Vector3[])null;
|
||||
this.minDistance = (float[])null;
|
||||
this.deltas = (Vector3[])null;
|
||||
this.deltasLocal = (Vector3[])null;
|
||||
this.isInsideVertex = (bool[])null;
|
||||
this.excludedVertices = (bool[])null;
|
||||
this.isLeftLegVertex = (bool[])null;
|
||||
this.isRightLegVertex = (bool[])null;
|
||||
this.vertexAdjacency = (List<int>[])null;
|
||||
if (this.equivalentVertices != null)
|
||||
{
|
||||
for (int index = 0; index < this.equivalentVertices.Count; ++index)
|
||||
this.equivalentVertices[index]?.Clear();
|
||||
this.equivalentVertices.Clear();
|
||||
this.equivalentVertices = (List<List<int>>)null;
|
||||
}
|
||||
this.humanoidMatchedBones = (Dictionary<HumanBodyBones, HashSet<Transform>>)null;
|
||||
this.smr = (SkinnedMeshRenderer)null;
|
||||
this.editableMesh = (Mesh)null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7baaee02374c83c47924c148c233808f
|
||||
283
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs
Normal file
283
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs
Normal file
@@ -0,0 +1,283 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.ClothInstanceTotal
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class ClothInstanceTotal
|
||||
{
|
||||
private readonly List<ClothInstance> clothInstances;
|
||||
|
||||
public int TotalVertexCount { get; private set; }
|
||||
|
||||
public Vector3[] GlobalPositions { get; private set; }
|
||||
|
||||
public Vector3[] GlobalDeltas { get; private set; }
|
||||
|
||||
public List<int>[] GlobalAdjacencyTopology { get; private set; }
|
||||
|
||||
public List<int>[] GlobalAdjacencyDistance { get; private set; }
|
||||
|
||||
public List<int>[] GlobalAdjacencyMerged { 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 ((double)distanceBuildRadius <= 0.0)
|
||||
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 != this.TotalVertexCount)
|
||||
throw new AutoMorpherException("Global Deltas are Invalid", "[ClothInstanceTotal] SetGlobalDeltas\n - globalDeltas is null or length mismatch");
|
||||
this.GlobalDeltas = globalDeltas;
|
||||
}
|
||||
|
||||
public void UpdateGlobalBuffersFromClothInstances()
|
||||
{
|
||||
this.ValidateGlobalBufferReady("[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances");
|
||||
for (int index1 = 0; index1 < this.clothInstances.Count; ++index1)
|
||||
{
|
||||
ClothInstance clothInstance = this.clothInstances[index1];
|
||||
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 vertexOffset = this.VertexOffsets[index1];
|
||||
int length = clothInstance.worldVertices.Length;
|
||||
if (length != clothInstance.deltasLocal.Length)
|
||||
throw new AutoMorpherException("Cloth Instance Array Length Mismatch", "[ClothInstanceTotal] UpdateGlobalBuffersFromClothInstances\n - worldVertices.Length != deltasLocal.Length");
|
||||
for (int index2 = 0; index2 < length; ++index2)
|
||||
{
|
||||
this.GlobalPositions[vertexOffset + index2] = clothInstance.worldVertices[index2];
|
||||
this.GlobalDeltas[vertexOffset + index2] = clothInstance.deltasLocal[index2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyGlobalDeltasToClothInstances()
|
||||
{
|
||||
this.ValidateGlobalBufferReady("[ClothInstanceTotal] ApplyGlobalDeltasToClothInstances");
|
||||
for (int index1 = 0; index1 < this.clothInstances.Count; ++index1)
|
||||
{
|
||||
ClothInstance clothInstance = this.clothInstances[index1];
|
||||
if (clothInstance != null)
|
||||
{
|
||||
if (clothInstance.deltasLocal == null)
|
||||
throw new AutoMorpherException("Cloth Deltas are Missing", "[ClothInstanceTotal] ApplyGlobalDeltasToClothInstances\n - deltasLocal is null");
|
||||
int vertexOffset = this.VertexOffsets[index1];
|
||||
int length = clothInstance.deltasLocal.Length;
|
||||
for (int index2 = 0; index2 < length; ++index2)
|
||||
clothInstance.deltasLocal[index2] = this.GlobalDeltas[vertexOffset + index2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
this.TotalVertexCount = this.CalculateTotalVertexCount(this.clothInstances);
|
||||
this.GlobalPositions = this.TotalVertexCount > 0 ? new Vector3[this.TotalVertexCount] : throw new AutoMorpherException("Total Vertex Count is Zero", "[ClothInstanceTotal] BuildTopologyCache\n - TotalVertexCount <= 0");
|
||||
this.GlobalDeltas = new Vector3[this.TotalVertexCount];
|
||||
this.GlobalAdjacencyTopology = new List<int>[this.TotalVertexCount];
|
||||
this.VertexOffsets = new int[this.clothInstances.Count];
|
||||
int num1 = 0;
|
||||
for (int index1 = 0; index1 < this.clothInstances.Count; ++index1)
|
||||
{
|
||||
ClothInstance clothInstance = this.clothInstances[index1];
|
||||
this.VertexOffsets[index1] = num1;
|
||||
if (clothInstance != null)
|
||||
{
|
||||
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 length = clothInstance.worldVertices.Length;
|
||||
if (length != clothInstance.deltasLocal.Length || length != clothInstance.vertexAdjacency.Length)
|
||||
throw new AutoMorpherException("Cloth Instance Array Length Mismatch", "[ClothInstanceTotal] BuildTopologyCache\n - worldVertices/deltasLocal/vertexAdjacency lengths differ");
|
||||
for (int index2 = 0; index2 < length; ++index2)
|
||||
{
|
||||
this.GlobalPositions[num1 + index2] = clothInstance.worldVertices[index2];
|
||||
this.GlobalDeltas[num1 + index2] = clothInstance.deltasLocal[index2];
|
||||
List<int> intList = clothInstance.vertexAdjacency[index2];
|
||||
// ISSUE: explicit non-virtual call
|
||||
int count = intList != null ? __nonvirtual(intList.Count) : 0;
|
||||
this.GlobalAdjacencyTopology[num1 + index2] = new List<int>(count);
|
||||
}
|
||||
for (int index3 = 0; index3 < length; ++index3)
|
||||
{
|
||||
List<int> intList1 = clothInstance.vertexAdjacency[index3];
|
||||
if (intList1 != null)
|
||||
{
|
||||
List<int> intList2 = this.GlobalAdjacencyTopology[num1 + index3];
|
||||
for (int index4 = 0; index4 < intList1.Count; ++index4)
|
||||
{
|
||||
int num2 = intList1[index4];
|
||||
if ((uint)num2 >= (uint)length)
|
||||
throw new AutoMorpherException("Vertex Adjacency Index is Out of Range", "[ClothInstanceTotal] BuildTopologyCache\n - vertexAdjacency contains invalid neighbor index");
|
||||
intList2.Add(num1 + num2);
|
||||
}
|
||||
}
|
||||
}
|
||||
num1 += length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (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 length = this.GlobalAdjacencyTopology.Length;
|
||||
this.GlobalAdjacencyMerged = new List<int>[length];
|
||||
for (int index1 = 0; index1 < length; ++index1)
|
||||
{
|
||||
List<int> intList1 = this.GlobalAdjacencyTopology[index1];
|
||||
// ISSUE: explicit non-virtual call
|
||||
int count1 = intList1 != null ? __nonvirtual(intList1.Count) : 0;
|
||||
List<int> intList2 = this.GlobalAdjacencyDistance[index1];
|
||||
// ISSUE: explicit non-virtual call
|
||||
int count2 = intList2 != null ? __nonvirtual(intList2.Count) : 0;
|
||||
List<int> intList3 = new List<int>(count1 + count2);
|
||||
HashSet<int> intSet = new HashSet<int>();
|
||||
List<int> intList4 = this.GlobalAdjacencyTopology[index1];
|
||||
if (intList4 != null)
|
||||
{
|
||||
for (int index2 = 0; index2 < intList4.Count; ++index2)
|
||||
{
|
||||
int num = intList4[index2];
|
||||
if (num != index1 && intSet.Add(num))
|
||||
intList3.Add(num);
|
||||
}
|
||||
}
|
||||
List<int> intList5 = this.GlobalAdjacencyDistance[index1];
|
||||
if (intList5 != null)
|
||||
{
|
||||
for (int index3 = 0; index3 < intList5.Count; ++index3)
|
||||
{
|
||||
int num = intList5[index3];
|
||||
if (num != index1 && intSet.Add(num))
|
||||
intList3.Add(num);
|
||||
}
|
||||
}
|
||||
this.GlobalAdjacencyMerged[index1] = intList3;
|
||||
}
|
||||
}
|
||||
|
||||
private int CalculateTotalVertexCount(List<ClothInstance> clothInstances)
|
||||
{
|
||||
int totalVertexCount = 0;
|
||||
for (int index = 0; index < clothInstances.Count; ++index)
|
||||
{
|
||||
ClothInstance clothInstance = clothInstances[index];
|
||||
if (clothInstance != null && clothInstance.worldVertices != null)
|
||||
totalVertexCount += clothInstance.worldVertices.Length;
|
||||
}
|
||||
return totalVertexCount;
|
||||
}
|
||||
|
||||
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 ((double)radius <= 0.0)
|
||||
throw new AutoMorpherException("Radius is Invalid", "[ClothInstanceTotal] BuildDistanceAdjacencyCandidatesInternal\n - radius must be > 0");
|
||||
int length = referencePositions.Length;
|
||||
List<int>[] intListArray = new List<int>[length];
|
||||
for (int index = 0; index < length; ++index)
|
||||
intListArray[index] = new List<int>(8);
|
||||
float num1 = 1f / Mathf.Max(radius, 1E-12f);
|
||||
float num2 = radius * radius;
|
||||
Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>(length);
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
Vector3 referencePosition = referencePositions[index];
|
||||
Vector3Int key;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3Int)ref key).\u002Ector(Mathf.FloorToInt(referencePosition.x * num1), Mathf.FloorToInt(referencePosition.y * num1), Mathf.FloorToInt(referencePosition.z * num1));
|
||||
List<int> intList;
|
||||
if (!dictionary.TryGetValue(key, out intList))
|
||||
{
|
||||
intList = new List<int>(16 /*0x10*/);
|
||||
dictionary.Add(key, intList);
|
||||
}
|
||||
intList.Add(index);
|
||||
}
|
||||
for (int index1 = 0; index1 < length; ++index1)
|
||||
{
|
||||
Vector3 referencePosition = referencePositions[index1];
|
||||
Vector3Int vector3Int;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3Int)ref vector3Int).\u002Ector(Mathf.FloorToInt(referencePosition.x * num1), Mathf.FloorToInt(referencePosition.y * num1), Mathf.FloorToInt(referencePosition.z * num1));
|
||||
List<int> intList1 = intListArray[index1];
|
||||
for (int index2 = -1; index2 <= 1; ++index2)
|
||||
{
|
||||
for (int index3 = -1; index3 <= 1; ++index3)
|
||||
{
|
||||
for (int index4 = -1; index4 <= 1; ++index4)
|
||||
{
|
||||
Vector3Int key;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3Int)ref key).\u002Ector(((Vector3Int)ref vector3Int).x + index2, ((Vector3Int)ref vector3Int).y + index3, ((Vector3Int)ref vector3Int).z + index4);
|
||||
List<int> intList2;
|
||||
if (dictionary.TryGetValue(key, out intList2))
|
||||
{
|
||||
for (int index5 = 0; index5 < intList2.Count; ++index5)
|
||||
{
|
||||
int index6 = intList2[index5];
|
||||
if (index6 != index1)
|
||||
{
|
||||
Vector3 vector3 = Vector3.op_Subtraction(referencePositions[index6], referencePosition);
|
||||
if ((double)((Vector3)ref vector3).sqrMagnitude <= (double)num2)
|
||||
{
|
||||
intList1.Add(index6);
|
||||
if (maxNeighborsPerVertex > 0 && intList1.Count >= maxNeighborsPerVertex)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxNeighborsPerVertex > 0 && intList1.Count >= maxNeighborsPerVertex)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return intListArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3515d0fa4131c9439e99aec94e163bb
|
||||
575
Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs
Normal file
575
Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs
Normal file
@@ -0,0 +1,575 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.EdenAutoMorpher
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class EdenAutoMorpher : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
public GameObject sourceAvatarObject;
|
||||
[SerializeField]
|
||||
public GameObject sourceClothesObject;
|
||||
[SerializeField]
|
||||
private List<SkinnedMeshRenderer> sourceBodyMeshes = new List<SkinnedMeshRenderer>();
|
||||
[SerializeField]
|
||||
private IReadOnlyList<SkinnedMeshRenderer> sourceBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)new List<SkinnedMeshRenderer>();
|
||||
[SerializeField]
|
||||
public string profileName;
|
||||
[SerializeField]
|
||||
public GameObject targetAvatarObject;
|
||||
[SerializeField]
|
||||
private GameObject targetClothesObject;
|
||||
[SerializeField]
|
||||
private GameObject targetClothesObjectOriginal;
|
||||
[SerializeField]
|
||||
private List<SkinnedMeshRenderer> targetBodyMeshes = new List<SkinnedMeshRenderer>();
|
||||
[SerializeField]
|
||||
private IReadOnlyList<SkinnedMeshRenderer> targetBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)new List<SkinnedMeshRenderer>();
|
||||
[SerializeField]
|
||||
private float minMargin = 3f / 1000f;
|
||||
[SerializeField]
|
||||
private float worldRadius = 0.1f;
|
||||
[SerializeField]
|
||||
private float sigma = 0.85f;
|
||||
[SerializeField]
|
||||
private int smoothingIteration = 1;
|
||||
[SerializeField]
|
||||
private int fittingExpandIteration = 10;
|
||||
[SerializeField]
|
||||
private int fittingShrinkIteration = 12;
|
||||
[SerializeField]
|
||||
public bool isBodyAutoSetup = true;
|
||||
[SerializeField]
|
||||
public bool isReparentAccessoryBonesToTargetAvatar = true;
|
||||
[SerializeField]
|
||||
public bool skipFootFitting;
|
||||
[SerializeField]
|
||||
public bool transferWeightToAvatar;
|
||||
[SerializeField]
|
||||
public bool addAnchorBone = true;
|
||||
[SerializeField]
|
||||
public bool armatureBoneScaleCopy;
|
||||
[SerializeField]
|
||||
public bool isRemoveAutoMorphedClothes = true;
|
||||
private Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones;
|
||||
private Dictionary<Transform, ClothBoneType> clothBoneTypeMap;
|
||||
private GameObject fittedTargetAvatar;
|
||||
private GameObject fittedTargetClothes;
|
||||
private const string EditedMeshRootFolder = "Assets/@Eden_Mesh";
|
||||
private string tagEdenMorpehrCloth = "EDENAutoMorpher_EditedCloth";
|
||||
private bool doProcess;
|
||||
private MorpherMode morpherMode;
|
||||
private MorpherState morpherState;
|
||||
private ProcessInfo processInfo;
|
||||
|
||||
public ProcessInfo GetProcessInfo() => this.processInfo;
|
||||
|
||||
public void ChangeMode(MorpherMode newMode)
|
||||
{
|
||||
this.morpherMode = newMode;
|
||||
this.morpherState = MorpherState.Idle;
|
||||
}
|
||||
|
||||
public void StopProcess()
|
||||
{
|
||||
this.doProcess = false;
|
||||
switch (this.morpherState)
|
||||
{
|
||||
case MorpherState.Fitting_Doing:
|
||||
this.morpherState = MorpherState.Idle;
|
||||
break;
|
||||
case MorpherState.Weighting_Doing:
|
||||
this.morpherState = MorpherState.Fitting_End;
|
||||
break;
|
||||
default:
|
||||
this.morpherState = MorpherState.Idle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private EdenAutoMorpherConfig SetupConfigData(MorpherMode morpherMode)
|
||||
{
|
||||
EdenAutoMorpherConfig autoMorpherConfig = new EdenAutoMorpherConfig();
|
||||
switch (morpherMode)
|
||||
{
|
||||
case MorpherMode.AutoMorpher:
|
||||
case MorpherMode.ManualMorpher:
|
||||
autoMorpherConfig.sourceAvatarObject = this.sourceAvatarObject;
|
||||
autoMorpherConfig.sourceClothesObject = this.sourceClothesObject;
|
||||
autoMorpherConfig.sourceBodyMeshes = this.sourceBodyMeshesReadOnly;
|
||||
autoMorpherConfig.profileName = string.Empty;
|
||||
break;
|
||||
case MorpherMode.ProfileMorpher:
|
||||
autoMorpherConfig.sourceAvatarObject = (GameObject)null;
|
||||
autoMorpherConfig.sourceClothesObject = this.sourceClothesObject;
|
||||
autoMorpherConfig.sourceBodyMeshes = (IReadOnlyList<SkinnedMeshRenderer>)null;
|
||||
autoMorpherConfig.profileName = this.profileName;
|
||||
break;
|
||||
default:
|
||||
autoMorpherConfig.sourceAvatarObject = (GameObject)null;
|
||||
autoMorpherConfig.sourceClothesObject = (GameObject)null;
|
||||
autoMorpherConfig.sourceBodyMeshes = (IReadOnlyList<SkinnedMeshRenderer>)null;
|
||||
autoMorpherConfig.profileName = string.Empty;
|
||||
break;
|
||||
}
|
||||
autoMorpherConfig.targetAvatarObject = this.targetAvatarObject;
|
||||
autoMorpherConfig.targetClothesObject = this.targetClothesObject;
|
||||
autoMorpherConfig.targetBodyMeshes = this.targetBodyMeshesReadOnly;
|
||||
autoMorpherConfig.minMargin = this.minMargin;
|
||||
autoMorpherConfig.worldRadius = this.worldRadius;
|
||||
autoMorpherConfig.sigma = this.sigma;
|
||||
autoMorpherConfig.smoothingIteration = this.smoothingIteration;
|
||||
autoMorpherConfig.fittingExpandIteration = this.fittingExpandIteration;
|
||||
autoMorpherConfig.fittingShrinkIteration = this.fittingShrinkIteration;
|
||||
autoMorpherConfig.isBodyAutoSetup = this.isBodyAutoSetup;
|
||||
autoMorpherConfig.isReparentAccessoryBonesToTargetAvatar = this.isReparentAccessoryBonesToTargetAvatar;
|
||||
autoMorpherConfig.skipFootFitting = this.skipFootFitting;
|
||||
autoMorpherConfig.clothesHumanoidMatchedBones = this.clothesHumanoidMatchedBones;
|
||||
autoMorpherConfig.clothBoneTypeMap = this.clothBoneTypeMap;
|
||||
autoMorpherConfig.tagEdenMorpehrCloth = this.tagEdenMorpehrCloth;
|
||||
autoMorpherConfig.transferWeightToAvatar = this.transferWeightToAvatar;
|
||||
autoMorpherConfig.addAnchorBone = this.addAnchorBone;
|
||||
autoMorpherConfig.armatureBoneScaleCopy = this.armatureBoneScaleCopy;
|
||||
autoMorpherConfig.isRemoveAutoMorphedClothes = this.isRemoveAutoMorphedClothes;
|
||||
return autoMorpherConfig;
|
||||
}
|
||||
|
||||
public void AutoPoseSetup(MorpherMode morpherMode)
|
||||
{
|
||||
TransformInfo transformInfo1 = new TransformInfo(this.sourceAvatarObject.transform);
|
||||
TransformInfo transformInfo2 = new TransformInfo(this.targetAvatarObject.transform);
|
||||
try
|
||||
{
|
||||
EdenAutoMorpher_SetUpUtil morpherSetUpUtil = new EdenAutoMorpher_SetUpUtil();
|
||||
this.sourceBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)morpherSetUpUtil.SetupBodyMeshes(this.sourceAvatarObject, this.isBodyAutoSetup, this.sourceBodyMeshes, "Source ").AsReadOnly();
|
||||
this.targetBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)morpherSetUpUtil.SetupBodyMeshes(this.targetAvatarObject, this.isBodyAutoSetup, this.targetBodyMeshes, "Target ").AsReadOnly();
|
||||
this.targetAvatarObject.transform.SetParent((Transform)null, true);
|
||||
this.targetAvatarObject.transform.localRotation = Quaternion.identity;
|
||||
this.sourceAvatarObject.transform.SetParent((Transform)null, true);
|
||||
this.sourceAvatarObject.transform.localRotation = Quaternion.identity;
|
||||
EdenAutoMorpherConfig config = this.SetupConfigData(morpherMode);
|
||||
new EdenAutoMorpher_SetUpUtil().AutoSetup(ref config, out this.clothesHumanoidMatchedBones, out this.clothBoneTypeMap);
|
||||
this.targetClothesObject = config.targetClothesObject;
|
||||
this.targetClothesObjectOriginal = this.targetClothesObject;
|
||||
}
|
||||
finally
|
||||
{
|
||||
transformInfo1.ApplyToTransform(this.sourceAvatarObject.transform, true, false, true, true);
|
||||
transformInfo2.ApplyToTransform(this.targetAvatarObject.transform, true, false, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void ProfileSetup(MorpherMode morpherMode)
|
||||
{
|
||||
TransformInfo transformInfo1 = new TransformInfo(this.sourceClothesObject.transform);
|
||||
TransformInfo transformInfo2 = new TransformInfo(this.targetAvatarObject.transform);
|
||||
try
|
||||
{
|
||||
this.targetBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)new EdenAutoMorpher_SetUpUtil().SetupBodyMeshes(this.targetAvatarObject, this.isBodyAutoSetup, this.targetBodyMeshes, "Target ").AsReadOnly();
|
||||
this.targetAvatarObject.transform.SetParent((Transform)null, true);
|
||||
this.targetAvatarObject.transform.localRotation = Quaternion.identity;
|
||||
this.sourceClothesObject.transform.SetParent((Transform)null, true);
|
||||
this.sourceClothesObject.transform.localScale = Vector3.one;
|
||||
this.sourceClothesObject.transform.localRotation = Quaternion.identity;
|
||||
EdenAutoMorpherConfig config = this.SetupConfigData(morpherMode);
|
||||
new EdenAutoMorpher_SetUpUtil().ProfileAutoSetup(ref config, out this.clothesHumanoidMatchedBones, out this.clothBoneTypeMap);
|
||||
this.targetClothesObject = config.targetClothesObject;
|
||||
this.targetClothesObjectOriginal = this.targetClothesObject;
|
||||
}
|
||||
finally
|
||||
{
|
||||
transformInfo1.ApplyToTransform(this.sourceClothesObject.transform, true, false, true, true);
|
||||
transformInfo2.ApplyToTransform(this.targetAvatarObject.transform, true, false, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator AutoMorphingEnumerator(MorpherMode morpherMode)
|
||||
{
|
||||
this.doProcess = true;
|
||||
yield return (object)null;
|
||||
this.ProcessInfoDebug(morpherMode, "Run ALL");
|
||||
this.morpherState = MorpherState.Fitting_Doing;
|
||||
IEnumerator fitEnum = (IEnumerator)null;
|
||||
this.morpherMode = morpherMode;
|
||||
yield return (object)null;
|
||||
Debug.Log((object)"[Eden Auto Morpher] Run ALL - Start Fitting");
|
||||
switch (morpherMode)
|
||||
{
|
||||
case MorpherMode.AutoMorpher:
|
||||
fitEnum = this.AutoFitting(morpherMode);
|
||||
break;
|
||||
case MorpherMode.ManualMorpher:
|
||||
fitEnum = this.ManualFitting(morpherMode);
|
||||
break;
|
||||
case MorpherMode.ProfileMorpher:
|
||||
fitEnum = this.ProfileFitting(morpherMode);
|
||||
break;
|
||||
default:
|
||||
Debug.LogError((object)"Unknown Mode Index");
|
||||
break;
|
||||
}
|
||||
while (fitEnum != null && fitEnum.MoveNext() && this.doProcess)
|
||||
yield return fitEnum.Current;
|
||||
this.morpherState = MorpherState.Fitting_End;
|
||||
yield return (object)null;
|
||||
this.morpherState = MorpherState.Weighting_Doing;
|
||||
yield return (object)null;
|
||||
Debug.Log((object)"[Eden Auto Morpher] Run ALL - Start Weighting");
|
||||
using (EdenAutoMorpherManager eamManager = new EdenAutoMorpherManager())
|
||||
{
|
||||
IEnumerator eamFitting = eamManager.WeightingEnumerator(this.SetupConfigData(morpherMode));
|
||||
while (eamFitting.MoveNext() && this.doProcess)
|
||||
{
|
||||
ref string local1 = ref this.processInfo.title;
|
||||
ref string local2 = ref this.processInfo.text;
|
||||
ref float local3 = ref this.processInfo.progress;
|
||||
(string, string, float) progressInfo = eamManager.GetProgressInfo();
|
||||
local1 = progressInfo.Item1;
|
||||
local2 = progressInfo.Item2;
|
||||
double num = (double)progressInfo.Item3;
|
||||
local3 = (float)num;
|
||||
yield return eamFitting.Current;
|
||||
}
|
||||
eamFitting = (IEnumerator)null;
|
||||
}
|
||||
yield return (object)null;
|
||||
this.doProcess = false;
|
||||
this.morpherState = MorpherState.Idle;
|
||||
Debug.Log((object)"[Eden Auto Morpher] Ended Run ALL");
|
||||
yield return (object)null;
|
||||
}
|
||||
|
||||
public IEnumerator FittingEnumerator(MorpherMode morpherMode)
|
||||
{
|
||||
this.doProcess = true;
|
||||
ref string local1 = ref this.processInfo.title;
|
||||
ref string local2 = ref this.processInfo.text;
|
||||
ref float local3 = ref this.processInfo.progress;
|
||||
local1 = "Setup Avatar Pose";
|
||||
local2 = "Calculating avatar shape and skeletal data.";
|
||||
local3 = 0.0f;
|
||||
yield return (object)null;
|
||||
this.ProcessInfoDebug(morpherMode, "Fitting");
|
||||
yield return (object)null;
|
||||
this.morpherState = MorpherState.Fitting_Doing;
|
||||
IEnumerator fitEnum = (IEnumerator)null;
|
||||
this.morpherMode = morpherMode;
|
||||
yield return (object)null;
|
||||
switch (morpherMode)
|
||||
{
|
||||
case MorpherMode.AutoMorpher:
|
||||
fitEnum = this.AutoFitting(morpherMode);
|
||||
break;
|
||||
case MorpherMode.ManualMorpher:
|
||||
fitEnum = this.ManualFitting(morpherMode);
|
||||
break;
|
||||
case MorpherMode.ProfileMorpher:
|
||||
fitEnum = this.ProfileFitting(morpherMode);
|
||||
break;
|
||||
default:
|
||||
Debug.LogError((object)"Unknown Mode Index");
|
||||
break;
|
||||
}
|
||||
while (fitEnum != null && fitEnum.MoveNext() && this.doProcess)
|
||||
yield return (object)null;
|
||||
this.morpherState = MorpherState.Fitting_End;
|
||||
yield return (object)null;
|
||||
this.doProcess = false;
|
||||
Debug.Log((object)"[Eden Auto Morpher] Ended Fitting");
|
||||
yield return (object)null;
|
||||
}
|
||||
|
||||
public IEnumerator WeightingEnumerator()
|
||||
{
|
||||
this.morpherState = MorpherState.Weighting_Doing;
|
||||
this.doProcess = true;
|
||||
yield return (object)null;
|
||||
this.ProcessInfoDebug(this.morpherMode, "Weighting");
|
||||
using (EdenAutoMorpherManager eamManager = new EdenAutoMorpherManager())
|
||||
{
|
||||
IEnumerator eamFitting = eamManager.WeightingEnumerator(this.SetupConfigData(MorpherMode.ETC));
|
||||
while (eamFitting.MoveNext() && this.doProcess)
|
||||
{
|
||||
ref string local1 = ref this.processInfo.title;
|
||||
ref string local2 = ref this.processInfo.text;
|
||||
ref float local3 = ref this.processInfo.progress;
|
||||
(string, string, float) progressInfo = eamManager.GetProgressInfo();
|
||||
local1 = progressInfo.Item1;
|
||||
local2 = progressInfo.Item2;
|
||||
double num = (double)progressInfo.Item3;
|
||||
local3 = (float)num;
|
||||
yield return eamFitting.Current;
|
||||
}
|
||||
eamFitting = (IEnumerator)null;
|
||||
}
|
||||
yield return (object)null;
|
||||
this.doProcess = false;
|
||||
this.morpherState = MorpherState.Idle;
|
||||
Debug.Log((object)"[Eden Auto Morpher] Ended Weighting");
|
||||
yield return (object)null;
|
||||
}
|
||||
|
||||
public IEnumerator AutoFitting(MorpherMode morpherMode)
|
||||
{
|
||||
TransformInfo sourceAvatarInfo = new TransformInfo(this.sourceAvatarObject.transform);
|
||||
TransformInfo targetAvatarInfo = new TransformInfo(this.targetAvatarObject.transform);
|
||||
try
|
||||
{
|
||||
EdenAutoMorpher_SetUpUtil morpherSetUpUtil = new EdenAutoMorpher_SetUpUtil();
|
||||
this.sourceBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)morpherSetUpUtil.SetupBodyMeshes(this.sourceAvatarObject, this.isBodyAutoSetup, this.sourceBodyMeshes, "Source ").AsReadOnly();
|
||||
this.targetBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)morpherSetUpUtil.SetupBodyMeshes(this.targetAvatarObject, this.isBodyAutoSetup, this.targetBodyMeshes, "Target ").AsReadOnly();
|
||||
this.targetAvatarObject.transform.SetParent((Transform)null, true);
|
||||
this.targetAvatarObject.transform.localRotation = Quaternion.identity;
|
||||
this.sourceAvatarObject.transform.SetParent((Transform)null, true);
|
||||
this.sourceAvatarObject.transform.localRotation = Quaternion.identity;
|
||||
EdenAutoMorpherConfig configData = this.SetupConfigData(morpherMode);
|
||||
new EdenAutoMorpher_SetUpUtil().AutoSetup(ref configData, out this.clothesHumanoidMatchedBones, out this.clothBoneTypeMap);
|
||||
this.targetClothesObject = configData.targetClothesObject;
|
||||
this.targetClothesObjectOriginal = this.targetClothesObject;
|
||||
yield return (object)null;
|
||||
this.fittedTargetAvatar = (GameObject)null;
|
||||
this.fittedTargetClothes = (GameObject)null;
|
||||
yield return (object)null;
|
||||
configData = this.SetupConfigData(morpherMode);
|
||||
using (EdenAutoMorpherManager eamManager = new EdenAutoMorpherManager())
|
||||
{
|
||||
IEnumerator eamFitting = eamManager.FittingIteration(configData, morpherMode);
|
||||
while (eamFitting.MoveNext() && this.doProcess)
|
||||
{
|
||||
ref string local1 = ref this.processInfo.title;
|
||||
ref string local2 = ref this.processInfo.text;
|
||||
ref float local3 = ref this.processInfo.progress;
|
||||
(string, string, float) progressInfo = eamManager.GetProgressInfo();
|
||||
local1 = progressInfo.Item1;
|
||||
local2 = progressInfo.Item2;
|
||||
double num = (double)progressInfo.Item3;
|
||||
local3 = (float)num;
|
||||
yield return eamFitting.Current;
|
||||
}
|
||||
eamFitting = (IEnumerator)null;
|
||||
}
|
||||
this.fittedTargetAvatar = configData.targetAvatarObject;
|
||||
this.fittedTargetClothes = configData.targetClothesObject;
|
||||
configData = new EdenAutoMorpherConfig();
|
||||
}
|
||||
finally
|
||||
{
|
||||
sourceAvatarInfo.ApplyToTransform(this.sourceAvatarObject.transform, true, false, true, true);
|
||||
targetAvatarInfo.ApplyToTransform(this.targetAvatarObject.transform, true, false, true, true);
|
||||
}
|
||||
yield return (object)null;
|
||||
}
|
||||
|
||||
public IEnumerator ManualFitting(MorpherMode morpherMode)
|
||||
{
|
||||
TransformInfo sourceAvatarInfo = new TransformInfo(this.sourceAvatarObject.transform);
|
||||
TransformInfo targetAvatarInfo = new TransformInfo(this.targetAvatarObject.transform);
|
||||
try
|
||||
{
|
||||
EdenAutoMorpher_SetUpUtil morpherSetUpUtil = new EdenAutoMorpher_SetUpUtil();
|
||||
this.sourceBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)morpherSetUpUtil.SetupBodyMeshes(this.sourceAvatarObject, this.isBodyAutoSetup, this.sourceBodyMeshes, "Source ").AsReadOnly();
|
||||
this.targetBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)morpherSetUpUtil.SetupBodyMeshes(this.targetAvatarObject, this.isBodyAutoSetup, this.targetBodyMeshes, "Target ").AsReadOnly();
|
||||
this.targetClothesObject = this.targetClothesObjectOriginal;
|
||||
EdenAutoMorpherConfig configData = this.SetupConfigData(morpherMode);
|
||||
new EdenAutoMorpher_SetUpUtil().ManulSetup(ref configData, out this.clothesHumanoidMatchedBones, out this.clothBoneTypeMap);
|
||||
yield return (object)null;
|
||||
this.fittedTargetAvatar = (GameObject)null;
|
||||
this.fittedTargetClothes = (GameObject)null;
|
||||
configData = this.SetupConfigData(morpherMode);
|
||||
using (EdenAutoMorpherManager eamManager = new EdenAutoMorpherManager())
|
||||
{
|
||||
IEnumerator eamFitting = eamManager.FittingIteration(configData, morpherMode);
|
||||
while (eamFitting.MoveNext() && this.doProcess)
|
||||
{
|
||||
ref string local1 = ref this.processInfo.title;
|
||||
ref string local2 = ref this.processInfo.text;
|
||||
ref float local3 = ref this.processInfo.progress;
|
||||
(string, string, float) progressInfo = eamManager.GetProgressInfo();
|
||||
local1 = progressInfo.Item1;
|
||||
local2 = progressInfo.Item2;
|
||||
double num = (double)progressInfo.Item3;
|
||||
local3 = (float)num;
|
||||
yield return eamFitting.Current;
|
||||
}
|
||||
eamFitting = (IEnumerator)null;
|
||||
}
|
||||
this.fittedTargetAvatar = configData.targetAvatarObject;
|
||||
this.fittedTargetClothes = configData.targetClothesObject;
|
||||
configData = new EdenAutoMorpherConfig();
|
||||
}
|
||||
finally
|
||||
{
|
||||
sourceAvatarInfo.ApplyToTransform(this.sourceAvatarObject.transform, true, false, true, true);
|
||||
targetAvatarInfo.ApplyToTransform(this.targetAvatarObject.transform, true, false, true, true);
|
||||
}
|
||||
yield return (object)null;
|
||||
}
|
||||
|
||||
public IEnumerator ProfileFitting(MorpherMode morpherMode)
|
||||
{
|
||||
TransformInfo sourceClothesInfo = new TransformInfo(this.sourceClothesObject.transform);
|
||||
TransformInfo targetAvatarInfo = new TransformInfo(this.targetAvatarObject.transform);
|
||||
try
|
||||
{
|
||||
this.targetBodyMeshesReadOnly = (IReadOnlyList<SkinnedMeshRenderer>)new EdenAutoMorpher_SetUpUtil().SetupBodyMeshes(this.targetAvatarObject, this.isBodyAutoSetup, this.targetBodyMeshes, "Target ").AsReadOnly();
|
||||
this.targetAvatarObject.transform.SetParent((Transform)null, true);
|
||||
this.targetAvatarObject.transform.localRotation = Quaternion.identity;
|
||||
this.sourceClothesObject.transform.SetParent((Transform)null, true);
|
||||
this.sourceClothesObject.transform.localScale = Vector3.one;
|
||||
this.sourceClothesObject.transform.localRotation = Quaternion.identity;
|
||||
EdenAutoMorpherConfig configData = this.SetupConfigData(morpherMode);
|
||||
new EdenAutoMorpher_SetUpUtil().ProfileAutoSetup(ref configData, out this.clothesHumanoidMatchedBones, out this.clothBoneTypeMap);
|
||||
this.targetClothesObject = configData.targetClothesObject;
|
||||
this.targetClothesObjectOriginal = this.targetClothesObject;
|
||||
yield return (object)null;
|
||||
this.fittedTargetAvatar = (GameObject)null;
|
||||
this.fittedTargetClothes = (GameObject)null;
|
||||
yield return (object)null;
|
||||
configData = this.SetupConfigData(morpherMode);
|
||||
using (EdenAutoMorpherManager eamManager = new EdenAutoMorpherManager())
|
||||
{
|
||||
IEnumerator eamFitting = eamManager.FittingIteration(configData, morpherMode);
|
||||
while (eamFitting.MoveNext() && this.doProcess)
|
||||
{
|
||||
ref string local1 = ref this.processInfo.title;
|
||||
ref string local2 = ref this.processInfo.text;
|
||||
ref float local3 = ref this.processInfo.progress;
|
||||
(string, string, float) progressInfo = eamManager.GetProgressInfo();
|
||||
local1 = progressInfo.Item1;
|
||||
local2 = progressInfo.Item2;
|
||||
double num = (double)progressInfo.Item3;
|
||||
local3 = (float)num;
|
||||
yield return eamFitting.Current;
|
||||
}
|
||||
eamFitting = (IEnumerator)null;
|
||||
}
|
||||
this.fittedTargetAvatar = configData.targetAvatarObject;
|
||||
this.fittedTargetClothes = configData.targetClothesObject;
|
||||
yield return (object)null;
|
||||
configData = new EdenAutoMorpherConfig();
|
||||
}
|
||||
finally
|
||||
{
|
||||
sourceClothesInfo.ApplyToTransform(this.sourceClothesObject.transform, true, false, true, true);
|
||||
targetAvatarInfo.ApplyToTransform(this.targetAvatarObject.transform, true, false, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsWeightingReady(bool isAutoMode)
|
||||
{
|
||||
bool flag = this.morpherState == MorpherState.Fitting_End && Object.op_Inequality((Object)this.fittedTargetAvatar, (Object)null) && Object.op_Equality((Object)this.fittedTargetAvatar, (Object)this.targetAvatarObject);
|
||||
if (!isAutoMode)
|
||||
flag = flag && Object.op_Equality((Object)this.fittedTargetClothes, (Object)this.targetClothesObjectOriginal);
|
||||
return flag;
|
||||
}
|
||||
|
||||
private void ProcessInfoDebug(MorpherMode morpherMode, string processType)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendLine($"Start Process [{processType} / {morpherMode}]");
|
||||
EdenAutoMorpherConfig autoMorpherConfig = this.SetupConfigData(morpherMode);
|
||||
string str1 = Object.op_Inequality((Object)autoMorpherConfig.sourceAvatarObject, (Object)null) ? ((Object)autoMorpherConfig.sourceAvatarObject).name : "null";
|
||||
string str2 = Object.op_Inequality((Object)autoMorpherConfig.sourceClothesObject, (Object)null) ? ((Object)autoMorpherConfig.sourceClothesObject).name : "null";
|
||||
string str3 = Object.op_Inequality((Object)autoMorpherConfig.targetAvatarObject, (Object)null) ? ((Object)autoMorpherConfig.targetAvatarObject).name : "null";
|
||||
string str4 = Object.op_Inequality((Object)autoMorpherConfig.targetClothesObject, (Object)null) ? ((Object)autoMorpherConfig.targetClothesObject).name : "null";
|
||||
stringBuilder.AppendLine("[Objects]");
|
||||
if (morpherMode == MorpherMode.ProfileMorpher)
|
||||
stringBuilder.AppendLine("- profileName: " + (string.IsNullOrEmpty(autoMorpherConfig.profileName) ? "null/empty" : autoMorpherConfig.profileName));
|
||||
stringBuilder.AppendLine("- sourceAvatarObject: " + str1);
|
||||
stringBuilder.AppendLine("- sourceClothesObject: " + str2);
|
||||
if (Object.op_Inequality((Object)autoMorpherConfig.sourceClothesObject, (Object)null))
|
||||
{
|
||||
SkinnedMeshRenderer[] componentsInChildren = autoMorpherConfig.sourceClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
stringBuilder.AppendLine($" - sourceClothes SkinnedMeshRenderers Count: {componentsInChildren.Length}");
|
||||
int num = Mathf.Min(componentsInChildren.Length, 10);
|
||||
for (int index = 0; index < num; ++index)
|
||||
{
|
||||
SkinnedMeshRenderer skinnedMeshRenderer = componentsInChildren[index];
|
||||
string str5 = Object.op_Inequality((Object)skinnedMeshRenderer, (Object)null) ? ((Object)skinnedMeshRenderer).name : "null";
|
||||
string str6 = !Object.op_Inequality((Object)skinnedMeshRenderer, (Object)null) || !Object.op_Inequality((Object)skinnedMeshRenderer.rootBone, (Object)null) ? "null" : ((Object)skinnedMeshRenderer.rootBone).name;
|
||||
string str7 = !Object.op_Inequality((Object)skinnedMeshRenderer, (Object)null) || !Object.op_Inequality((Object)skinnedMeshRenderer.sharedMesh, (Object)null) ? "null" : ((Object)skinnedMeshRenderer.sharedMesh).name;
|
||||
stringBuilder.AppendLine($" - [{index}] SMR: {str5} / rootBone: {str6} / mesh: {str7}");
|
||||
}
|
||||
if (componentsInChildren.Length > num)
|
||||
stringBuilder.AppendLine($" - ... ({componentsInChildren.Length - num} more)");
|
||||
}
|
||||
stringBuilder.AppendLine("- targetAvatarObject: " + str3);
|
||||
stringBuilder.AppendLine("- targetClothesObject: " + str4);
|
||||
if (Object.op_Inequality((Object)autoMorpherConfig.targetClothesObject, (Object)null))
|
||||
{
|
||||
SkinnedMeshRenderer[] componentsInChildren = autoMorpherConfig.targetClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
stringBuilder.AppendLine($" - targetClothes SkinnedMeshRenderers Count: {componentsInChildren.Length}");
|
||||
int num = Mathf.Min(componentsInChildren.Length, 10);
|
||||
for (int index = 0; index < num; ++index)
|
||||
{
|
||||
SkinnedMeshRenderer skinnedMeshRenderer = componentsInChildren[index];
|
||||
string str8 = Object.op_Inequality((Object)skinnedMeshRenderer, (Object)null) ? ((Object)skinnedMeshRenderer).name : "null";
|
||||
string str9 = !Object.op_Inequality((Object)skinnedMeshRenderer, (Object)null) || !Object.op_Inequality((Object)skinnedMeshRenderer.rootBone, (Object)null) ? "null" : ((Object)skinnedMeshRenderer.rootBone).name;
|
||||
string str10 = !Object.op_Inequality((Object)skinnedMeshRenderer, (Object)null) || !Object.op_Inequality((Object)skinnedMeshRenderer.sharedMesh, (Object)null) ? "null" : ((Object)skinnedMeshRenderer.sharedMesh).name;
|
||||
stringBuilder.AppendLine($" - [{index}] SMR: {str8} / rootBone: {str9} / mesh: {str10}");
|
||||
}
|
||||
if (componentsInChildren.Length > num)
|
||||
stringBuilder.AppendLine($" - ... ({componentsInChildren.Length - num} more)");
|
||||
}
|
||||
stringBuilder.AppendLine();
|
||||
stringBuilder.AppendLine("[Body Meshes]");
|
||||
stringBuilder.AppendLine($"- isBodyAutoSetup: {autoMorpherConfig.isBodyAutoSetup}");
|
||||
if (!autoMorpherConfig.isBodyAutoSetup)
|
||||
{
|
||||
if (autoMorpherConfig.sourceBodyMeshes == null)
|
||||
{
|
||||
stringBuilder.AppendLine("- sourceBodyMeshes: null");
|
||||
}
|
||||
else
|
||||
{
|
||||
stringBuilder.AppendLine($"- sourceBodyMeshes Count: {this.sourceBodyMeshes.Count}");
|
||||
for (int index = 0; index < this.sourceBodyMeshes.Count; ++index)
|
||||
{
|
||||
SkinnedMeshRenderer sourceBodyMesh = this.sourceBodyMeshes[index];
|
||||
string str11 = Object.op_Inequality((Object)sourceBodyMesh, (Object)null) ? ((Object)sourceBodyMesh).name : "null";
|
||||
string str12 = !Object.op_Inequality((Object)sourceBodyMesh, (Object)null) || !Object.op_Inequality((Object)sourceBodyMesh.rootBone, (Object)null) ? "null" : ((Object)sourceBodyMesh.rootBone).name;
|
||||
string str13 = !Object.op_Inequality((Object)sourceBodyMesh, (Object)null) || !Object.op_Inequality((Object)sourceBodyMesh.sharedMesh, (Object)null) ? "null" : ((Object)sourceBodyMesh.sharedMesh).name;
|
||||
stringBuilder.AppendLine($" - [{index}] SMR: {str11} / rootBone: {str12} / mesh: {str13}");
|
||||
}
|
||||
}
|
||||
if (this.targetBodyMeshes == null)
|
||||
{
|
||||
stringBuilder.AppendLine("- targetBodyMeshes: null");
|
||||
}
|
||||
else
|
||||
{
|
||||
stringBuilder.AppendLine($"- targetBodyMeshes Count: {this.targetBodyMeshes.Count}");
|
||||
for (int index = 0; index < this.targetBodyMeshes.Count; ++index)
|
||||
{
|
||||
SkinnedMeshRenderer targetBodyMesh = this.targetBodyMeshes[index];
|
||||
string str14 = Object.op_Inequality((Object)targetBodyMesh, (Object)null) ? ((Object)targetBodyMesh).name : "null";
|
||||
string str15 = !Object.op_Inequality((Object)targetBodyMesh, (Object)null) || !Object.op_Inequality((Object)targetBodyMesh.rootBone, (Object)null) ? "null" : ((Object)targetBodyMesh.rootBone).name;
|
||||
string str16 = !Object.op_Inequality((Object)targetBodyMesh, (Object)null) || !Object.op_Inequality((Object)targetBodyMesh.sharedMesh, (Object)null) ? "null" : ((Object)targetBodyMesh.sharedMesh).name;
|
||||
stringBuilder.AppendLine($" - [{index}] SMR: {str14} / rootBone: {str15} / mesh: {str16}");
|
||||
}
|
||||
}
|
||||
}
|
||||
stringBuilder.AppendLine();
|
||||
stringBuilder.AppendLine("[Parameters]");
|
||||
stringBuilder.AppendLine($"- minMargin: {autoMorpherConfig.minMargin}");
|
||||
stringBuilder.AppendLine($"- worldRadius: {autoMorpherConfig.worldRadius}");
|
||||
stringBuilder.AppendLine($"- sigma: {autoMorpherConfig.sigma}");
|
||||
stringBuilder.AppendLine($"- smoothingIteration: {autoMorpherConfig.smoothingIteration}");
|
||||
stringBuilder.AppendLine($"- fittingExpandIteration: {autoMorpherConfig.fittingExpandIteration}");
|
||||
stringBuilder.AppendLine($"- fittingShrinkIteration: {autoMorpherConfig.fittingShrinkIteration}");
|
||||
stringBuilder.AppendLine();
|
||||
stringBuilder.AppendLine("[Options]");
|
||||
stringBuilder.AppendLine($"- isReparentAccessoryBonesToTargetAvatar: {autoMorpherConfig.isReparentAccessoryBonesToTargetAvatar}");
|
||||
stringBuilder.AppendLine($"- skipFootFitting: {autoMorpherConfig.skipFootFitting}");
|
||||
Debug.Log((object)stringBuilder.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eaae26efe7cd8314ab19e85cd1c4c1fa
|
||||
@@ -0,0 +1,38 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.EdenAutoMorpherConfig
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public struct EdenAutoMorpherConfig
|
||||
{
|
||||
public GameObject sourceAvatarObject;
|
||||
public GameObject sourceClothesObject;
|
||||
public IReadOnlyList<SkinnedMeshRenderer> sourceBodyMeshes;
|
||||
public GameObject targetAvatarObject;
|
||||
public GameObject targetClothesObject;
|
||||
public IReadOnlyList<SkinnedMeshRenderer> targetBodyMeshes;
|
||||
public string profileName;
|
||||
public float minMargin;
|
||||
public float worldRadius;
|
||||
public float sigma;
|
||||
public int smoothingIteration;
|
||||
public int fittingExpandIteration;
|
||||
public int fittingShrinkIteration;
|
||||
public bool isBodyAutoSetup;
|
||||
public bool isReparentAccessoryBonesToTargetAvatar;
|
||||
public bool skipFootFitting;
|
||||
public bool isRemoveAutoMorphedClothes;
|
||||
public bool transferWeightToAvatar;
|
||||
public bool addAnchorBone;
|
||||
public bool armatureBoneScaleCopy;
|
||||
public Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones;
|
||||
public Dictionary<Transform, ClothBoneType> clothBoneTypeMap;
|
||||
public string tagEdenMorpehrCloth;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a6e56a2e3d0f314a96d690af08d87a9
|
||||
@@ -0,0 +1,362 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.EdenAutoMorpherManager
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using Eden.AutoMorpher.profile;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class EdenAutoMorpherManager : IDisposable
|
||||
{
|
||||
private string displayTitle;
|
||||
private string displayText;
|
||||
private float displayProgress;
|
||||
private List<ClothInstance> clothInstances;
|
||||
|
||||
public (string, string, float) GetProgressInfo()
|
||||
{
|
||||
return (this.displayTitle, this.displayText, this.displayProgress);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
this.clothInstances = new List<ClothInstance>();
|
||||
SkinnedMeshRenderer[] targetClothesSMRs = targetClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(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}] - ({((Object)targetClothesSMRs[rendereri]).name})", Mathf.Lerp(0.05f, 0.1f, (float)(rendereri / targetClothesSMRs.Length)));
|
||||
yield return (object)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)
|
||||
{
|
||||
this.clothInstances = new List<ClothInstance>();
|
||||
SkinnedMeshRenderer[] targetClothesSMRs = targetClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>(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>(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}] - ({((Object)targetClothesSMRs[rendereri]).name})", Mathf.Lerp(0.07f, 0.1f, (float)(rendereri / targetClothesSMRs.Length)));
|
||||
yield return (object)null;
|
||||
ClothInstance clothInstance = setupUtil.SetupClothInstance(targetClothesSMRs[rendereri], sourceClothesSMRs[rendereri], meshMatcher, clothesHumanoidMatchedBones, 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)
|
||||
{
|
||||
this.SetupProgress("Set Up", "Setup Target Avatar Info", 0.03f);
|
||||
yield return (object)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 (object)null;
|
||||
this.SetupProgress("Set Up", "Setup Source Avatar Info", 0.05f);
|
||||
yield return (object)null;
|
||||
BvhTriangleMesh sourceBodyBVH = (BvhTriangleMesh)null;
|
||||
switch (morpherMode)
|
||||
{
|
||||
case MorpherMode.AutoMorpher:
|
||||
case MorpherMode.ManualMorpher:
|
||||
sourceBodyBVH = meshMatcher.BuildBvhMulti(config.sourceBodyMeshes, config.sourceAvatarObject.GetComponent<Animator>());
|
||||
break;
|
||||
case MorpherMode.ProfileMorpher:
|
||||
sourceBodyBVH = new ProfileLoader().LoadBvhWithRootTransform(config.sourceClothesObject.transform, config.profileName);
|
||||
break;
|
||||
default:
|
||||
Debug.LogError((object)"Unknown MorpherMode");
|
||||
break;
|
||||
}
|
||||
yield return (object)null;
|
||||
meshMatcher.bodyBVH = sourceBodyBVH != null ? sourceBodyBVH : throw new AutoMorpherException("sourceBodyBVH is Null", "[EdenAutoMorpherManater] FittingIteration\n - sourceBodyBVH is null");
|
||||
this.SetupProgress("Set Up", "Setup Clothes Info", 0.07f);
|
||||
yield return (object)null;
|
||||
IEnumerator setupClothEnum = this.SetupClothInstances(config.targetClothesObject, config.clothesHumanoidMatchedBones, config.sourceClothesObject, meshMatcher);
|
||||
while (setupClothEnum.MoveNext())
|
||||
yield return setupClothEnum.Current;
|
||||
yield return (object)null;
|
||||
float fittingRadius = config.worldRadius;
|
||||
meshMatcher.bodyBVH = targetBodyBVH;
|
||||
VertexFittingUtil vertexFittingUtil = new VertexFittingUtil();
|
||||
int fittingI;
|
||||
ClothInstance clothInstance;
|
||||
for (fittingI = 0; fittingI < config.fittingExpandIteration; ++fittingI)
|
||||
{
|
||||
foreach (ClothInstance clothInstance1 in this.clothInstances)
|
||||
{
|
||||
clothInstance = clothInstance1;
|
||||
this.SetupProgress("Fitting", $"Phase 1 Expanding [{fittingI + 1}/{config.fittingExpandIteration}] - {((Object)((Component)clothInstance.smr).transform).name}", Mathf.Lerp(0.1f, 0.4f, (float)fittingI / (float)config.fittingExpandIteration));
|
||||
yield return (object)null;
|
||||
vertexFittingUtil.ExpandClothes_World(clothInstance, this.clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return (object)null;
|
||||
clothInstance = (ClothInstance)null;
|
||||
}
|
||||
if (fittingI % 2 == 0)
|
||||
fittingRadius *= 0.97f;
|
||||
}
|
||||
fittingRadius = config.worldRadius;
|
||||
for (fittingI = 0; fittingI < config.fittingShrinkIteration; ++fittingI)
|
||||
{
|
||||
foreach (ClothInstance clothInstance2 in this.clothInstances)
|
||||
{
|
||||
clothInstance = clothInstance2;
|
||||
this.SetupProgress("Fitting", $"Phase 2 Fitting [{fittingI + 1}/{config.fittingShrinkIteration}] - {((Object)((Component)clothInstance.smr).transform).name}", Mathf.Lerp(0.4f, 0.8f, (float)fittingI / (float)config.fittingShrinkIteration));
|
||||
yield return (object)null;
|
||||
vertexFittingUtil.ShrinkClothes_World(clothInstance, this.clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return (object)null;
|
||||
vertexFittingUtil.ExpandClothes_World(clothInstance, this.clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return (object)null;
|
||||
clothInstance = (ClothInstance)null;
|
||||
}
|
||||
if (fittingI % 2 == 0)
|
||||
fittingRadius *= 0.97f;
|
||||
}
|
||||
fittingRadius = config.worldRadius / 2f;
|
||||
for (fittingI = 0; fittingI < config.fittingExpandIteration; ++fittingI)
|
||||
{
|
||||
foreach (ClothInstance clothInstance3 in this.clothInstances)
|
||||
{
|
||||
clothInstance = clothInstance3;
|
||||
this.SetupProgress("Fitting", $"Phase 3 Fine-tuning [{fittingI + 1}/{config.fittingExpandIteration}] - {((Object)((Component)clothInstance.smr).transform).name}", Mathf.Lerp(0.8f, 0.9f, (float)fittingI / (float)config.fittingExpandIteration));
|
||||
yield return (object)null;
|
||||
vertexFittingUtil.ExpandClothes_World(clothInstance, this.clothInstances, meshMatcher, config, fittingRadius);
|
||||
yield return (object)null;
|
||||
clothInstance = (ClothInstance)null;
|
||||
}
|
||||
if (fittingI % 2 == 0)
|
||||
fittingRadius *= 0.97f;
|
||||
}
|
||||
yield return (object)null;
|
||||
this.SetupProgress("Fitting", "Apply Transform Bone", 0.93f);
|
||||
yield return (object)null;
|
||||
BoneAlignmentUtil boneAlignmentUtil = new BoneAlignmentUtil();
|
||||
boneAlignmentUtil.CleanupTempBones(config.targetClothesObject.transform);
|
||||
switch (morpherMode)
|
||||
{
|
||||
case MorpherMode.AutoMorpher:
|
||||
case MorpherMode.ProfileMorpher:
|
||||
config.targetClothesObject.transform.localScale = Vector3.one;
|
||||
boneAlignmentUtil.AlignClothBonesToAvatar(this.clothInstances[0], config.targetAvatarObject.GetComponent<Animator>());
|
||||
break;
|
||||
}
|
||||
yield return (object)null;
|
||||
this.SetupProgress("Fitting", "Apply Transform Mesh", 0.99f);
|
||||
yield return (object)null;
|
||||
for (fittingI = 0; fittingI < this.clothInstances.Count; ++fittingI)
|
||||
{
|
||||
clothInstance = this.clothInstances[fittingI];
|
||||
this.SetupProgress("Fitting", $"Apply to Mesh [{fittingI + 1}/{this.clothInstances.Count}] - {((Object)((Component)clothInstance.smr).transform).name}", Mathf.Lerp(0.93f, 0.98f, (float)fittingI / (float)this.clothInstances.Count));
|
||||
yield return (object)null;
|
||||
clothInstance.ApplyWorldVerticesToMesh();
|
||||
((Renderer)clothInstance.smr).localBounds = new Bounds(Vector3.zero, Vector3.op_Multiply(Vector3.one, 2f));
|
||||
EditorUtility.SetDirty((Object)clothInstance.smr.sharedMesh);
|
||||
EditorUtility.SetDirty((Object)clothInstance.smr);
|
||||
yield return (object)null;
|
||||
clothInstance = (ClothInstance)null;
|
||||
}
|
||||
yield return (object)null;
|
||||
this.SetupProgress("Saving", "Saving Mesh Data", 0.99f);
|
||||
yield return (object)null;
|
||||
this.SaveEditedMeshesToAssets(this.clothInstances, config);
|
||||
yield return (object)null;
|
||||
this.SetupProgress("Finishing", "Finishing", 1f);
|
||||
foreach (ClothInstance clothInstance4 in this.clothInstances)
|
||||
clothInstance4.Dispose();
|
||||
this.clothInstances = (List<ClothInstance>)null;
|
||||
sourceBodyBVH = (BvhTriangleMesh)null;
|
||||
targetBodyBVH = (BvhTriangleMesh)null;
|
||||
yield return (object)null;
|
||||
}
|
||||
|
||||
public IEnumerator WeightingEnumerator(EdenAutoMorpherConfig config)
|
||||
{
|
||||
EdenAutoMorpherManager autoMorpherManager = this;
|
||||
autoMorpherManager.SetupProgress("Set Up", "Setup Target Avatar Info", 0.0f);
|
||||
yield return (object)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 (object)null;
|
||||
List<Mesh> bakedTargetBodyMeshes = new List<Mesh>();
|
||||
foreach (SkinnedMeshRenderer bodyMesh in (IEnumerable<SkinnedMeshRenderer>)config.targetBodyMeshes)
|
||||
{
|
||||
autoMorpherManager.SetupProgress("Set Up", "Setup Target Avatar BodyMesh Info", Mathf.Lerp(0.02f, 0.05f, (float)(bakedTargetBodyMeshes.Count / config.targetBodyMeshes.Count)));
|
||||
yield return (object)null;
|
||||
Mesh mesh = new Mesh();
|
||||
bodyMesh.BakeMesh(mesh);
|
||||
mesh.triangles = bodyMesh.sharedMesh.triangles;
|
||||
mesh.boneWeights = bodyMesh.sharedMesh.boneWeights;
|
||||
bakedTargetBodyMeshes.Add(mesh);
|
||||
}
|
||||
yield return (object)null;
|
||||
IEnumerator setupClothEnum = autoMorpherManager.SetupClothInstances(config.targetClothesObject, config.clothesHumanoidMatchedBones, false);
|
||||
while (setupClothEnum.MoveNext())
|
||||
yield return setupClothEnum.Current;
|
||||
yield return (object)null;
|
||||
Dictionary<Transform, Transform> clonedBoneMap = (Dictionary<Transform, Transform>)null;
|
||||
if (!config.transferWeightToAvatar)
|
||||
new EdenAutoMorpher_SetUpUtil().CreateClothesArmature(config, out clonedBoneMap);
|
||||
yield return (object)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 (object)null;
|
||||
for (int weightingI = 0; weightingI < autoMorpherManager.clothInstances.Count; ++weightingI)
|
||||
{
|
||||
ClothInstance clothInstance = autoMorpherManager.clothInstances[weightingI];
|
||||
float num1 = 0.1f;
|
||||
float num2 = (0.95f - num1) / (float)Mathf.Max(1, autoMorpherManager.clothInstances.Count);
|
||||
float num3 = num1 + num2 * (float)weightingI;
|
||||
float num4 = 0.8f;
|
||||
float weightingStart = num3;
|
||||
float weightingEnd = num3 + num2 * num4;
|
||||
float applyStart = num3 + num2 * num4;
|
||||
int step = 1;
|
||||
autoMorpherManager.SetupProgress("Weighting", $"Weighting | Step {step} [{weightingI + 1}/{autoMorpherManager.clothInstances.Count}] - {((Object)((Component)clothInstance.smr).transform).name}", weightingStart);
|
||||
yield return (object)null;
|
||||
IEnumerator weightingEnum = weightTransferUtil.RetargetAndTransfer(clothInstance, config.targetAvatarObject.GetComponent<Animator>(), config.targetBodyMeshes, (IReadOnlyList<Mesh>)bakedTargetBodyMeshes, settings: wtSettings, boneTypeMap: config.clothBoneTypeMap, bodyToClothesMap: clonedBoneMap);
|
||||
while (weightingEnum.MoveNext())
|
||||
{
|
||||
yield return (object)null;
|
||||
++step;
|
||||
float progress = Mathf.Lerp(weightingStart, weightingEnd, (float)(1.0 - 1.0 / ((double)step + 1.0)));
|
||||
autoMorpherManager.SetupProgress("Weighting", $"Weighting | Step {step} [{weightingI + 1}/{autoMorpherManager.clothInstances.Count}] - {((Object)((Component)clothInstance.smr).transform).name}", progress);
|
||||
yield return weightingEnum.Current;
|
||||
}
|
||||
yield return (object)null;
|
||||
++step;
|
||||
autoMorpherManager.SetupProgress("Weighting", $"Weighting | Step {step} - Apply to Mesh [{weightingI + 1}/{autoMorpherManager.clothInstances.Count}] - {((Object)((Component)clothInstance.smr).transform).name}", applyStart);
|
||||
yield return (object)null;
|
||||
clothInstance.ApplyWorldVerticesToMesh();
|
||||
((Renderer)clothInstance.smr).localBounds = new Bounds(Vector3.zero, Vector3.op_Multiply(Vector3.one, 2f));
|
||||
EditorUtility.SetDirty((Object)clothInstance.smr.sharedMesh);
|
||||
EditorUtility.SetDirty((Object)clothInstance.smr);
|
||||
yield return (object)null;
|
||||
clothInstance = (ClothInstance)null;
|
||||
weightingEnum = (IEnumerator)null;
|
||||
}
|
||||
autoMorpherManager.SetupProgress("Weighting", "Allocate Bones", 0.95f);
|
||||
yield return (object)null;
|
||||
if (config.transferWeightToAvatar && config.isReparentAccessoryBonesToTargetAvatar)
|
||||
new BoneAlignmentUtil().ReparentAccessoryBonesToAvatar(config);
|
||||
autoMorpherManager.SetupProgress("Finishing", "Finishing", 1f);
|
||||
yield return (object)null;
|
||||
foreach (ClothInstance clothInstance in autoMorpherManager.clothInstances)
|
||||
clothInstance.Dispose();
|
||||
autoMorpherManager.clothInstances = (List<ClothInstance>)null;
|
||||
yield return (object)null;
|
||||
}
|
||||
|
||||
private void SaveEditedMeshesToAssets(
|
||||
List<ClothInstance> clothInstances,
|
||||
EdenAutoMorpherConfig config)
|
||||
{
|
||||
if (clothInstances == null || clothInstances.Count == 0)
|
||||
{
|
||||
Debug.LogWarning((object)"[EdenAutoMorpher] 저장할 ClothInstance가 없습니다.");
|
||||
throw new AutoMorpherException("Can't Save Mesh", "Therer is no ClothInstance to save mesh");
|
||||
}
|
||||
if (Object.op_Equality((Object)config.targetClothesObject, (Object)null) || Object.op_Equality((Object)config.targetAvatarObject, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"[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 str1 = "Assets/@Eden_Mesh";
|
||||
if (!AssetDatabase.IsValidFolder(str1))
|
||||
AssetDatabase.CreateFolder("Assets", "@Eden_Mesh");
|
||||
string str2 = SanitizeForAssetName(((Object)config.targetAvatarObject).name);
|
||||
string str3 = $"{str1}/{str2}";
|
||||
if (!AssetDatabase.IsValidFolder(str3))
|
||||
AssetDatabase.CreateFolder(str1, str2);
|
||||
string str4 = SanitizeForAssetName(((Object)config.targetClothesObject).name);
|
||||
string str5 = $"{str3}/{str4}";
|
||||
if (!AssetDatabase.IsValidFolder(str5))
|
||||
AssetDatabase.CreateFolder(str3, str4);
|
||||
string uniqueAssetPath = AssetDatabase.GenerateUniqueAssetPath($"{str5}/{str4}_Meshes.asset");
|
||||
int num = 0;
|
||||
Mesh mesh1 = new Mesh();
|
||||
((Object)mesh1).name = str4 + "_RootMesh";
|
||||
AssetDatabase.CreateAsset((Object)mesh1, uniqueAssetPath);
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
{
|
||||
if (clothInstance != null && !Object.op_Equality((Object)clothInstance.smr, (Object)null))
|
||||
{
|
||||
Mesh sharedMesh = clothInstance.smr.sharedMesh;
|
||||
if (!Object.op_Equality((Object)sharedMesh, (Object)null))
|
||||
{
|
||||
Mesh mesh2 = Object.Instantiate<Mesh>(sharedMesh);
|
||||
((Object)mesh2).name = SanitizeForAssetName(((Object)((Component)clothInstance.smr).gameObject).name + "_EditedMesh");
|
||||
AssetDatabase.AddObjectToAsset((Object)mesh2, uniqueAssetPath);
|
||||
clothInstance.smr.sharedMesh = mesh2;
|
||||
clothInstance.editableMesh = clothInstance.smr.sharedMesh;
|
||||
EditorUtility.SetDirty((Object)clothInstance.smr);
|
||||
EditorUtility.SetDirty((Object)clothInstance.smr.sharedMesh);
|
||||
EditorUtility.SetDirty((Object)((Component)clothInstance.smr).gameObject);
|
||||
++num;
|
||||
}
|
||||
}
|
||||
}
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log((object)$"{$"[EdenAutoMorpher] 편집된 메쉬 {num}개를 "}'{uniqueAssetPath}' 에 서브 에셋으로 저장했습니다. (원본 프리팹은 변경하지 않음)");
|
||||
|
||||
static string SanitizeForAssetName(string rawName)
|
||||
{
|
||||
foreach (char invalidFileNameChar in Path.GetInvalidFileNameChars())
|
||||
rawName = rawName.Replace(invalidFileNameChar, '_');
|
||||
return rawName.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db28ab8ea782f894bb3ca3288606e842
|
||||
@@ -0,0 +1,552 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.EdenAutoMorpher_SetUpUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using Eden.AutoMorpher.profile;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class EdenAutoMorpher_SetUpUtil
|
||||
{
|
||||
public GameObject InstantiateTargetClothes(
|
||||
GameObject sourceClothesObject,
|
||||
GameObject targetAvatarObject,
|
||||
string tagEdenMorpherCloth,
|
||||
bool removeAutoMorphedClothes)
|
||||
{
|
||||
EdenAutoMorpher_SetUpUtil.EnsureTagExists(tagEdenMorpherCloth);
|
||||
if (removeAutoMorphedClothes)
|
||||
{
|
||||
List<GameObject> gameObjectList = new List<GameObject>();
|
||||
foreach (Transform componentsInChild in targetAvatarObject.GetComponentsInChildren<Transform>(true))
|
||||
{
|
||||
if (!Object.op_Equality((Object)((Component)componentsInChild).gameObject, (Object)targetAvatarObject) && ((Component)componentsInChild).CompareTag(tagEdenMorpherCloth))
|
||||
gameObjectList.Add(((Component)componentsInChild).gameObject);
|
||||
}
|
||||
foreach (Object @object in gameObjectList)
|
||||
Object.DestroyImmediate(@object);
|
||||
}
|
||||
GameObject gameObject = Object.Instantiate<GameObject>(sourceClothesObject, targetAvatarObject.transform);
|
||||
gameObject.SetActive(true);
|
||||
gameObject.transform.localPosition = Vector3.zero;
|
||||
gameObject.transform.localRotation = Quaternion.identity;
|
||||
gameObject.transform.localScale = Vector3.one;
|
||||
gameObject.tag = tagEdenMorpherCloth;
|
||||
return gameObject;
|
||||
}
|
||||
|
||||
private static void EnsureTagExists(string tag)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tag))
|
||||
throw new AutoMorpherException("Clothes Tag is Invalid", "[EdenAutoMorpherManager] EnsureTagExists\n - tagEdenMorpherCloth is null or empty");
|
||||
foreach (string tag1 in InternalEditorUtility.tags)
|
||||
{
|
||||
if (tag1 == tag)
|
||||
return;
|
||||
}
|
||||
SerializedObject serializedObject = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
|
||||
SerializedProperty property = serializedObject.FindProperty("tags");
|
||||
int arraySize = property.arraySize;
|
||||
property.InsertArrayElementAtIndex(arraySize);
|
||||
property.GetArrayElementAtIndex(arraySize).stringValue = tag;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
public void AutoSetup(
|
||||
ref EdenAutoMorpherConfig config,
|
||||
out Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones,
|
||||
out Dictionary<Transform, ClothBoneType> clothBoneTypeMap)
|
||||
{
|
||||
config.targetClothesObject = this.InstantiateTargetClothes(config.sourceClothesObject, config.targetAvatarObject, config.tagEdenMorpehrCloth, config.isRemoveAutoMorphedClothes);
|
||||
if (Object.op_Equality((Object)config.targetClothesObject, (Object)null))
|
||||
throw new AutoMorpherException("Target Clothes Object is Null", "[EdenAutoMorpher_SetUpUtil] AutoSetup\n - config.targetClothesObject is null");
|
||||
BoneMatchUtil boneMatchUtil = new BoneMatchUtil();
|
||||
List<BoneMatchUtil.BoneRootLocalData> bodyRootLocalBones = boneMatchUtil.GetBodyRootLocalBones(config.sourceAvatarObject.transform, config.sourceAvatarObject.GetComponent<Animator>(), config.sourceBodyMeshes.ToList<SkinnedMeshRenderer>());
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalBones = boneMatchUtil.GetRootLocalBones(config.targetClothesObject.transform, boneMatchUtil.GetMeshBones(((IEnumerable<SkinnedMeshRenderer>)config.targetClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>()).ToList<SkinnedMeshRenderer>()));
|
||||
Dictionary<Transform, BoneMatchUtil.BoneRootLocalData> clothToBodyMatched;
|
||||
boneMatchUtil.MatchClothesToBodyBones(bodyRootLocalBones, rootLocalBones, out clothesHumanoidMatchedBones, out clothBoneTypeMap, out clothToBodyMatched);
|
||||
Dictionary<Transform, Transform> sourceToProxy;
|
||||
GameObject gameObject = new BodyPoseMatchUtil().AutoAdjustBodyPose(config.sourceAvatarObject, config.sourceBodyMeshes, config.targetAvatarObject, config.targetBodyMeshes, out sourceToProxy);
|
||||
if (Object.op_Equality((Object)gameObject, (Object)null))
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.BodyProxyNull"), LanguageManager.Get("UI.Exception.message.BodyProxyNull"));
|
||||
try
|
||||
{
|
||||
if (clothesHumanoidMatchedBones == null || clothesHumanoidMatchedBones.Count == 0)
|
||||
throw new AutoMorpherException("Clothes Humanoid Matched Bones is Null", "[EdenAutoMorpher_SetUpUtil] AutoSetup\n - clothesHumanoidMatchedBones is null\n - Please check whether the outfit’s bones match the bones of the source avatar.");
|
||||
if (clothBoneTypeMap == null)
|
||||
throw new AutoMorpherException("Cloth Bone Type Map is Null", "[EdenAutoMorpher_SetUpUtil] AutoSetup\n - clothBoneTypeMap is null\n - Please check whether the outfit’s bones match the bones of the source avatar.");
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
this.DebugPrintSameNameBonePaths(clothToBodyMatched, sourceToProxy);
|
||||
new BodyPoseToClothApplier().ApplyBodyPoseToClothes(gameObject.transform, config.targetClothesObject.transform, clothToBodyMatched, sourceToProxy);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Object.DestroyImmediate((Object)gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void DebugPrintSameNameBonePaths(
|
||||
Dictionary<Transform, BoneMatchUtil.BoneRootLocalData> clothToBodyMatched,
|
||||
Dictionary<Transform, Transform> sourceToProxy)
|
||||
{
|
||||
if (clothToBodyMatched == null)
|
||||
throw new AutoMorpherException("clothToBodyMatched is Missing", "[DebugBonePath] DebugPrintSameNameBonePaths\n - clothToBodyMatched is null");
|
||||
if (sourceToProxy == null)
|
||||
throw new AutoMorpherException("sourceToProxy is Missing", "[DebugBonePath] DebugPrintSameNameBonePaths\n - sourceToProxy is null");
|
||||
Dictionary<string, List<Transform>> dictionary = new Dictionary<string, List<Transform>>();
|
||||
foreach (KeyValuePair<Transform, Transform> keyValuePair in sourceToProxy)
|
||||
{
|
||||
Transform key = keyValuePair.Key;
|
||||
if (!Object.op_Equality((Object)key, (Object)null))
|
||||
{
|
||||
List<Transform> transformList;
|
||||
if (!dictionary.TryGetValue(((Object)key).name, out transformList))
|
||||
{
|
||||
transformList = new List<Transform>();
|
||||
dictionary.Add(((Object)key).name, transformList);
|
||||
}
|
||||
transformList.Add(key);
|
||||
}
|
||||
}
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendLine("[DebugBonePath] Same-name bone path comparison");
|
||||
stringBuilder.AppendLine("--------------------------------------------------");
|
||||
foreach (KeyValuePair<Transform, BoneMatchUtil.BoneRootLocalData> keyValuePair in clothToBodyMatched)
|
||||
{
|
||||
Transform key = keyValuePair.Key;
|
||||
Transform sourceTransform = GetSourceTransform(keyValuePair.Value);
|
||||
if (!Object.op_Equality((Object)sourceTransform, (Object)null))
|
||||
{
|
||||
string name = ((Object)sourceTransform).name;
|
||||
List<Transform> transformList;
|
||||
if (dictionary.TryGetValue(name, out transformList))
|
||||
{
|
||||
stringBuilder.AppendLine("[Bone Name] " + name);
|
||||
stringBuilder.AppendLine(" - BoneRootLocalData Source Path: " + GetPath(sourceTransform));
|
||||
foreach (Transform t in transformList)
|
||||
stringBuilder.AppendLine(" - sourceToProxy Source Path : " + GetPath(t));
|
||||
stringBuilder.AppendLine("--------------------------------------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
Debug.Log((object)stringBuilder.ToString());
|
||||
|
||||
static string GetPath(Transform t)
|
||||
{
|
||||
if (Object.op_Equality((Object)t, (Object)null))
|
||||
return "(null)";
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
while (Object.op_Inequality((Object)t, (Object)null))
|
||||
{
|
||||
stringBuilder.Insert(0, ((Object)t).name);
|
||||
t = t.parent;
|
||||
if (Object.op_Inequality((Object)t, (Object)null))
|
||||
stringBuilder.Insert(0, "/");
|
||||
}
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
static Transform GetSourceTransform(BoneMatchUtil.BoneRootLocalData data)
|
||||
{
|
||||
if (data == null)
|
||||
return (Transform)null;
|
||||
foreach (FieldInfo field in data.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
if (typeof(Transform).IsAssignableFrom(field.FieldType))
|
||||
return field.GetValue((object)data) as Transform;
|
||||
}
|
||||
return (Transform)null;
|
||||
}
|
||||
}
|
||||
|
||||
public void ManulSetup(
|
||||
ref EdenAutoMorpherConfig config,
|
||||
out Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones,
|
||||
out Dictionary<Transform, ClothBoneType> clothBoneTypeMap)
|
||||
{
|
||||
BoneMatchUtil boneMatchUtil = new BoneMatchUtil();
|
||||
List<BoneMatchUtil.BoneRootLocalData> bodyRootLocalBones = boneMatchUtil.GetBodyRootLocalBones(config.sourceAvatarObject.transform, config.sourceAvatarObject.GetComponent<Animator>(), config.sourceBodyMeshes.ToList<SkinnedMeshRenderer>());
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalBones = boneMatchUtil.GetRootLocalBones(config.sourceClothesObject.transform, boneMatchUtil.GetMeshBones(((IEnumerable<SkinnedMeshRenderer>)config.sourceClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>()).ToList<SkinnedMeshRenderer>()));
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothHumanBones;
|
||||
Dictionary<Transform, ClothBoneType> clothBoneTypeMap1;
|
||||
boneMatchUtil.MatchClothesToBodyBones(bodyRootLocalBones, rootLocalBones, out clothHumanBones, out clothBoneTypeMap1, out Dictionary<Transform, BoneMatchUtil.BoneRootLocalData> _);
|
||||
boneMatchUtil.RemapSourceClothMatchToTargetCloth(config.sourceClothesObject.transform, config.targetClothesObject.transform, clothHumanBones, clothBoneTypeMap1, out clothesHumanoidMatchedBones, out clothBoneTypeMap);
|
||||
if (clothesHumanoidMatchedBones == null || clothesHumanoidMatchedBones.Count == 0)
|
||||
throw new AutoMorpherException("Clothes Humanoid Matched Bones is Null", "[EdenAutoMorpher_SetUpUtil] ManulSetup\n - clothesHumanoidMatchedBones is null\n - Please check whether the Source Clothes’s bones match the bones of the source avatar.");
|
||||
if (clothBoneTypeMap == null)
|
||||
throw new AutoMorpherException("Cloth Bone Type Map is Null", "[EdenAutoMorpher_SetUpUtil] ManulSetup\n - clothBoneTypeMap is null\n - Please check whether the Source Clothes’s bones match the bones of the source avatar.");
|
||||
MeshClassifier meshClassifier = new MeshClassifier();
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanBoneMap1 = meshClassifier.MeshHumanoidBoneMatcher(config.sourceAvatarObject.GetComponent<Animator>(), config.sourceBodyMeshes);
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> humanBoneMap2 = meshClassifier.MeshHumanoidBoneMatcher(config.targetAvatarObject.GetComponent<Animator>(), config.sourceBodyMeshes);
|
||||
BodyPoseMatchSetupUtil poseMatchSetupUtil = new BodyPoseMatchSetupUtil();
|
||||
poseMatchSetupUtil.AdjustAvatarScaleByNeck(config.sourceAvatarObject.transform, humanBoneMap1, 1.5f);
|
||||
poseMatchSetupUtil.AdjustAvatarScaleByNeck(config.targetAvatarObject.transform, humanBoneMap2, 1.5f);
|
||||
}
|
||||
|
||||
public void ProfileAutoSetup(
|
||||
ref EdenAutoMorpherConfig config,
|
||||
out Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones,
|
||||
out Dictionary<Transform, ClothBoneType> clothBoneTypeMap)
|
||||
{
|
||||
config.targetClothesObject = this.InstantiateTargetClothes(config.sourceClothesObject, config.targetAvatarObject, config.tagEdenMorpehrCloth, config.isRemoveAutoMorphedClothes);
|
||||
ProfileData profileData = !Object.op_Equality((Object)config.targetClothesObject, (Object)null) ? new ProfileLoader().LoadProfileData(config.profileName) : throw new AutoMorpherException("Target Clothes Object is Null", "[EdenAutoMorpher_SetUpUtil] ProfileAutoSetup\n - config.targetClothesObject is null");
|
||||
if (profileData == null)
|
||||
throw new AutoMorpherException("Clothes Humanoid Matched Bones is Null", "[EdenAutoMorpher_SetUpUtil] ProfileAutoSetup\n - profile Data is null");
|
||||
BoneMatchUtil boneMatchUtil = new BoneMatchUtil();
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalData = boneMatchUtil.ConvertProfileBoneDataToRootLocalData(profileData.bones);
|
||||
List<BoneMatchUtil.BoneRootLocalData> rootLocalBones = boneMatchUtil.GetRootLocalBones(config.targetClothesObject.transform, boneMatchUtil.GetMeshBones(((IEnumerable<SkinnedMeshRenderer>)config.targetClothesObject.GetComponentsInChildren<SkinnedMeshRenderer>()).ToList<SkinnedMeshRenderer>()));
|
||||
boneMatchUtil.MatchClothesToBodyBones(rootLocalData, rootLocalBones, out clothesHumanoidMatchedBones, out clothBoneTypeMap, out Dictionary<Transform, BoneMatchUtil.BoneRootLocalData> _);
|
||||
if (clothesHumanoidMatchedBones == null || clothesHumanoidMatchedBones.Count == 0)
|
||||
throw new AutoMorpherException("Cloth Body Bones is Null", "[EdenAutoMorpher_SetUpUtil] ProfileAutoSetup\n - clothesHumanoidMatchedBones is null\n - Please check whether you have selected the correct profile for the outfit.");
|
||||
if (clothBoneTypeMap == null)
|
||||
throw new AutoMorpherException("Cloth Bone Type Map is Null", "[EdenAutoMorpher_SetUpUtil] ProfileAutoSetup\n - clothBoneTypeMap is null\n - Please check whether you have selected the correct profile for the outfit.");
|
||||
new ProfilePoseMatchUtil().ProfilePoseMatcher(config.targetAvatarObject, config.targetBodyMeshes, config.targetClothesObject, profileData, clothesHumanoidMatchedBones, clothBoneTypeMap);
|
||||
}
|
||||
|
||||
public List<SkinnedMeshRenderer> SetupBodyMeshes(
|
||||
GameObject bodyObject,
|
||||
bool isBodyAutoSetup,
|
||||
List<SkinnedMeshRenderer> userAllocatedBoeyMeshes,
|
||||
string errorPreFix = "")
|
||||
{
|
||||
EdenAutoMorpherManager autoMorpherManager = new EdenAutoMorpherManager();
|
||||
List<SkinnedMeshRenderer> skinnedMeshRendererList = isBodyAutoSetup ? this.GetBodyMeshes(bodyObject) : userAllocatedBoeyMeshes;
|
||||
if (skinnedMeshRendererList == null)
|
||||
throw new AutoMorpherException(errorPreFix + "Body Mesh Is Null or Empty", errorPreFix + "Body Mesh list is null or empty");
|
||||
foreach (Object @object in skinnedMeshRendererList)
|
||||
{
|
||||
if (Object.op_Equality(@object, (Object)null))
|
||||
throw new AutoMorpherException(errorPreFix + "Body Mesh Is Null", $"Null Mesh in {errorPreFix} Body Meshes");
|
||||
}
|
||||
return skinnedMeshRendererList;
|
||||
}
|
||||
|
||||
public List<SkinnedMeshRenderer> GetBodyMeshes(GameObject avatarObject)
|
||||
{
|
||||
MeshClassifier meshClassifier = new MeshClassifier();
|
||||
List<SkinnedMeshRenderer> bodyMeshes = new List<SkinnedMeshRenderer>();
|
||||
Animator component = avatarObject.GetComponent<Animator>();
|
||||
if (Object.op_Inequality((Object)component, (Object)null) && Object.op_Inequality((Object)component.avatar, (Object)null) && component.avatar.isHuman)
|
||||
{
|
||||
bodyMeshes.Add(meshClassifier.GetBodyMesh(avatarObject.transform, component));
|
||||
foreach (Object @object in bodyMeshes)
|
||||
{
|
||||
if (Object.op_Equality(@object, (Object)null))
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.BodyMeshNull"), LanguageManager.GetFormat("UI.Exception.message.BodyMeshNull", (object)((Object)avatarObject).name));
|
||||
}
|
||||
return bodyMeshes;
|
||||
}
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.BodyMeshNull"), LanguageManager.GetFormat("UI.Exception.message.BodyMeshNull", (object)((Object)avatarObject).name));
|
||||
}
|
||||
|
||||
public ClothInstance SetupClothInstance(
|
||||
SkinnedMeshRenderer clothSMR,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones,
|
||||
bool duplicateMesh)
|
||||
{
|
||||
ClothHumanoidMaskUtil humanoidMaskUtil = new ClothHumanoidMaskUtil();
|
||||
ClothInstance clothInstance = !Object.op_Equality((Object)clothSMR, (Object)null) && !Object.op_Equality((Object)clothSMR.sharedMesh, (Object)null) ? new ClothInstance(clothSMR, duplicateMesh) : throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.TargetRendererNull"), LanguageManager.Get("UI.Exception.message.TargetRendererNull"));
|
||||
clothInstance.humanoidMatchedBones = clothesHumanoidMatchedBones;
|
||||
humanoidMaskUtil.BuildExcludedVertexMaskForHandsAndHead(clothInstance);
|
||||
return clothInstance;
|
||||
}
|
||||
|
||||
public ClothInstance SetupClothInstance(
|
||||
SkinnedMeshRenderer clothSMR,
|
||||
SkinnedMeshRenderer coupledSMR,
|
||||
MeshMatcher meshMatcher,
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> clothesHumanoidMatchedBones,
|
||||
bool duplicateMesh)
|
||||
{
|
||||
if (Object.op_Equality((Object)coupledSMR, (Object)null))
|
||||
throw new AutoMorpherException("Coupled Skinned Mesh Renderer is Null", "[EdenAutoMorpher_SetupUtil] SetupClothInstance\n\n - Coupled Skinned Mesh Renderer is null");
|
||||
if (Object.op_Equality((Object)coupledSMR.sharedMesh, (Object)null) || coupledSMR.sharedMesh.vertexCount == 0)
|
||||
throw new AutoMorpherException("Coupled Skinned Mesh Renderer's Mesh is Null or empty", "[EdenAutoMorpher_SetupUtil] SetupClothInstance\n\n - Coupled Skinned Mesh Renderer's mesh is null or no vertices");
|
||||
ClothInstance clothInstance = this.SetupClothInstance(clothSMR, clothesHumanoidMatchedBones, duplicateMesh);
|
||||
if (clothInstance == null)
|
||||
return (ClothInstance)null;
|
||||
Vector3[] worldVertices = new WorldVertexUtil().GetWorldVertices(coupledSMR);
|
||||
clothInstance.minDistanceVector = meshMatcher.GetMinDistanceToBody(worldVertices);
|
||||
if (clothInstance.minDistanceVector == null || clothInstance.minDistanceVector.Length == 0)
|
||||
throw new AutoMorpherException("Min Distance is Null", "[EdenAutoMorpher_SetupUtil] SetupClothInstance\n - minDistanceVector is null or empty");
|
||||
if (clothInstance.minDistanceVector != null)
|
||||
clothInstance.minDistance = ((IEnumerable<Vector3>)clothInstance.minDistanceVector).Select<Vector3, float>((Func<Vector3, float>)(v => ((Vector3)ref v).magnitude)).ToArray<float>();
|
||||
clothInstance.isInsideVertex = meshMatcher.GetBodyInsideFlags(worldVertices);
|
||||
if (clothInstance.isInsideVertex == null || clothInstance.isInsideVertex.Length == 0)
|
||||
throw new AutoMorpherException("isInsideVertex is Null", "[EdenAutoMorpher_SetupUtil] SetupClothInstance\n - isInsideVertex is null or empty");
|
||||
return clothInstance;
|
||||
}
|
||||
|
||||
public Transform CreateClothesArmature(
|
||||
EdenAutoMorpherConfig config,
|
||||
out Dictionary<Transform, Transform> clonedBoneMap)
|
||||
{
|
||||
clonedBoneMap = (Dictionary<Transform, Transform>)null;
|
||||
if (Object.op_Equality((Object)config.targetClothesObject, (Object)null))
|
||||
throw new AutoMorpherException("Target Clothes Object is Missing", "[EdenAutoMorpherManager] CreateClothesArmature\n - config.targetClothesObject is null");
|
||||
Animator animator = !Object.op_Equality((Object)config.targetAvatarObject, (Object)null) ? config.targetAvatarObject.GetComponent<Animator>() : throw new AutoMorpherException("Target Avatar Object is Missing", "[EdenAutoMorpherManager] CreateClothesArmature\n - config.targetAvatarObject is null");
|
||||
Transform key1 = !Object.op_Equality((Object)animator, (Object)null) && animator.isHuman ? animator.GetBoneTransform((HumanBodyBones)0) : throw new AutoMorpherException("Target Avatar Animator is Invalid", "[EdenAutoMorpherManager] CreateClothesArmature\n - targetAvatarAnimator is null or not a Humanoid");
|
||||
if (Object.op_Equality((Object)key1, (Object)null))
|
||||
throw new AutoMorpherException("Humanoid Root Bone is Missing", "[EdenAutoMorpherManager] CreateClothesArmature\n - Animator.GetBoneTransform(HumanBodyBones.Hips) returned null");
|
||||
if (config.targetBodyMeshes == null || config.targetBodyMeshes.Count == 0)
|
||||
throw new AutoMorpherException("Target Body Meshes are Missing", "[EdenAutoMorpherManager] CreateClothesArmature\n - config.targetBodyMeshes is null or empty");
|
||||
Transform transform1 = config.targetClothesObject.transform;
|
||||
Transform clothesArmature = this.FindArmature(config, config.targetClothesObject.transform);
|
||||
if (Object.op_Equality((Object)clothesArmature, (Object)null))
|
||||
{
|
||||
clothesArmature = new GameObject("Armature.1").transform;
|
||||
clothesArmature.SetParent(transform1, false);
|
||||
clothesArmature.localPosition = Vector3.zero;
|
||||
clothesArmature.localRotation = Quaternion.identity;
|
||||
clothesArmature.localScale = Vector3.one;
|
||||
}
|
||||
if (((Object)clothesArmature).name == "Armature")
|
||||
((Object)clothesArmature).name = "Armature.1";
|
||||
Dictionary<Transform, Transform> dictionary1 = new Dictionary<Transform, Transform>();
|
||||
if (config.clothesHumanoidMatchedBones != null && config.clothesHumanoidMatchedBones.Count > 0)
|
||||
{
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> humanoidMatchedBone in config.clothesHumanoidMatchedBones)
|
||||
{
|
||||
HumanBodyBones key2 = humanoidMatchedBone.Key;
|
||||
HashSet<Transform> transformSet = humanoidMatchedBone.Value;
|
||||
if (transformSet != null && transformSet.Count != 0)
|
||||
{
|
||||
Transform boneTransform = animator.GetBoneTransform(key2);
|
||||
if (!Object.op_Equality((Object)boneTransform, (Object)null))
|
||||
{
|
||||
Transform transform2 = (Transform)null;
|
||||
int num1 = int.MaxValue;
|
||||
foreach (Transform transform3 in transformSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform3, (Object)null))
|
||||
{
|
||||
int num2 = 0;
|
||||
for (Transform transform4 = transform3; Object.op_Inequality((Object)transform4, (Object)null); transform4 = transform4.parent)
|
||||
++num2;
|
||||
if (num2 < num1)
|
||||
{
|
||||
num1 = num2;
|
||||
transform2 = transform3;
|
||||
}
|
||||
else if (num2 == num1 && Object.op_Inequality((Object)transform2, (Object)null) && string.Compare(((Object)transform3).name, ((Object)transform2).name, StringComparison.Ordinal) < 0)
|
||||
transform2 = transform3;
|
||||
}
|
||||
}
|
||||
if (!Object.op_Equality((Object)transform2, (Object)null) && !dictionary1.ContainsKey(boneTransform))
|
||||
dictionary1.Add(boneTransform, transform2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MeshClassifier meshClassifier = new MeshClassifier();
|
||||
HashSet<Transform> collection = new HashSet<Transform>();
|
||||
for (int index = 0; index < config.targetBodyMeshes.Count; ++index)
|
||||
{
|
||||
SkinnedMeshRenderer targetBodyMesh = config.targetBodyMeshes[index];
|
||||
if (!Object.op_Equality((Object)targetBodyMesh, (Object)null))
|
||||
{
|
||||
HashSet<Transform> activeBones = meshClassifier.GetActiveBones(targetBodyMesh);
|
||||
if (activeBones != null)
|
||||
{
|
||||
foreach (Transform transform5 in activeBones)
|
||||
{
|
||||
if (Object.op_Inequality((Object)transform5, (Object)null))
|
||||
collection.Add(transform5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
HashSet<Transform> transformSet1 = new HashSet<Transform>((IEnumerable<Transform>)collection);
|
||||
foreach (Transform transform6 in collection)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform6, (Object)null))
|
||||
{
|
||||
for (Transform transform7 = transform6; Object.op_Inequality((Object)transform7, (Object)null); transform7 = transform7.parent)
|
||||
{
|
||||
transformSet1.Add(transform7);
|
||||
if (Object.op_Equality((Object)transform7, (Object)key1))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Dictionary<Transform, Transform> dictionary2 = new Dictionary<Transform, Transform>(transformSet1.Count);
|
||||
Dictionary<Transform, Transform> dictionary3 = new Dictionary<Transform, Transform>(transformSet1.Count);
|
||||
foreach (Transform transform8 in transformSet1)
|
||||
{
|
||||
if (!Object.op_Equality((Object)transform8, (Object)null))
|
||||
{
|
||||
Transform transform9 = (Transform)null;
|
||||
Transform transform10;
|
||||
Transform reusableClothBone;
|
||||
if (dictionary1.TryGetValue(transform8, out transform10) && Object.op_Inequality((Object)transform10, (Object)null))
|
||||
{
|
||||
reusableClothBone = transform10;
|
||||
if (config.addAnchorBone)
|
||||
{
|
||||
transform9 = new GameObject(((Object)transform8).name).transform;
|
||||
transform9.SetParent(clothesArmature, false);
|
||||
transform9.position = transform8.position;
|
||||
transform9.rotation = transform8.rotation;
|
||||
transform9.localScale = Vector3.one;
|
||||
reusableClothBone.SetParent(transform9, true);
|
||||
((Object)reusableClothBone).name = ((Object)transform8).name + "_clothes";
|
||||
reusableClothBone.localPosition = Vector3.zero;
|
||||
reusableClothBone.localScale = Vector3.one;
|
||||
}
|
||||
else
|
||||
{
|
||||
((Object)reusableClothBone).name = ((Object)transform8).name;
|
||||
reusableClothBone.position = transform8.position;
|
||||
this.ChildBonePositionPreserve(reusableClothBone, transform8);
|
||||
reusableClothBone.localScale = !config.armatureBoneScaleCopy ? Vector3.one : transform8.localScale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reusableClothBone = new GameObject(((Object)transform8).name).transform;
|
||||
reusableClothBone.SetParent(clothesArmature, false);
|
||||
reusableClothBone.position = transform8.position;
|
||||
reusableClothBone.rotation = transform8.rotation;
|
||||
reusableClothBone.localScale = !config.armatureBoneScaleCopy ? Vector3.one : transform8.localScale;
|
||||
}
|
||||
if (!Object.op_Equality((Object)reusableClothBone, (Object)null))
|
||||
{
|
||||
dictionary2[transform8] = reusableClothBone;
|
||||
dictionary3[transform8] = Object.op_Inequality((Object)transform9, (Object)null) ? transform9 : reusableClothBone;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (Transform key3 in transformSet1)
|
||||
{
|
||||
if (!Object.op_Equality((Object)key3, (Object)null))
|
||||
{
|
||||
Transform transform11;
|
||||
if (!dictionary2.TryGetValue(key3, out transform11) || Object.op_Equality((Object)transform11, (Object)null))
|
||||
throw new AutoMorpherException("Mapped Clothes Bone is Missing", "[EdenAutoMorpherManager] CreateClothesArmature\n - clonedByOriginal does not contain originalBone or mappedClothesBone is null\n - originalBone: " + ((Object)key3).name);
|
||||
Transform transform12;
|
||||
if (!dictionary3.TryGetValue(key3, out transform12) || Object.op_Equality((Object)transform12, (Object)null))
|
||||
throw new AutoMorpherException("Mapped Anchor Bone is Missing", "[EdenAutoMorpherManager] CreateClothesArmature\n - parentAnchorByOriginal does not contain originalBone or mappedAnchorBone is null\n - originalBone: " + ((Object)key3).name);
|
||||
if (Object.op_Equality((Object)key3, (Object)key1))
|
||||
{
|
||||
transform12.SetParent(clothesArmature, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform parent = key3.parent;
|
||||
if (Object.op_Equality((Object)parent, (Object)null))
|
||||
{
|
||||
transform12.SetParent(clothesArmature, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform transform13;
|
||||
if (dictionary3.TryGetValue(parent, out transform13) && Object.op_Inequality((Object)transform13, (Object)null))
|
||||
transform12.SetParent(transform13, true);
|
||||
else
|
||||
transform12.SetParent(clothesArmature, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Transform transform14;
|
||||
if (!dictionary3.TryGetValue(key1, out transform14) || Object.op_Equality((Object)transform14, (Object)null))
|
||||
throw new AutoMorpherException("Cloned Humanoid Root Bone is Missing", "[EdenAutoMorpherManager] CreateClothesArmature\n - failed to map clone for HumanBodyBones.Hips");
|
||||
transform14.SetParent(clothesArmature, true);
|
||||
clonedBoneMap = dictionary2;
|
||||
return clothesArmature;
|
||||
}
|
||||
|
||||
private Transform FindArmature(EdenAutoMorpherConfig config, Transform clothesRoot)
|
||||
{
|
||||
if (Object.op_Equality((Object)clothesRoot, (Object)null))
|
||||
throw new AutoMorpherException("Armature Root Resolve Failed", "[EdenAutoMorpherManager] FindSingleArmatureRootFromHumanoidMatchedBones\n - config is null or clothesRoot is null");
|
||||
if (config.clothesHumanoidMatchedBones == null || config.clothesHumanoidMatchedBones.Count == 0)
|
||||
return (Transform)null;
|
||||
Transform transform = (Transform)null;
|
||||
bool flag = false;
|
||||
foreach (KeyValuePair<HumanBodyBones, HashSet<Transform>> humanoidMatchedBone in config.clothesHumanoidMatchedBones)
|
||||
{
|
||||
HashSet<Transform> transformSet = humanoidMatchedBone.Value;
|
||||
if (transformSet != null && transformSet.Count != 0)
|
||||
{
|
||||
foreach (Transform bone in transformSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)bone, (Object)null) && (!Object.op_Inequality((Object)bone, (Object)clothesRoot) || bone.IsChildOf(clothesRoot)))
|
||||
{
|
||||
flag = true;
|
||||
Transform topChildUnderRoot = this.GetTopChildUnderRoot(bone, clothesRoot);
|
||||
if (Object.op_Equality((Object)topChildUnderRoot, (Object)null) || Object.op_Equality((Object)topChildUnderRoot, (Object)clothesRoot))
|
||||
return (Transform)null;
|
||||
if (Object.op_Equality((Object)transform, (Object)null))
|
||||
transform = topChildUnderRoot;
|
||||
else if (Object.op_Inequality((Object)transform, (Object)topChildUnderRoot))
|
||||
return (Transform)null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
return (Transform)null;
|
||||
return Object.op_Equality((Object)transform, (Object)null) || Object.op_Equality((Object)transform, (Object)clothesRoot) ? (Transform)null : transform;
|
||||
}
|
||||
|
||||
private Transform GetTopChildUnderRoot(Transform bone, Transform clothesRoot)
|
||||
{
|
||||
if (Object.op_Equality((Object)bone, (Object)null) || Object.op_Equality((Object)clothesRoot, (Object)null))
|
||||
return (Transform)null;
|
||||
if (Object.op_Equality((Object)bone, (Object)clothesRoot))
|
||||
return clothesRoot;
|
||||
Transform transform = bone;
|
||||
while (Object.op_Inequality((Object)transform.parent, (Object)null) && Object.op_Inequality((Object)transform.parent, (Object)clothesRoot))
|
||||
transform = transform.parent;
|
||||
return Object.op_Equality((Object)transform.parent, (Object)clothesRoot) ? transform : clothesRoot;
|
||||
}
|
||||
|
||||
private void ChildBonePositionPreserve(Transform reusableClothBone, Transform referenceAvatarBone)
|
||||
{
|
||||
if (Object.op_Equality((Object)reusableClothBone, (Object)null) || Object.op_Equality((Object)referenceAvatarBone, (Object)null))
|
||||
throw new AutoMorpherException("Reusable Bone Sync Failed", "[EdenAutoMorpherManager] SyncReusableBoneRotationPreserveChildrenWorld\n - reusableClothBone or referenceAvatarBone is null");
|
||||
List<Transform> resultList = new List<Transform>();
|
||||
List<Vector3> vector3List = new List<Vector3>();
|
||||
List<Quaternion> quaternionList = new List<Quaternion>();
|
||||
for (int index = 0; index < reusableClothBone.childCount; ++index)
|
||||
{
|
||||
Transform child = reusableClothBone.GetChild(index);
|
||||
if (!Object.op_Equality((Object)child, (Object)null))
|
||||
this.CollectDescendants(child, resultList);
|
||||
}
|
||||
for (int index = 0; index < resultList.Count; ++index)
|
||||
{
|
||||
Transform transform = resultList[index];
|
||||
vector3List.Add(transform.position);
|
||||
quaternionList.Add(transform.rotation);
|
||||
}
|
||||
reusableClothBone.localRotation = referenceAvatarBone.localRotation;
|
||||
for (int index = 0; index < resultList.Count; ++index)
|
||||
resultList[index].SetPositionAndRotation(vector3List[index], quaternionList[index]);
|
||||
}
|
||||
|
||||
private void CollectDescendants(Transform root, List<Transform> resultList)
|
||||
{
|
||||
if (Object.op_Equality((Object)root, (Object)null))
|
||||
return;
|
||||
resultList.Add(root);
|
||||
for (int index = 0; index < root.childCount; ++index)
|
||||
{
|
||||
Transform child = root.GetChild(index);
|
||||
if (!Object.op_Equality((Object)child, (Object)null))
|
||||
this.CollectDescendants(child, resultList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 084d635978a925d4caec9538d24f3114
|
||||
218
Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs
Normal file
218
Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.MeshClassifier
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class MeshClassifier
|
||||
{
|
||||
private HumanBodyBones[] bodyBones;
|
||||
private HumanBodyBones[] headBones;
|
||||
|
||||
public SkinnedMeshRenderer GetBodyMesh(Transform root, Animator animator)
|
||||
{
|
||||
List<Transform> humanBoneTransforms = this.HumanBodyBonesTrsnforms(this.bodyBones, animator);
|
||||
if (humanBoneTransforms.Count == this.bodyBones.Length)
|
||||
return this.GetBoneMatchedMesh(root, humanBoneTransforms);
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
Debug.LogWarning((object)"[Body Mesh] Animator Bone is not enough");
|
||||
return (SkinnedMeshRenderer)null;
|
||||
}
|
||||
|
||||
public SkinnedMeshRenderer GetHeadMesh(Transform root, Animator animator)
|
||||
{
|
||||
List<Transform> humanBoneTransforms = this.HumanBodyBonesTrsnforms(this.headBones, animator);
|
||||
return humanBoneTransforms.Count != this.headBones.Length ? (SkinnedMeshRenderer)null : this.GetBoneMatchedMesh(root, humanBoneTransforms);
|
||||
}
|
||||
|
||||
private List<Transform> HumanBodyBonesTrsnforms(
|
||||
HumanBodyBones[] humanBonesList,
|
||||
Animator animator)
|
||||
{
|
||||
List<Transform> transformList = new List<Transform>();
|
||||
List<HumanBodyBones> values = new List<HumanBodyBones>();
|
||||
foreach (int humanBones in humanBonesList)
|
||||
{
|
||||
HumanBodyBones humanBodyBones = (HumanBodyBones)humanBones;
|
||||
Transform boneTransform = animator.GetBoneTransform(humanBodyBones);
|
||||
if (Object.op_Equality((Object)boneTransform, (Object)null))
|
||||
values.Add(humanBodyBones);
|
||||
else
|
||||
transformList.Add(boneTransform);
|
||||
}
|
||||
if (values.Count > 0)
|
||||
throw new AutoMorpherException("[Body Mesh Finding] Required Humanoid Bones are Missing", $"[BodyMeshUtil] HumanBodyBonesTrsnforms\n - Missing Humanoid Bones: [{string.Join<HumanBodyBones>(", ", (IEnumerable<HumanBodyBones>)values)}]\n - Animator Humanoid mapping may be broken\n - Please check whether the missing humanoid bones are correctly assigned in [Animator → Avatar → Configure].");
|
||||
return transformList;
|
||||
}
|
||||
|
||||
private SkinnedMeshRenderer GetBoneMatchedMesh(
|
||||
Transform root,
|
||||
List<Transform> humanBoneTransforms)
|
||||
{
|
||||
foreach (SkinnedMeshRenderer componentsInChild in ((Component)root).GetComponentsInChildren<SkinnedMeshRenderer>(false))
|
||||
{
|
||||
bool flag = true;
|
||||
HashSet<Transform> activeBones = this.GetActiveBones(componentsInChild);
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
Debug.Log((object)$"[Body Mesh] {((Object)((Component)componentsInChild).gameObject).name} have bone Set {activeBones.Count}");
|
||||
foreach (Transform humanBoneTransform in humanBoneTransforms)
|
||||
{
|
||||
if (!activeBones.Contains(humanBoneTransform) && !this.BoneExistsByPosition(humanBoneTransform, activeBones))
|
||||
{
|
||||
flag = false;
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
{
|
||||
Debug.Log((object)$"[Body Mesh] {((Object)((Component)componentsInChild).gameObject).name} Doesn't hav bone {((Object)humanBoneTransform).name}");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
return componentsInChild;
|
||||
}
|
||||
return (SkinnedMeshRenderer)null;
|
||||
}
|
||||
|
||||
private bool BoneExistsByPosition(
|
||||
Transform boneToCheck,
|
||||
HashSet<Transform> smrBoneSet,
|
||||
float posTolerance = 0.0001f)
|
||||
{
|
||||
foreach (Transform smrBone in smrBoneSet)
|
||||
{
|
||||
Vector3 vector3 = Vector3.op_Subtraction(smrBone.position, boneToCheck.position);
|
||||
if ((double)((Vector3)ref vector3).sqrMagnitude <= (double)posTolerance * (double)posTolerance)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public HashSet<Transform> GetActiveBones(SkinnedMeshRenderer smr, float weightThreshold = 0.0001f)
|
||||
{
|
||||
Mesh sharedMesh = smr.sharedMesh;
|
||||
if (Object.op_Equality((Object)sharedMesh, (Object)null))
|
||||
{
|
||||
Debug.LogWarning((object)"SkinnedMeshRenderer에 연결된 Mesh가 없습니다.");
|
||||
return new HashSet<Transform>();
|
||||
}
|
||||
Transform[] bones = smr.bones;
|
||||
BoneWeight[] boneWeights = sharedMesh.boneWeights;
|
||||
HashSet<int> intSet = new HashSet<int>();
|
||||
foreach (BoneWeight boneWeight in boneWeights)
|
||||
{
|
||||
if ((double)((BoneWeight)ref boneWeight).weight0 > (double)weightThreshold)
|
||||
intSet.Add(((BoneWeight)ref boneWeight).boneIndex0);
|
||||
if ((double)((BoneWeight)ref boneWeight).weight1 > (double)weightThreshold)
|
||||
intSet.Add(((BoneWeight)ref boneWeight).boneIndex1);
|
||||
if ((double)((BoneWeight)ref boneWeight).weight2 > (double)weightThreshold)
|
||||
intSet.Add(((BoneWeight)ref boneWeight).boneIndex2);
|
||||
if ((double)((BoneWeight)ref boneWeight).weight3 > (double)weightThreshold)
|
||||
intSet.Add(((BoneWeight)ref boneWeight).boneIndex3);
|
||||
}
|
||||
HashSet<Transform> activeBones = new HashSet<Transform>();
|
||||
foreach (int index in intSet)
|
||||
{
|
||||
if (index >= 0 && index < bones.Length)
|
||||
activeBones.Add(bones[index]);
|
||||
}
|
||||
return activeBones;
|
||||
}
|
||||
|
||||
public Dictionary<HumanBodyBones, HashSet<Transform>> MeshHumanoidBoneMatcher(
|
||||
Animator animator,
|
||||
IReadOnlyList<SkinnedMeshRenderer> bodyMeshes,
|
||||
float posTolerance = 0.0001f,
|
||||
float weightThreshold = 0.0001f)
|
||||
{
|
||||
Dictionary<HumanBodyBones, HashSet<Transform>> dictionary = new Dictionary<HumanBodyBones, HashSet<Transform>>();
|
||||
if (Object.op_Equality((Object)animator, (Object)null))
|
||||
throw new AutoMorpherException("Animator is Missing", "[MeshHumanoidBoneMatcher] MeshHumanoidBoneMatcher\n - animator is null");
|
||||
HashSet<Transform> smrBoneSet = new HashSet<Transform>();
|
||||
if (bodyMeshes != null)
|
||||
{
|
||||
foreach (SkinnedMeshRenderer bodyMesh in (IEnumerable<SkinnedMeshRenderer>)bodyMeshes)
|
||||
{
|
||||
if (!Object.op_Equality((Object)bodyMesh, (Object)null))
|
||||
{
|
||||
foreach (Transform activeBone in this.GetActiveBones(bodyMesh, weightThreshold))
|
||||
{
|
||||
if (Object.op_Inequality((Object)activeBone, (Object)null))
|
||||
smrBoneSet.Add(activeBone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int index = 0; index < 55; ++index)
|
||||
{
|
||||
HumanBodyBones key = (HumanBodyBones)index;
|
||||
Transform boneTransform = animator.GetBoneTransform(key);
|
||||
if (!Object.op_Equality((Object)boneTransform, (Object)null))
|
||||
{
|
||||
HashSet<Transform> transformSet = new HashSet<Transform>();
|
||||
transformSet.Add(boneTransform);
|
||||
foreach (Transform transform in this.FindBonesByPosition(boneTransform, smrBoneSet, posTolerance))
|
||||
transformSet.Add(transform);
|
||||
dictionary[key] = transformSet;
|
||||
}
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
private List<Transform> FindBonesByPosition(
|
||||
Transform boneToCheck,
|
||||
HashSet<Transform> smrBoneSet,
|
||||
float posTolerance = 0.0001f)
|
||||
{
|
||||
List<Transform> bonesByPosition = new List<Transform>();
|
||||
if (Object.op_Equality((Object)boneToCheck, (Object)null))
|
||||
return bonesByPosition;
|
||||
float num = posTolerance * posTolerance;
|
||||
Vector3 position = boneToCheck.position;
|
||||
foreach (Transform smrBone in smrBoneSet)
|
||||
{
|
||||
if (!Object.op_Equality((Object)smrBone, (Object)null) && !Object.op_Equality((Object)smrBone, (Object)boneToCheck) && this.NameMatches(((Object)((Component)smrBone).gameObject).name, ((Object)((Component)boneToCheck).gameObject).name))
|
||||
{
|
||||
Vector3 vector3 = Vector3.op_Subtraction(smrBone.position, position);
|
||||
if ((double)((Vector3)ref vector3).sqrMagnitude <= (double)num)
|
||||
bonesByPosition.Add(smrBone);
|
||||
}
|
||||
}
|
||||
return bonesByPosition;
|
||||
}
|
||||
|
||||
private string[] TokenizeBoneName(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return Array.Empty<string>();
|
||||
char[] separator = new char[5]
|
||||
{
|
||||
'-',
|
||||
'_',
|
||||
':',
|
||||
'.',
|
||||
'|'
|
||||
};
|
||||
name = name.Trim();
|
||||
return name.Split(separator, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
private bool NameMatches(string boneToCheckName, string candidateName)
|
||||
{
|
||||
string[] strArray1 = this.TokenizeBoneName(boneToCheckName);
|
||||
string[] strArray2 = this.TokenizeBoneName(candidateName);
|
||||
return strArray1.Length != 0 && strArray2.Length != 0 && strArray1[0].Equals(strArray2[0], StringComparison.OrdinalIgnoreCase) && (strArray1.Length <= 1 || strArray2.Length <= 1 || strArray1[1].Equals(strArray2[1], StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public MeshClassifier()
|
||||
{
|
||||
// ISSUE: unable to decompile the method.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d30a49a0209cbf44282af1dc59c279df
|
||||
208
Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs
Normal file
208
Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.MeshMatcher
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class MeshMatcher
|
||||
{
|
||||
public BvhTriangleMesh bodyBVH;
|
||||
private readonly HashSet<HumanBodyBones> LeftLegBones = new HashSet<HumanBodyBones>()
|
||||
{
|
||||
(HumanBodyBones) 1,
|
||||
(HumanBodyBones) 3,
|
||||
(HumanBodyBones) 5,
|
||||
(HumanBodyBones) 19
|
||||
};
|
||||
private readonly HashSet<HumanBodyBones> RightLegBones = new HashSet<HumanBodyBones>()
|
||||
{
|
||||
(HumanBodyBones) 2,
|
||||
(HumanBodyBones) 4,
|
||||
(HumanBodyBones) 6,
|
||||
(HumanBodyBones) 20
|
||||
};
|
||||
|
||||
public BvhTriangleMesh BuildBvhMulti(
|
||||
IReadOnlyList<SkinnedMeshRenderer> bodies,
|
||||
Animator bodyAnimator)
|
||||
{
|
||||
BvhTriangleMesh bvhTriangleMesh = bodies != null && bodies.Count != 0 ? new BvhTriangleMesh().BuildFromSkinnedMeshes(bodies, bodyAnimator) : throw new AutoMorpherException("Body Meshes are Missing", "[BuildBvhMulti] BuildBvhMulti\n - bodies is null or empty");
|
||||
if (bvhTriangleMesh == null || bvhTriangleMesh.triangles == null)
|
||||
{
|
||||
Debug.LogError((object)"Failed to build multi-body BVH (no triangles).");
|
||||
throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.BodyBVHFail"), LanguageManager.GetFormat("UI.Exception.message.BodyBVHFail", (object)((Object)((Component)bodyAnimator).gameObject).name, (object)(bvhTriangleMesh == null), (object)(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 (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((object)"clothes mesh has no vertices");
|
||||
return (Vector3[])null;
|
||||
}
|
||||
if (minDistance == null)
|
||||
Debug.LogWarning((object)"minDists is null");
|
||||
if (minDistance.Length != worldVertices.Length)
|
||||
Debug.LogWarning((object)"minDists.Length != worldVertexs.Length");
|
||||
Vector3[] vector3Array = new Vector3[worldVertices.Length];
|
||||
float num1 = maxMatchDistance * maxMatchDistance;
|
||||
for (int index = 0; index < worldVertices.Length; ++index)
|
||||
{
|
||||
if (clothInstance.excludedVertices[index])
|
||||
vector3Array[index] = Vector3.zero;
|
||||
else if (clothInstance.isInsideVertex[index])
|
||||
{
|
||||
vector3Array[index] = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
float num2 = minDistance[index] + defaultMinDist;
|
||||
BvhTriangleMesh.ClosestHit closestHit = !clothInstance.isLeftLegVertex[index] ? (!clothInstance.isRightLegVertex[index] ? this.bodyBVH.QueryClosest(worldVertices[index]) : this.bodyBVH.QueryClosest(worldVertices[index], this.RightLegBones)) : this.bodyBVH.QueryClosest(worldVertices[index], this.LeftLegBones);
|
||||
if (skipFootFitting && (closestHit.mainHumanBone == 5 || closestHit.mainHumanBone == 6 || closestHit.mainHumanBone == 20 || closestHit.mainHumanBone == 19))
|
||||
vector3Array[index] = Vector3.zero;
|
||||
else if ((double)closestHit.sqrDistance > (double)num1)
|
||||
{
|
||||
vector3Array[index] = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 vector3 = Vector3.op_Subtraction(closestHit.closestPoint, worldVertices[index]);
|
||||
Vector3 normalized = ((Vector3)ref vector3).normalized;
|
||||
float num3 = Vector3.Dot(normalized, ((Vector3)ref closestHit.normal).normalized);
|
||||
if ((double)num3 > 0.699999988079071)
|
||||
vector3Array[index] = Vector3.op_Subtraction(Vector3.op_Addition(closestHit.closestPoint, Vector3.op_Multiply(normalized, num2)), worldVertices[index]);
|
||||
else if ((double)num3 < -0.699999988079071)
|
||||
{
|
||||
if ((double)closestHit.sqrDistance < (double)num2 * (double)num2)
|
||||
vector3Array[index] = Vector3.op_Subtraction(Vector3.op_Subtraction(closestHit.closestPoint, Vector3.op_Multiply(normalized, num2)), worldVertices[index]);
|
||||
}
|
||||
else
|
||||
vector3Array[index] = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
return vector3Array;
|
||||
}
|
||||
|
||||
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((object)"clothes mesh has no vertices");
|
||||
return (Vector3[])null;
|
||||
}
|
||||
if (minDistance == null)
|
||||
Debug.LogWarning((object)"minDists is null");
|
||||
if (minDistance.Length != worldVertices.Length)
|
||||
Debug.LogWarning((object)"minDists.Length != worldVertexs.Length");
|
||||
Vector3[] vector3Array = new Vector3[worldVertices.Length];
|
||||
float num1 = maxMatchDistance * maxMatchDistance;
|
||||
bool[] isLeftLegVertex = clothInstance.isLeftLegVertex;
|
||||
bool[] isRightLegVertex = clothInstance.isRightLegVertex;
|
||||
for (int index = 0; index < worldVertices.Length; ++index)
|
||||
{
|
||||
if (clothInstance.excludedVertices[index])
|
||||
vector3Array[index] = Vector3.zero;
|
||||
else if (clothInstance.isInsideVertex[index])
|
||||
{
|
||||
vector3Array[index] = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
float num2 = minDistance[index] + defaultMinDist;
|
||||
BvhTriangleMesh.ClosestHit closestHit = !clothInstance.isLeftLegVertex[index] ? (!clothInstance.isRightLegVertex[index] ? this.bodyBVH.QueryClosest(worldVertices[index]) : this.bodyBVH.QueryClosest(worldVertices[index], this.RightLegBones)) : this.bodyBVH.QueryClosest(worldVertices[index], this.LeftLegBones);
|
||||
if ((double)closestHit.sqrDistance > (double)num1)
|
||||
vector3Array[index] = Vector3.zero;
|
||||
else if (closestHit.mainHumanBone == 5 || closestHit.mainHumanBone == 6 || closestHit.mainHumanBone == 20 || closestHit.mainHumanBone == 19)
|
||||
{
|
||||
vector3Array[index] = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 vector3 = Vector3.op_Subtraction(closestHit.closestPoint, worldVertices[index]);
|
||||
Vector3 normalized = ((Vector3)ref vector3).normalized;
|
||||
float num3 = Vector3.Dot(normalized, ((Vector3)ref closestHit.normal).normalized);
|
||||
if ((double)num3 < -0.699999988079071)
|
||||
vector3Array[index] = Vector3.op_Subtraction(Vector3.op_Subtraction(closestHit.closestPoint, Vector3.op_Multiply(normalized, num2)), worldVertices[index]);
|
||||
else if ((double)num3 < -0.699999988079071)
|
||||
{
|
||||
if ((double)closestHit.sqrDistance < (double)num2 * (double)num2)
|
||||
vector3Array[index] = Vector3.op_Subtraction(Vector3.op_Addition(closestHit.closestPoint, Vector3.op_Multiply(normalized, num2)), worldVertices[index]);
|
||||
}
|
||||
else
|
||||
vector3Array[index] = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
return vector3Array;
|
||||
}
|
||||
|
||||
public Vector3[] GetMinDistanceToBody(Vector3[] clothesVertices)
|
||||
{
|
||||
if (this.bodyBVH == null)
|
||||
throw new AutoMorpherException("sourceBodyBVH is null", "[MeshMatcher] GetMinDistanceToBodysourceBodyBVH is null");
|
||||
Vector3[] minDistanceToBody = clothesVertices != null && clothesVertices.Length != 0 ? new Vector3[clothesVertices.Length] : throw new AutoMorpherException("Source Vertices is null", "[MeshMatcher] GetMinDistanceToBodySource Vertices is null or no vertices");
|
||||
for (int index = 0; index < clothesVertices.Length; ++index)
|
||||
{
|
||||
Vector3 clothesVertex = clothesVertices[index];
|
||||
Vector3 vector3 = Vector3.op_Subtraction(this.bodyBVH.QueryClosest(clothesVertex).closestPoint, clothesVertex);
|
||||
minDistanceToBody[index] = vector3;
|
||||
}
|
||||
return minDistanceToBody;
|
||||
}
|
||||
|
||||
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((object)"clothes is null");
|
||||
throw new AutoMorpherException("Source Vertices is null", "[MeshMatcher] GetMinDistanceToBodySource Vertices is null or no vertices");
|
||||
}
|
||||
bool[] bodyInsideFlags = new bool[worldVertices.Length];
|
||||
for (int index = 0; index < worldVertices.Length; ++index)
|
||||
{
|
||||
BvhTriangleMesh.ClosestHit closestHit = this.bodyBVH.QueryClosest(worldVertices[index]);
|
||||
Vector3 vector3 = Vector3.op_Subtraction(closestHit.closestPoint, worldVertices[index]);
|
||||
float num = Vector3.Dot(((Vector3)ref vector3).normalized, ((Vector3)ref closestHit.normal).normalized);
|
||||
bodyInsideFlags[index] = (double)num > 0.0;
|
||||
}
|
||||
return bodyInsideFlags;
|
||||
}
|
||||
|
||||
public struct ClosestHit
|
||||
{
|
||||
public Vector3 closestP;
|
||||
public Vector3 direction;
|
||||
public Vector3 moveVector;
|
||||
public float distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8f0e392696b1cc4b84a811342b1c9a4
|
||||
16
Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs
Normal file
16
Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.MorpherMode
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public enum MorpherMode
|
||||
{
|
||||
AutoMorpher = 0,
|
||||
ManualMorpher = 1,
|
||||
ProfileMorpher = 2,
|
||||
ETC = 99, // 0x00000063
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 051a6a1f505d3684eaff6e056eb3daf5
|
||||
17
Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs
Normal file
17
Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.MorpherState
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public enum MorpherState
|
||||
{
|
||||
Idle,
|
||||
Fitting_Doing,
|
||||
Fitting_End,
|
||||
Weighting_Doing,
|
||||
Weighting_End,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2cbda2228845b345bd4473f31dbbf7f
|
||||
184
Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs
Normal file
184
Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.PcaUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class PcaUtil
|
||||
{
|
||||
public RegionStats ComputeRegionStats(IList<Vector3> points)
|
||||
{
|
||||
RegionStats regionStats = new RegionStats();
|
||||
if (points == null || points.Count == 0)
|
||||
return regionStats;
|
||||
int count = points.Count;
|
||||
Vector3 vector3_1 = Vector3.zero;
|
||||
for (int index = 0; index < count; ++index)
|
||||
vector3_1 = Vector3.op_Addition(vector3_1, points[index]);
|
||||
Vector3 vector3_2 = Vector3.op_Division(vector3_1, (float)count);
|
||||
float num1 = 0.0f;
|
||||
float num2 = 0.0f;
|
||||
float num3 = 0.0f;
|
||||
float num4 = 0.0f;
|
||||
float num5 = 0.0f;
|
||||
float num6 = 0.0f;
|
||||
for (int index = 0; index < count; ++index)
|
||||
{
|
||||
Vector3 vector3_3 = Vector3.op_Subtraction(points[index], vector3_2);
|
||||
num1 += vector3_3.x * vector3_3.x;
|
||||
num2 += vector3_3.x * vector3_3.y;
|
||||
num3 += vector3_3.x * vector3_3.z;
|
||||
num4 += vector3_3.y * vector3_3.y;
|
||||
num5 += vector3_3.y * vector3_3.z;
|
||||
num6 += vector3_3.z * vector3_3.z;
|
||||
}
|
||||
float num7 = 1f / (float)count;
|
||||
float[] eigenValues;
|
||||
Vector3[] eigenVectors;
|
||||
this.JacobiEigenDecomposition3x3(num1 * num7, num2 * num7, num3 * num7, num4 * num7, num5 * num7, num6 * num7, out eigenValues, out eigenVectors);
|
||||
int index1 = 0;
|
||||
if ((double)eigenValues[1] > (double)eigenValues[index1])
|
||||
index1 = 1;
|
||||
if ((double)eigenValues[2] > (double)eigenValues[index1])
|
||||
index1 = 2;
|
||||
Vector3 normalized = ((Vector3)ref eigenVectors[index1]).normalized;
|
||||
float num8 = float.PositiveInfinity;
|
||||
float num9 = float.NegativeInfinity;
|
||||
float num10 = 0.0f;
|
||||
for (int index2 = 0; index2 < count; ++index2)
|
||||
{
|
||||
float num11 = Vector3.Dot(Vector3.op_Subtraction(points[index2], vector3_2), normalized);
|
||||
if ((double)num11 < (double)num8)
|
||||
num8 = num11;
|
||||
if ((double)num11 > (double)num9)
|
||||
num9 = num11;
|
||||
Vector3 vector3_4 = Vector3.op_Addition(vector3_2, Vector3.op_Multiply(normalized, num11));
|
||||
Vector3 vector3_5 = Vector3.op_Subtraction(points[index2], vector3_4);
|
||||
float magnitude = ((Vector3)ref vector3_5).magnitude;
|
||||
num10 += magnitude;
|
||||
}
|
||||
regionStats.center = vector3_2;
|
||||
regionStats.principalAxis = normalized;
|
||||
regionStats.length = num9 - num8;
|
||||
regionStats.avgRadius = num10 / (float)count;
|
||||
return regionStats;
|
||||
}
|
||||
|
||||
private void JacobiEigenDecomposition3x3(
|
||||
float c00,
|
||||
float c01,
|
||||
float c02,
|
||||
float c11,
|
||||
float c12,
|
||||
float c22,
|
||||
out float[] eigenValues,
|
||||
out Vector3[] eigenVectors)
|
||||
{
|
||||
float[,] numArray1 = new float[3, 3]
|
||||
{
|
||||
{
|
||||
c00,
|
||||
c01,
|
||||
c02
|
||||
},
|
||||
{
|
||||
c01,
|
||||
c11,
|
||||
c12
|
||||
},
|
||||
{
|
||||
c02,
|
||||
c12,
|
||||
c22
|
||||
}
|
||||
};
|
||||
float[,] numArray2 = new float[3, 3]
|
||||
{
|
||||
{
|
||||
1f,
|
||||
0.0f,
|
||||
0.0f
|
||||
},
|
||||
{
|
||||
0.0f,
|
||||
1f,
|
||||
0.0f
|
||||
},
|
||||
{
|
||||
0.0f,
|
||||
0.0f,
|
||||
1f
|
||||
}
|
||||
};
|
||||
for (int index1 = 0; index1 < 32 /*0x20*/; ++index1)
|
||||
{
|
||||
int index2 = 0;
|
||||
int index3 = 1;
|
||||
float num1 = Mathf.Abs(numArray1[0, 1]);
|
||||
float num2 = Mathf.Abs(numArray1[0, 2]);
|
||||
if ((double)num2 > (double)num1)
|
||||
{
|
||||
num1 = num2;
|
||||
index2 = 0;
|
||||
index3 = 2;
|
||||
}
|
||||
float num3 = Mathf.Abs(numArray1[1, 2]);
|
||||
if ((double)num3 > (double)num1)
|
||||
{
|
||||
num1 = num3;
|
||||
index2 = 1;
|
||||
index3 = 2;
|
||||
}
|
||||
if ((double)num1 >= 1.000000013351432E-10)
|
||||
{
|
||||
float num4 = numArray1[index2, index2];
|
||||
float num5 = numArray1[index3, index3];
|
||||
float num6 = numArray1[index2, index3];
|
||||
double num7 = 0.5 * (double)Mathf.Atan2(2f * num6, num5 - num4);
|
||||
float num8 = Mathf.Cos((float)num7);
|
||||
float num9 = Mathf.Sin((float)num7);
|
||||
for (int index4 = 0; index4 < 3; ++index4)
|
||||
{
|
||||
if (index4 != index2 && index4 != index3)
|
||||
{
|
||||
float num10 = numArray1[index4, index2];
|
||||
float num11 = numArray1[index4, index3];
|
||||
numArray1[index4, index2] = (float)((double)num8 * (double)num10 - (double)num9 * (double)num11);
|
||||
numArray1[index2, index4] = numArray1[index4, index2];
|
||||
numArray1[index4, index3] = (float)((double)num9 * (double)num10 + (double)num8 * (double)num11);
|
||||
numArray1[index3, index4] = numArray1[index4, index3];
|
||||
}
|
||||
}
|
||||
float num12 = (float)((double)num8 * (double)num8 * (double)num4 - 2.0 * (double)num9 * (double)num8 * (double)num6 + (double)num9 * (double)num9 * (double)num5);
|
||||
float num13 = (float)((double)num9 * (double)num9 * (double)num4 + 2.0 * (double)num9 * (double)num8 * (double)num6 + (double)num8 * (double)num8 * (double)num5);
|
||||
numArray1[index2, index2] = num12;
|
||||
numArray1[index3, index3] = num13;
|
||||
numArray1[index2, index3] = 0.0f;
|
||||
numArray1[index3, index2] = 0.0f;
|
||||
for (int index5 = 0; index5 < 3; ++index5)
|
||||
{
|
||||
float num14 = numArray2[index5, index2];
|
||||
float num15 = numArray2[index5, index3];
|
||||
numArray2[index5, index2] = (float)((double)num8 * (double)num14 - (double)num9 * (double)num15);
|
||||
numArray2[index5, index3] = (float)((double)num9 * (double)num14 + (double)num8 * (double)num15);
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
eigenValues = new float[3];
|
||||
eigenVectors = new Vector3[3];
|
||||
eigenValues[0] = numArray1[0, 0];
|
||||
eigenValues[1] = numArray1[1, 1];
|
||||
eigenValues[2] = numArray1[2, 2];
|
||||
eigenVectors[0] = new Vector3(numArray2[0, 0], numArray2[1, 0], numArray2[2, 0]);
|
||||
eigenVectors[1] = new Vector3(numArray2[0, 1], numArray2[1, 1], numArray2[2, 1]);
|
||||
eigenVectors[2] = new Vector3(numArray2[0, 2], numArray2[1, 2], numArray2[2, 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19d0bd017b9aa7f4681275eda30241ed
|
||||
15
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs
Normal file
15
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.ProcessInfo
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public struct ProcessInfo
|
||||
{
|
||||
public string title;
|
||||
public string text;
|
||||
public float progress;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d43dcdb2d1bafb4a97b6a14f9f954e5
|
||||
244
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs
Normal file
244
Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.profile.ProfileLoader
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher.profile;
|
||||
|
||||
public class ProfileLoader
|
||||
{
|
||||
private ProfileData loadedProfileData;
|
||||
private const int HEX32_W = 8;
|
||||
|
||||
public List<string> GetProfileList()
|
||||
{
|
||||
string path1 = Path.Combine(Application.dataPath, new ProfileUtils().GetProfileBasePath());
|
||||
List<string> profileList = new List<string>();
|
||||
if (!Directory.Exists(path1))
|
||||
{
|
||||
Debug.LogWarning((object)("[ProfileUtils] Profile base path does not exist: " + path1));
|
||||
return profileList;
|
||||
}
|
||||
foreach (string directory in Directory.GetDirectories(path1))
|
||||
{
|
||||
string fileName = Path.GetFileName(directory);
|
||||
if (!string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
string path2 = Path.Combine(directory, fileName + ".json");
|
||||
string path3 = Path.Combine(directory, fileName + ".eb");
|
||||
if (File.Exists(path2) && File.Exists(path3))
|
||||
profileList.Add(fileName);
|
||||
}
|
||||
}
|
||||
return profileList;
|
||||
}
|
||||
|
||||
public ProfileData LoadProfileData(string profileName)
|
||||
{
|
||||
string path = Path.Combine(Path.Combine(Path.Combine(Application.dataPath, new ProfileUtils().GetProfileBasePath()), profileName), profileName + ".json");
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
throw new AutoMorpherException("Profile File Path is Invalid", "[ProfileLoader] LoadProfileData\n - Profile Path is null, empty, or whitespace");
|
||||
this.loadedProfileData = File.Exists(path) ? JsonUtility.FromJson<ProfileData>(File.ReadAllText(path)) : throw new AutoMorpherException("Profile File Does Not Exist", "[ProfileLoader] LoadProfileData\n - profile file does not exist\n - path : " + path);
|
||||
return this.loadedProfileData != null ? this.loadedProfileData : 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);
|
||||
}
|
||||
|
||||
public BvhTriangleMesh LoadBvhWithRootTransform(Transform rootTransform, string profileName)
|
||||
{
|
||||
string path = Path.Combine(Path.Combine(Path.Combine(Application.dataPath, new ProfileUtils().GetProfileBasePath()), profileName), profileName + ".eb");
|
||||
if (Object.op_Equality((Object)rootTransform, (Object)null))
|
||||
throw new AutoMorpherException("Root Transform is Null", "[ProfileLoader] LoadBvhWithRootTransform\n - rootTransform is null");
|
||||
ProfileBVH profileBvh = !string.IsNullOrEmpty(path) ? this.LoadProfileBVHData(path, out int _) : throw new AutoMorpherException("Profile BVH Path is Invalid", "[ProfileLoader] LoadBvhWithRootTransform\n - profileBvhPath is null or empty");
|
||||
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 length = profileBvh.datas.Length;
|
||||
BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh()
|
||||
{
|
||||
triangles = new BvhTriangle[length],
|
||||
triIndices = new int[profileBvh.dataIndices.Length],
|
||||
nodes = new BvhNode[profileBvh.nodes.Length]
|
||||
};
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
profileBVHData data = profileBvh.datas[index];
|
||||
Vector3 vertex1 = profileBvh.vertices[data.verA];
|
||||
Vector3 vertex2 = profileBvh.vertices[data.verB];
|
||||
Vector3 vertex3 = profileBvh.vertices[data.verC];
|
||||
Vector3 a = ((Matrix4x4)ref localToWorldMatrix).MultiplyPoint3x4(vertex1);
|
||||
Vector3 b = ((Matrix4x4)ref localToWorldMatrix).MultiplyPoint3x4(vertex2);
|
||||
Vector3 c = ((Matrix4x4)ref localToWorldMatrix).MultiplyPoint3x4(vertex3);
|
||||
Vector3 triangleNormal = this.ComputeTriangleNormal(a, b, c);
|
||||
bvhTriangleMesh.triangles[index] = new BvhTriangle()
|
||||
{
|
||||
a = a,
|
||||
b = b,
|
||||
c = c,
|
||||
normal = triangleNormal,
|
||||
mainHumanBone = (HumanBodyBones)55
|
||||
};
|
||||
}
|
||||
Array.Copy((Array)profileBvh.dataIndices, (Array)bvhTriangleMesh.triIndices, profileBvh.dataIndices.Length);
|
||||
for (int index = 0; index < profileBvh.nodes.Length; ++index)
|
||||
{
|
||||
profileBVHNode node = profileBvh.nodes[index];
|
||||
bvhTriangleMesh.nodes[index] = new BvhNode()
|
||||
{
|
||||
isLeaf = node.isLeaf,
|
||||
leftChild = node.leftChild,
|
||||
rightChild = node.rightChild,
|
||||
start = node.start,
|
||||
count = node.count,
|
||||
bounds = this.TransformBoundsToWorldAABB(localToWorldMatrix, node.bounds)
|
||||
};
|
||||
}
|
||||
return bvhTriangleMesh;
|
||||
}
|
||||
|
||||
private ProfileBVH LoadProfileBVHData(string path, out int version)
|
||||
{
|
||||
version = 0;
|
||||
string s = File.Exists(path) ? File.ReadAllText(path, Encoding.UTF8) : throw new AutoMorpherException("Profile BVH File Not Found", "[ProfileLoader] LoadProfileBVHData\n - file not found\n - path : " + path);
|
||||
int num = 0;
|
||||
ProfileUtils profileUtils = new ProfileUtils();
|
||||
string profileMagic = profileUtils.GetProfileMagic();
|
||||
if (s.Length < profileMagic.Length || s.Substring(0, profileMagic.Length) != profileMagic)
|
||||
throw new AutoMorpherException("Profile BVH Magic Mismatch", "[ProfileLoader] LoadProfileBVHData\n - magic string mismatch\n - invalid or corrupted BVH file");
|
||||
int p = num + profileMagic.Length;
|
||||
version = this.ReadHexIntSafe(s, ref p);
|
||||
int seed = this.ReadHexIntSafe(s, ref p);
|
||||
int capacity = this.ReadHexIntSafe(s, ref p);
|
||||
int length1 = this.ReadHexIntSafe(s, ref p);
|
||||
int length2 = this.ReadHexIntSafe(s, ref p);
|
||||
int length3 = this.ReadHexIntSafe(s, ref p);
|
||||
if (capacity < 0 || length1 < 0 || length2 < 0 || length3 < 0)
|
||||
throw new AutoMorpherException("Profile BVH Count Data is Invalid", "[ProfileLoader] LoadProfileBVHData\n - one or more count values are negative");
|
||||
Vector3[] encoded = new Vector3[capacity];
|
||||
for (int index = 0; index < capacity; ++index)
|
||||
encoded[index] = this.ReadHexVec3Safe(s, ref p);
|
||||
BaseKey3[] baseKey3Array = new ProfileUtils_VertexUtil().LoadTable(profileUtils.GetBaseDataPath(), out int _, out int _);
|
||||
if (baseKey3Array == null || baseKey3Array.Length == 0)
|
||||
throw new AutoMorpherException("Profile BVH Base Vertex Table is Invalid", "[ProfileLoader] LoadProfileBVHData\n - base vertex table is null or empty");
|
||||
ProfileUtil_IndexUtil profileUtilIndexUtil = new ProfileUtil_IndexUtil();
|
||||
profileUtilIndexUtil.Build(seed);
|
||||
Vector3[] output = new Vector3[capacity];
|
||||
profileUtilIndexUtil.DecodeInto(encoded, output);
|
||||
Vector3[] collection = new Vector3[capacity];
|
||||
for (int index = 0; index < capacity; ++index)
|
||||
collection[index] = this.TransformVec3(output[index], baseKey3Array[index % baseKey3Array.Length]);
|
||||
ProfileBVH profileBvh = new ProfileBVH()
|
||||
{
|
||||
vertices = new List<Vector3>(capacity),
|
||||
datas = new profileBVHData[length1],
|
||||
nodes = new profileBVHNode[length2],
|
||||
dataIndices = new int[length3]
|
||||
};
|
||||
profileBvh.vertices.AddRange((IEnumerable<Vector3>)collection);
|
||||
for (int index = 0; index < length1; ++index)
|
||||
profileBvh.datas[index] = new profileBVHData()
|
||||
{
|
||||
verA = this.ReadHexIntSafe(s, ref p),
|
||||
verB = this.ReadHexIntSafe(s, ref p),
|
||||
verC = this.ReadHexIntSafe(s, ref p)
|
||||
};
|
||||
for (int index = 0; index < length2; ++index)
|
||||
{
|
||||
Vector3 vector3_1 = this.ReadHexVec3Safe(s, ref p);
|
||||
Vector3 vector3_2 = this.ReadHexVec3Safe(s, ref p);
|
||||
profileBvh.nodes[index] = new profileBVHNode()
|
||||
{
|
||||
bounds = new Bounds(vector3_1, Vector3.op_Multiply(vector3_2, 2f)),
|
||||
leftChild = this.ReadHexIntSafe(s, ref p),
|
||||
rightChild = this.ReadHexIntSafe(s, ref p),
|
||||
start = this.ReadHexIntSafe(s, ref p),
|
||||
count = this.ReadHexIntSafe(s, ref p),
|
||||
isLeaf = p < s.Length && s[p++] == '1'
|
||||
};
|
||||
}
|
||||
for (int index = 0; index < length3; ++index)
|
||||
profileBvh.dataIndices[index] = this.ReadHexIntSafe(s, ref p);
|
||||
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");
|
||||
}
|
||||
int uint32 = (int)Convert.ToUInt32(s.Substring(p, 8), 16 /*0x10*/);
|
||||
p += 8;
|
||||
return uint32;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
int uint32 = (int)Convert.ToUInt32(s.Substring(p, 8), 16 /*0x10*/);
|
||||
p += 8;
|
||||
return BitConverter.Int32BitsToSingle(uint32);
|
||||
}
|
||||
|
||||
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 Vector3 ComputeTriangleNormal(Vector3 a, Vector3 b, Vector3 c)
|
||||
{
|
||||
Vector3 vector3 = Vector3.Cross(Vector3.op_Subtraction(b, a), Vector3.op_Subtraction(c, a));
|
||||
float magnitude = ((Vector3)ref vector3).magnitude;
|
||||
return (double)magnitude > 9.99999993922529E-09 ? Vector3.op_Division(vector3, magnitude) : Vector3.up;
|
||||
}
|
||||
|
||||
private Bounds TransformBoundsToWorldAABB(Matrix4x4 l2w, Bounds localBounds)
|
||||
{
|
||||
Vector3 center = ((Bounds)ref localBounds).center;
|
||||
Vector3 extents = ((Bounds)ref localBounds).extents;
|
||||
Vector3 vector3 = ((Matrix4x4)ref l2w).MultiplyPoint3x4(Vector3.op_Addition(center, new Vector3(-extents.x, -extents.y, -extents.z)));
|
||||
Vector3 p1 = ((Matrix4x4)ref l2w).MultiplyPoint3x4(Vector3.op_Addition(center, new Vector3(-extents.x, -extents.y, extents.z)));
|
||||
Vector3 p2 = ((Matrix4x4)ref l2w).MultiplyPoint3x4(Vector3.op_Addition(center, new Vector3(-extents.x, extents.y, -extents.z)));
|
||||
Vector3 p3 = ((Matrix4x4)ref l2w).MultiplyPoint3x4(Vector3.op_Addition(center, new Vector3(-extents.x, extents.y, extents.z)));
|
||||
Vector3 p4 = ((Matrix4x4)ref l2w).MultiplyPoint3x4(Vector3.op_Addition(center, new Vector3(extents.x, -extents.y, -extents.z)));
|
||||
Vector3 p5 = ((Matrix4x4)ref l2w).MultiplyPoint3x4(Vector3.op_Addition(center, new Vector3(extents.x, -extents.y, extents.z)));
|
||||
Vector3 p6 = ((Matrix4x4)ref l2w).MultiplyPoint3x4(Vector3.op_Addition(center, new Vector3(extents.x, extents.y, -extents.z)));
|
||||
Vector3 p7 = ((Matrix4x4)ref l2w).MultiplyPoint3x4(Vector3.op_Addition(center, new Vector3(extents.x, extents.y, extents.z)));
|
||||
Vector3 min = vector3;
|
||||
Vector3 max = vector3;
|
||||
this.Encapsulate(ref min, ref max, p1);
|
||||
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(Vector3.op_Multiply(Vector3.op_Addition(min, max), 0.5f), Vector3.op_Subtraction(max, min));
|
||||
}
|
||||
|
||||
private void Encapsulate(ref Vector3 min, ref Vector3 max, Vector3 p)
|
||||
{
|
||||
min = Vector3.Min(min, p);
|
||||
max = Vector3.Max(max, p);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a9626ae72afe0240b059a130fd80049
|
||||
@@ -0,0 +1,72 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.profile.ProfilePoseMatchUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher.profile;
|
||||
|
||||
public class ProfilePoseMatchUtil
|
||||
{
|
||||
private WorldVertexUtil _worldVertexUtil;
|
||||
private MeshClassifier 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 (Object.op_Equality((Object)targetAvatar, (Object)null))
|
||||
throw new AutoMorpherException("Target Avatar is Null", "[ProfilePoseMatchUtil] ProfilePoseMatcher\n - targetAvatar is null");
|
||||
if (Object.op_Equality((Object)targetAvatar.GetComponent<Animator>(), (Object)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 (Object.op_Equality((Object)targetCloth, (Object)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 transform1 = targetAvatar.transform;
|
||||
Transform transform2 = targetCloth.transform;
|
||||
Transform parent1 = transform1.parent;
|
||||
transform1.SetParent((Transform)null, true);
|
||||
Transform parent2 = transform2.parent;
|
||||
transform2.SetParent((Transform)null, true);
|
||||
transform2.position = transform1.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 poseMatchSetupUtil = new BodyPoseMatchSetupUtil();
|
||||
Vector3 comprehensiveScale = poseMatchSetupUtil.GetComprehensiveScale(transform2, clothHumanBonesMap, profileData);
|
||||
Debug.Log((object)$"ComprehensiveScale: {comprehensiveScale}");
|
||||
poseMatchSetupUtil.AdjustAvatarScaleByNeck(transform1, dictionary, neckTargetHeight);
|
||||
poseMatchSetupUtil.AdjustAvatarScaleByNeck(transform2, clothHumanBonesMap, neckTargetHeight);
|
||||
List<BakedBodyMesh> targetBakedBodyMeshes = new List<BakedBodyMesh>();
|
||||
foreach (SkinnedMeshRenderer targetBodyMesh in (IEnumerable<SkinnedMeshRenderer>)targetBodyMeshes)
|
||||
targetBakedBodyMeshes.Add(new BakedBodyMesh(targetBodyMesh));
|
||||
new BodyPoseMatch_Torso().AlignTorsoByNeck(transform1, (IReadOnlyList<BakedBodyMesh>)targetBakedBodyMeshes, dictionary, clothHumanBonesMap, transform2, profileData, comprehensiveScale);
|
||||
BodyPoseMatch_Arm bodyPoseMatchArm = new BodyPoseMatch_Arm();
|
||||
bodyPoseMatchArm.AlignUpperArmByArmPcaCenters((IReadOnlyList<BakedBodyMesh>)targetBakedBodyMeshes, dictionary, clothHumanBonesMap, transform2, profileData, comprehensiveScale);
|
||||
bodyPoseMatchArm.ScalingBothArmsLength((IReadOnlyList<BakedBodyMesh>)targetBakedBodyMeshes, dictionary, clothHumanBonesMap, profileData, comprehensiveScale);
|
||||
BodyPoseMatch_Leg bodyPoseMatchLeg = new BodyPoseMatch_Leg();
|
||||
bodyPoseMatchLeg.AlignBothUpperLegs(transform1, (IReadOnlyList<BakedBodyMesh>)targetBakedBodyMeshes, dictionary, transform2, clothHumanBonesMap, profileData, comprehensiveScale);
|
||||
bodyPoseMatchLeg.ScalingBothLegsAndFoots(transform1, (IReadOnlyList<BakedBodyMesh>)targetBakedBodyMeshes, dictionary, transform2, clothHumanBonesMap, profileData, comprehensiveScale);
|
||||
transform1.SetParent(parent1, true);
|
||||
transform2.SetParent(parent2, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fed47961631fd674ba17c72e9df7d471
|
||||
18
Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs
Normal file
18
Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.RegionStats
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public struct RegionStats
|
||||
{
|
||||
public Vector3 center;
|
||||
public Vector3 principalAxis;
|
||||
public float length;
|
||||
public float avgRadius;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: daf685816cce49240b2ff0f269905ef5
|
||||
248
Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs
Normal file
248
Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs
Normal file
@@ -0,0 +1,248 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.SkinningUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class SkinningUtil
|
||||
{
|
||||
public Vector3 WorldPosToBindPos(
|
||||
SkinnedMeshRenderer smr,
|
||||
Mesh bindMesh,
|
||||
int vertexIndex,
|
||||
Vector3 targetWorld)
|
||||
{
|
||||
if (Object.op_Equality((Object)smr, (Object)null) || Object.op_Equality((Object)bindMesh, (Object)null))
|
||||
return Vector3.zero;
|
||||
BoneWeight[] boneWeights = bindMesh.boneWeights;
|
||||
Matrix4x4[] bindposes = bindMesh.bindposes;
|
||||
Transform[] bones = smr.bones;
|
||||
if (boneWeights == null || bindposes == null || bones == null)
|
||||
return ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
if (vertexIndex < 0 || vertexIndex >= boneWeights.Length)
|
||||
return ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
if (bindposes.Length != bones.Length)
|
||||
return ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
BoneWeight boneWeight = boneWeights[vertexIndex];
|
||||
bool flag1 = ((BoneWeight)ref boneWeight).boneIndex0 >= 0 && ((BoneWeight)ref boneWeight).boneIndex0 < bones.Length && Object.op_Inequality((Object)bones[((BoneWeight)ref boneWeight).boneIndex0], (Object)null) && (double)((BoneWeight)ref boneWeight).weight0 > 0.0;
|
||||
bool flag2 = ((BoneWeight)ref boneWeight).boneIndex1 >= 0 && ((BoneWeight)ref boneWeight).boneIndex1 < bones.Length && Object.op_Inequality((Object)bones[((BoneWeight)ref boneWeight).boneIndex1], (Object)null) && (double)((BoneWeight)ref boneWeight).weight1 > 0.0;
|
||||
bool flag3 = ((BoneWeight)ref boneWeight).boneIndex2 >= 0 && ((BoneWeight)ref boneWeight).boneIndex2 < bones.Length && Object.op_Inequality((Object)bones[((BoneWeight)ref boneWeight).boneIndex2], (Object)null) && (double)((BoneWeight)ref boneWeight).weight2 > 0.0;
|
||||
int num1 = ((BoneWeight)ref boneWeight).boneIndex3 < 0 || ((BoneWeight)ref boneWeight).boneIndex3 >= bones.Length || !Object.op_Inequality((Object)bones[((BoneWeight)ref boneWeight).boneIndex3], (Object)null) ? 0 : ((double)((BoneWeight)ref boneWeight).weight3 > 0.0 ? 1 : 0);
|
||||
float num2 = flag1 ? ((BoneWeight)ref boneWeight).weight0 : 0.0f;
|
||||
float num3 = flag2 ? ((BoneWeight)ref boneWeight).weight1 : 0.0f;
|
||||
float num4 = flag3 ? ((BoneWeight)ref boneWeight).weight2 : 0.0f;
|
||||
float num5 = num1 != 0 ? ((BoneWeight)ref boneWeight).weight3 : 0.0f;
|
||||
float num6 = num2 + num3 + num4 + num5;
|
||||
if ((double)num6 <= 9.99999993922529E-09)
|
||||
return ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
float w1 = num2 / num6;
|
||||
float w2 = num3 / num6;
|
||||
float w3 = num4 / num6;
|
||||
float w4 = num5 / num6;
|
||||
Vector3 bindPos1 = ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
Matrix4x4 objWorldInv = ((Component)smr).transform.worldToLocalMatrix;
|
||||
Matrix4x4 zero = Matrix4x4.zero;
|
||||
if ((double)w1 > 0.0)
|
||||
Acc(ref zero, ((BoneWeight)ref boneWeight).boneIndex0, w1);
|
||||
if ((double)w2 > 0.0)
|
||||
Acc(ref zero, ((BoneWeight)ref boneWeight).boneIndex1, w2);
|
||||
if ((double)w3 > 0.0)
|
||||
Acc(ref zero, ((BoneWeight)ref boneWeight).boneIndex2, w3);
|
||||
if ((double)w4 > 0.0)
|
||||
Acc(ref zero, ((BoneWeight)ref boneWeight).boneIndex3, w4);
|
||||
if ((double)Mathf.Abs((float)((double)zero.m00 * ((double)zero.m11 * (double)zero.m22 - (double)zero.m12 * (double)zero.m21) - (double)zero.m01 * ((double)zero.m10 * (double)zero.m22 - (double)zero.m12 * (double)zero.m20) + (double)zero.m02 * ((double)zero.m10 * (double)zero.m21 - (double)zero.m11 * (double)zero.m20))) < 9.999999960041972E-13)
|
||||
return bindPos1;
|
||||
zero.m33 = 1f;
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.Inverse(zero);
|
||||
Vector3 bindPos2 = ((Matrix4x4)ref matrix4x4).MultiplyPoint3x4(bindPos1);
|
||||
Debug.Log((object)$"Diff{Vector3.op_Subtraction(((Component)smr).transform.TransformPoint(bindPos2), targetWorld)}");
|
||||
return bindPos2;
|
||||
|
||||
void Acc(ref Matrix4x4 acc, int boneIndex, float w)
|
||||
{
|
||||
if ((double)w <= 0.0)
|
||||
return;
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.op_Multiply(Matrix4x4.op_Multiply(objWorldInv, bones[boneIndex].localToWorldMatrix), bindposes[boneIndex]);
|
||||
acc.m00 += matrix4x4.m00 * w;
|
||||
acc.m01 += matrix4x4.m01 * w;
|
||||
acc.m02 += matrix4x4.m02 * w;
|
||||
acc.m10 += matrix4x4.m10 * w;
|
||||
acc.m11 += matrix4x4.m11 * w;
|
||||
acc.m12 += matrix4x4.m12 * w;
|
||||
acc.m20 += matrix4x4.m20 * w;
|
||||
acc.m21 += matrix4x4.m21 * w;
|
||||
acc.m22 += matrix4x4.m22 * w;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 WorldPosToBindPos_Full(
|
||||
SkinnedMeshRenderer smr,
|
||||
Mesh bindMesh,
|
||||
int vertexIndex,
|
||||
Vector3 targetWorld)
|
||||
{
|
||||
if (Object.op_Equality((Object)smr, (Object)null) || Object.op_Equality((Object)bindMesh, (Object)null))
|
||||
return Vector3.zero;
|
||||
BoneWeight[] boneWeights = bindMesh.boneWeights;
|
||||
Matrix4x4[] bindposes = bindMesh.bindposes;
|
||||
Transform[] bones = smr.bones;
|
||||
if (boneWeights == null || bindposes == null || bones == null)
|
||||
return ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
if (vertexIndex < 0 || vertexIndex >= boneWeights.Length)
|
||||
return ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
if (bindposes.Length != bones.Length)
|
||||
return ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
BoneWeight boneWeight = boneWeights[vertexIndex];
|
||||
float[] numArray1 = new float[4];
|
||||
int[] numArray2 = new int[4];
|
||||
numArray1[0] = ((BoneWeight)ref boneWeight).weight0;
|
||||
numArray2[0] = ((BoneWeight)ref boneWeight).boneIndex0;
|
||||
numArray1[1] = ((BoneWeight)ref boneWeight).weight1;
|
||||
numArray2[1] = ((BoneWeight)ref boneWeight).boneIndex1;
|
||||
numArray1[2] = ((BoneWeight)ref boneWeight).weight2;
|
||||
numArray2[2] = ((BoneWeight)ref boneWeight).boneIndex2;
|
||||
numArray1[3] = ((BoneWeight)ref boneWeight).weight3;
|
||||
numArray2[3] = ((BoneWeight)ref boneWeight).boneIndex3;
|
||||
float num = 0.0f;
|
||||
for (int index = 0; index < 4; ++index)
|
||||
{
|
||||
if (numArray2[index] >= 0 && numArray2[index] < bones.Length && Object.op_Inequality((Object)bones[numArray2[index]], (Object)null))
|
||||
num += numArray1[index];
|
||||
}
|
||||
if ((double)num < 9.99999993922529E-09)
|
||||
return ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
for (int index = 0; index < 4; ++index)
|
||||
numArray1[index] /= num;
|
||||
Vector3 bindPosFull = ((Component)smr).transform.InverseTransformPoint(targetWorld);
|
||||
Vector4 vector4;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector4)ref vector4).\u002Ector(bindPosFull.x, bindPosFull.y, bindPosFull.z, 1f);
|
||||
Matrix4x4 objWorldInv = ((Component)smr).transform.worldToLocalMatrix;
|
||||
Matrix4x4 zero = Matrix4x4.zero;
|
||||
for (int index = 0; index < 4; ++index)
|
||||
{
|
||||
if ((double)numArray1[index] > 0.0 && numArray2[index] >= 0 && numArray2[index] < bones.Length)
|
||||
Accumulate(ref zero, numArray2[index], numArray1[index]);
|
||||
}
|
||||
if ((double)Mathf.Abs((float)((double)zero.m00 * ((double)zero.m11 * (double)zero.m22 - (double)zero.m12 * (double)zero.m21) - (double)zero.m01 * ((double)zero.m10 * (double)zero.m22 - (double)zero.m12 * (double)zero.m20) + (double)zero.m02 * ((double)zero.m10 * (double)zero.m21 - (double)zero.m11 * (double)zero.m20))) < 9.999999960041972E-13)
|
||||
return bindPosFull;
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.Inverse(zero);
|
||||
return ((Matrix4x4)ref matrix4x4).MultiplyPoint3x4(Vector4.op_Implicit(vector4));
|
||||
|
||||
void Accumulate(ref Matrix4x4 acc, int bi, float w)
|
||||
{
|
||||
if ((double)w <= 0.0)
|
||||
return;
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.op_Multiply(Matrix4x4.op_Multiply(objWorldInv, bones[bi].localToWorldMatrix), bindposes[bi]);
|
||||
acc.m00 += matrix4x4.m00 * w;
|
||||
acc.m01 += matrix4x4.m01 * w;
|
||||
acc.m02 += matrix4x4.m02 * w;
|
||||
acc.m03 += matrix4x4.m03 * w;
|
||||
acc.m10 += matrix4x4.m10 * w;
|
||||
acc.m11 += matrix4x4.m11 * w;
|
||||
acc.m12 += matrix4x4.m12 * w;
|
||||
acc.m13 += matrix4x4.m13 * w;
|
||||
acc.m20 += matrix4x4.m20 * w;
|
||||
acc.m21 += matrix4x4.m21 * w;
|
||||
acc.m22 += matrix4x4.m22 * w;
|
||||
acc.m23 += matrix4x4.m23 * w;
|
||||
acc.m30 += matrix4x4.m30 * w;
|
||||
acc.m31 += matrix4x4.m31 * w;
|
||||
acc.m32 += matrix4x4.m32 * w;
|
||||
acc.m33 += matrix4x4.m33 * w;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 WorldDirToBindDir_Full(
|
||||
SkinnedMeshRenderer smr,
|
||||
Mesh bindMesh,
|
||||
int vertexIndex,
|
||||
Vector3 targetWorldDir)
|
||||
{
|
||||
if (Object.op_Equality((Object)smr, (Object)null) || Object.op_Equality((Object)bindMesh, (Object)null))
|
||||
return Vector3.zero;
|
||||
BoneWeight[] boneWeights = bindMesh.boneWeights;
|
||||
Matrix4x4[] bindposes = bindMesh.bindposes;
|
||||
Transform[] bones = smr.bones;
|
||||
if (boneWeights == null || bindposes == null || bones == null)
|
||||
{
|
||||
Vector3 vector3 = ((Component)smr).transform.InverseTransformDirection(targetWorldDir);
|
||||
return ((Vector3)ref vector3).normalized;
|
||||
}
|
||||
if (vertexIndex < 0 || vertexIndex >= boneWeights.Length)
|
||||
{
|
||||
Vector3 vector3 = ((Component)smr).transform.InverseTransformDirection(targetWorldDir);
|
||||
return ((Vector3)ref vector3).normalized;
|
||||
}
|
||||
if (bindposes.Length != bones.Length)
|
||||
{
|
||||
Vector3 vector3 = ((Component)smr).transform.InverseTransformDirection(targetWorldDir);
|
||||
return ((Vector3)ref vector3).normalized;
|
||||
}
|
||||
BoneWeight boneWeight = boneWeights[vertexIndex];
|
||||
float[] numArray1 = new float[4];
|
||||
int[] numArray2 = new int[4];
|
||||
numArray1[0] = ((BoneWeight)ref boneWeight).weight0;
|
||||
numArray2[0] = ((BoneWeight)ref boneWeight).boneIndex0;
|
||||
numArray1[1] = ((BoneWeight)ref boneWeight).weight1;
|
||||
numArray2[1] = ((BoneWeight)ref boneWeight).boneIndex1;
|
||||
numArray1[2] = ((BoneWeight)ref boneWeight).weight2;
|
||||
numArray2[2] = ((BoneWeight)ref boneWeight).boneIndex2;
|
||||
numArray1[3] = ((BoneWeight)ref boneWeight).weight3;
|
||||
numArray2[3] = ((BoneWeight)ref boneWeight).boneIndex3;
|
||||
float num = 0.0f;
|
||||
for (int index = 0; index < 4; ++index)
|
||||
{
|
||||
if (numArray2[index] >= 0 && numArray2[index] < bones.Length && Object.op_Inequality((Object)bones[numArray2[index]], (Object)null))
|
||||
num += numArray1[index];
|
||||
}
|
||||
if ((double)num < 9.99999993922529E-09)
|
||||
{
|
||||
Vector3 vector3 = ((Component)smr).transform.InverseTransformDirection(targetWorldDir);
|
||||
return ((Vector3)ref vector3).normalized;
|
||||
}
|
||||
for (int index = 0; index < 4; ++index)
|
||||
numArray1[index] /= num;
|
||||
Vector3 vector3_1 = ((Component)smr).transform.InverseTransformDirection(targetWorldDir);
|
||||
if ((double)((Vector3)ref vector3_1).sqrMagnitude < 9.999999960041972E-13)
|
||||
return Vector3.up;
|
||||
Matrix4x4 objWorldInv = ((Component)smr).transform.worldToLocalMatrix;
|
||||
Matrix4x4 zero = Matrix4x4.zero;
|
||||
for (int index = 0; index < 4; ++index)
|
||||
{
|
||||
if ((double)numArray1[index] > 0.0 && numArray2[index] >= 0 && numArray2[index] < bones.Length)
|
||||
Accumulate(ref zero, numArray2[index], numArray1[index]);
|
||||
}
|
||||
Matrix4x4 transpose = ((Matrix4x4)ref zero).transpose;
|
||||
Vector3 vector3_2 = ((Matrix4x4)ref transpose).MultiplyVector(vector3_1);
|
||||
return (double)((Vector3)ref vector3_2).sqrMagnitude < 9.999999960041972E-13 ? ((Vector3)ref vector3_1).normalized : ((Vector3)ref vector3_2).normalized;
|
||||
|
||||
void Accumulate(ref Matrix4x4 acc, int bi, float w)
|
||||
{
|
||||
if ((double)w <= 0.0)
|
||||
return;
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.op_Multiply(Matrix4x4.op_Multiply(objWorldInv, bones[bi].localToWorldMatrix), bindposes[bi]);
|
||||
acc.m00 += matrix4x4.m00 * w;
|
||||
acc.m01 += matrix4x4.m01 * w;
|
||||
acc.m02 += matrix4x4.m02 * w;
|
||||
acc.m03 += matrix4x4.m03 * w;
|
||||
acc.m10 += matrix4x4.m10 * w;
|
||||
acc.m11 += matrix4x4.m11 * w;
|
||||
acc.m12 += matrix4x4.m12 * w;
|
||||
acc.m13 += matrix4x4.m13 * w;
|
||||
acc.m20 += matrix4x4.m20 * w;
|
||||
acc.m21 += matrix4x4.m21 * w;
|
||||
acc.m22 += matrix4x4.m22 * w;
|
||||
acc.m23 += matrix4x4.m23 * w;
|
||||
acc.m30 += matrix4x4.m30 * w;
|
||||
acc.m31 += matrix4x4.m31 * w;
|
||||
acc.m32 += matrix4x4.m32 * w;
|
||||
acc.m33 += matrix4x4.m33 * w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ac3681bc6b089040940247042effe43
|
||||
15
Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs
Normal file
15
Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: TempBoneMarker
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class TempBoneMarker : MonoBehaviour
|
||||
{
|
||||
public Transform originalParent;
|
||||
public string additionalInfo = "";
|
||||
public List<string> wrappedChildNames = new List<string>();
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87c4265006020574d9a04594d52dc1af
|
||||
64
Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs
Normal file
64
Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.TransformInfo
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class TransformInfo
|
||||
{
|
||||
public Transform parentTransform;
|
||||
public Vector3 position;
|
||||
public Vector3 localPosition;
|
||||
public Quaternion rotation;
|
||||
public Quaternion localRotation;
|
||||
public Vector3 localScale;
|
||||
public string 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 = ((Object)t).name;
|
||||
}
|
||||
|
||||
public void ApplyToTransform(
|
||||
Transform t,
|
||||
bool applyParent,
|
||||
bool applyPosition,
|
||||
bool applyRotation,
|
||||
bool applyScale,
|
||||
bool applyName = false)
|
||||
{
|
||||
if (applyParent)
|
||||
{
|
||||
t.SetParent(this.parentTransform, 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)
|
||||
return;
|
||||
((Object)t).name = this.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9fd2f46f9215e90489540d2e347e6601
|
||||
56
Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs
Normal file
56
Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.TriangleUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class TriangleUtil
|
||||
{
|
||||
public Vector3 ClosestPointOnTriangle(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
|
||||
{
|
||||
Vector3 vector3_1 = Vector3.op_Subtraction(b, a);
|
||||
Vector3 vector3_2 = Vector3.op_Subtraction(c, a);
|
||||
Vector3 vector3_3 = Vector3.op_Subtraction(p, a);
|
||||
float num1 = Vector3.Dot(vector3_1, vector3_3);
|
||||
float num2 = Vector3.Dot(vector3_2, vector3_3);
|
||||
if ((double)num1 <= 0.0 && (double)num2 <= 0.0)
|
||||
return a;
|
||||
Vector3 vector3_4 = Vector3.op_Subtraction(p, b);
|
||||
float num3 = Vector3.Dot(vector3_1, vector3_4);
|
||||
float num4 = Vector3.Dot(vector3_2, vector3_4);
|
||||
if ((double)num3 >= 0.0 && (double)num4 <= (double)num3)
|
||||
return b;
|
||||
float num5 = (float)((double)num1 * (double)num4 - (double)num3 * (double)num2);
|
||||
if ((double)num5 <= 0.0 && (double)num1 >= 0.0 && (double)num3 <= 0.0)
|
||||
{
|
||||
float num6 = num1 / (num1 - num3);
|
||||
return Vector3.op_Addition(a, Vector3.op_Multiply(num6, vector3_1));
|
||||
}
|
||||
Vector3 vector3_5 = Vector3.op_Subtraction(p, c);
|
||||
float num7 = Vector3.Dot(vector3_1, vector3_5);
|
||||
float num8 = Vector3.Dot(vector3_2, vector3_5);
|
||||
if ((double)num8 >= 0.0 && (double)num7 <= (double)num8)
|
||||
return c;
|
||||
float num9 = (float)((double)num7 * (double)num2 - (double)num1 * (double)num8);
|
||||
if ((double)num9 <= 0.0 && (double)num2 >= 0.0 && (double)num8 <= 0.0)
|
||||
{
|
||||
float num10 = num2 / (num2 - num8);
|
||||
return Vector3.op_Addition(a, Vector3.op_Multiply(num10, vector3_2));
|
||||
}
|
||||
float num11 = (float)((double)num3 * (double)num8 - (double)num7 * (double)num4);
|
||||
if ((double)num11 <= 0.0 && (double)num4 - (double)num3 >= 0.0 && (double)num7 - (double)num8 >= 0.0)
|
||||
{
|
||||
float num12 = (float)(((double)num4 - (double)num3) / ((double)num4 - (double)num3 + ((double)num7 - (double)num8)));
|
||||
return Vector3.op_Addition(b, Vector3.op_Multiply(num12, Vector3.op_Subtraction(c, b)));
|
||||
}
|
||||
float num13 = (float)(1.0 / ((double)num11 + (double)num9 + (double)num5));
|
||||
float num14 = num9 * num13;
|
||||
float num15 = num5 * num13;
|
||||
return Vector3.op_Addition(Vector3.op_Addition(a, Vector3.op_Multiply(vector3_1, num14)), Vector3.op_Multiply(vector3_2, num15));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 309eb633b62714c4e9fe0151790830cb
|
||||
680
Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs
Normal file
680
Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs
Normal file
@@ -0,0 +1,680 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.VertexFittingUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class VertexFittingUtil
|
||||
{
|
||||
public void ExpandClothes_World_Test(
|
||||
List<ClothInstance> clothInstances,
|
||||
MeshMatcher meshMatcher,
|
||||
EdenAutoMorpherConfig config,
|
||||
ClothInstanceTotal clothInstanceTotal)
|
||||
{
|
||||
using (AutoMorpherDev.Profile("[Expand] BVH Mesh Matching time"))
|
||||
{
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
clothInstance.deltas = meshMatcher.ExpandVertexMatch(clothInstance, config.minMargin, config.skipFootFitting);
|
||||
}
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
clothInstance.deltasLocal = clothInstance.deltas;
|
||||
Vector3[] globalDeltas = clothInstanceTotal.GlobalDeltas;
|
||||
clothInstanceTotal.UpdateGlobalBuffersFromClothInstances();
|
||||
this.SmoothDeltasByDistance(clothInstanceTotal.GlobalPositions, ref globalDeltas, clothInstanceTotal.GlobalAdjacencyMerged, config.worldRadius, 1, config.smoothingIteration, gaussianSigma: config.sigma);
|
||||
clothInstanceTotal.SetGlobalDeltas(globalDeltas);
|
||||
clothInstanceTotal.ApplyGlobalDeltasToClothInstances();
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
{
|
||||
for (int index = 0; index < clothInstance.worldVertices.Length; ++index)
|
||||
{
|
||||
if (!clothInstance.excludedVertices[index] || !clothInstance.isInsideVertex[index])
|
||||
{
|
||||
ref Vector3 local = ref clothInstance.worldVertices[index];
|
||||
local = Vector3.op_Addition(local, clothInstance.deltasLocal[index]);
|
||||
}
|
||||
clothInstance.deltasLocal[index] = Vector3.zero;
|
||||
}
|
||||
foreach (List<int> equivalentVertex in clothInstance.equivalentVertices)
|
||||
{
|
||||
Vector3 vector3_1 = Vector3.zero;
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
vector3_1 = Vector3.op_Addition(vector3_1, clothInstance.worldVertices[equivalentVertex[index]]);
|
||||
Vector3 vector3_2 = Vector3.op_Division(vector3_1, (float)equivalentVertex.Count);
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
clothInstance.worldVertices[equivalentVertex[index]] = vector3_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ShrinkClothes_World_Test(
|
||||
List<ClothInstance> clothInstances,
|
||||
MeshMatcher meshMatcher,
|
||||
EdenAutoMorpherConfig config,
|
||||
ClothInstanceTotal clothInstanceTotal)
|
||||
{
|
||||
using (AutoMorpherDev.Profile("[Expand] BVH Mesh Matching time"))
|
||||
{
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
clothInstance.deltas = meshMatcher.ShrinkVertexMatch(clothInstance, config.minMargin);
|
||||
}
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
clothInstance.deltasLocal = clothInstance.deltas;
|
||||
Vector3[] globalDeltas = clothInstanceTotal.GlobalDeltas;
|
||||
clothInstanceTotal.UpdateGlobalBuffersFromClothInstances();
|
||||
this.SmoothDeltasByDistance(clothInstanceTotal.GlobalPositions, ref globalDeltas, clothInstanceTotal.GlobalAdjacencyMerged, config.worldRadius, iterations: config.smoothingIteration, gaussianSigma: config.sigma);
|
||||
clothInstanceTotal.SetGlobalDeltas(globalDeltas);
|
||||
clothInstanceTotal.ApplyGlobalDeltasToClothInstances();
|
||||
this.SmoothAllClothesDeltasByDistance(clothInstances, config.worldRadius, config.smoothingIteration, config.sigma);
|
||||
foreach (ClothInstance clothInstance in clothInstances)
|
||||
{
|
||||
for (int index = 0; index < clothInstance.worldVertices.Length; ++index)
|
||||
{
|
||||
if (!clothInstance.excludedVertices[index] || !clothInstance.isInsideVertex[index])
|
||||
{
|
||||
ref Vector3 local = ref clothInstance.worldVertices[index];
|
||||
local = Vector3.op_Addition(local, clothInstance.deltasLocal[index]);
|
||||
}
|
||||
clothInstance.deltasLocal[index] = Vector3.zero;
|
||||
}
|
||||
foreach (List<int> equivalentVertex in clothInstance.equivalentVertices)
|
||||
{
|
||||
Vector3 vector3_1 = Vector3.zero;
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
vector3_1 = Vector3.op_Addition(vector3_1, clothInstance.worldVertices[equivalentVertex[index]]);
|
||||
Vector3 vector3_2 = Vector3.op_Division(vector3_1, (float)equivalentVertex.Count);
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
clothInstance.worldVertices[equivalentVertex[index]] = vector3_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ExpandClothes_World(
|
||||
ClothInstance clothInstance,
|
||||
List<ClothInstance> clothInstances,
|
||||
MeshMatcher meshMatcher,
|
||||
EdenAutoMorpherConfig config,
|
||||
float fittingRadius)
|
||||
{
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
Debug.Log((object)$"[Expand] Start {((Object)((Component)clothInstance.smr).gameObject).name}//===============================================================================================================");
|
||||
Stopwatch stopwatch1 = AutoMorpherDev.isDeveloperMode ? Stopwatch.StartNew() : (Stopwatch)null;
|
||||
Stopwatch.StartNew();
|
||||
using (AutoMorpherDev.Profile("[Expand] BVH Mesh Matching time"))
|
||||
clothInstance.deltas = meshMatcher.ExpandVertexMatch(clothInstance, config.minMargin, config.skipFootFitting);
|
||||
List<int> intList = (List<int>)null;
|
||||
using (AutoMorpherDev.Profile("[Expand] Select Anchors time"))
|
||||
intList = this.SelectAnchors(clothInstance, fittingRadius);
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
Debug.Log((object)$"[Expand] Anchor Count {intList.Count}");
|
||||
if (intList.Count == 0)
|
||||
{
|
||||
if (!AutoMorpherDev.isDeveloperMode)
|
||||
return;
|
||||
stopwatch1.Stop();
|
||||
Debug.Log((object)$"[Expand] TOTAL ShrinkClothes time: {stopwatch1.ElapsedMilliseconds} ms");
|
||||
Debug.Log((object)$"[Expand] End {((Object)((Component)clothInstance.smr).gameObject).name}//===============================================================================================================");
|
||||
}
|
||||
else
|
||||
{
|
||||
Stopwatch stopwatch2 = AutoMorpherDev.isDeveloperMode ? Stopwatch.StartNew() : (Stopwatch)null;
|
||||
float num1 = 0.0f;
|
||||
float num2 = 0.0f;
|
||||
VertexMoverUtil vertexMoverUtil = new VertexMoverUtil();
|
||||
foreach (int targetVertexIdx in intList)
|
||||
{
|
||||
if (!clothInstance.excludedVertices[targetVertexIdx])
|
||||
{
|
||||
Stopwatch stopwatch3 = AutoMorpherDev.isDeveloperMode ? Stopwatch.StartNew() : (Stopwatch)null;
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
{
|
||||
Debug.Log((object)$"[Expand] Selected Expand Vertes: {((Object)((Component)clothInstance.smr).gameObject).name} / {targetVertexIdx}");
|
||||
Debug.Log((object)$"[Expand] SelectedCEnter {targetVertexIdx} {clothInstance.deltas[targetVertexIdx]} {clothInstance.worldVertices[targetVertexIdx]}");
|
||||
}
|
||||
Vector3[] vector3Array1 = vertexMoverUtil.MoveVertices(clothInstance, targetVertexIdx, clothInstance.isLeftLegVertex[targetVertexIdx], clothInstance.isRightLegVertex[targetVertexIdx], fittingRadius, config.sigma, clothInstance.deltas[targetVertexIdx]);
|
||||
if (vector3Array1 == null)
|
||||
{
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
{
|
||||
stopwatch3.Stop();
|
||||
num1 += (float)stopwatch3.ElapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index = 0; index < clothInstance.worldVertices.Length && index < vector3Array1.Length; ++index)
|
||||
{
|
||||
if (Vector3.op_Inequality(vector3Array1[index], Vector3.zero))
|
||||
{
|
||||
ref Vector3 local = ref clothInstance.deltasLocal[index];
|
||||
local = Vector3.op_Addition(local, vector3Array1[index]);
|
||||
}
|
||||
}
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
{
|
||||
stopwatch3.Stop();
|
||||
num1 += (float)stopwatch3.ElapsedMilliseconds;
|
||||
}
|
||||
Stopwatch stopwatch4 = AutoMorpherDev.isDeveloperMode ? Stopwatch.StartNew() : (Stopwatch)null;
|
||||
using (List<ClothInstance>.Enumerator enumerator = clothInstances.GetEnumerator())
|
||||
{
|
||||
label_38:
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
ClothInstance current = enumerator.Current;
|
||||
if (current != clothInstance)
|
||||
{
|
||||
Vector3[] vector3Array2 = vertexMoverUtil.MoveVertices(current, clothInstance.worldVertices[targetVertexIdx], clothInstance.isLeftLegVertex[targetVertexIdx], clothInstance.isRightLegVertex[targetVertexIdx], fittingRadius, config.sigma, clothInstance.deltas[targetVertexIdx]);
|
||||
if (vector3Array2 != null)
|
||||
{
|
||||
int index = 0;
|
||||
while (true)
|
||||
{
|
||||
if (index < current.worldVertices.Length && index < vector3Array2.Length)
|
||||
{
|
||||
if (Vector3.op_Inequality(vector3Array2[index], Vector3.zero))
|
||||
{
|
||||
ref Vector3 local = ref current.deltasLocal[index];
|
||||
local = Vector3.op_Addition(local, vector3Array2[index]);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
else
|
||||
goto label_38;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
{
|
||||
stopwatch4.Stop();
|
||||
num2 += (float)stopwatch4.ElapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.SmoothAllClothesDeltasByDistance(clothInstances, fittingRadius, config.smoothingIteration, config.sigma);
|
||||
foreach (ClothInstance clothInstance1 in clothInstances)
|
||||
{
|
||||
for (int index = 0; index < clothInstance1.worldVertices.Length; ++index)
|
||||
{
|
||||
if (!clothInstance1.excludedVertices[index])
|
||||
{
|
||||
ref Vector3 local = ref clothInstance1.worldVertices[index];
|
||||
local = Vector3.op_Addition(local, clothInstance1.deltasLocal[index]);
|
||||
}
|
||||
clothInstance1.deltasLocal[index] = Vector3.zero;
|
||||
}
|
||||
foreach (List<int> equivalentVertex in clothInstance1.equivalentVertices)
|
||||
{
|
||||
Vector3 vector3_1 = Vector3.zero;
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
vector3_1 = Vector3.op_Addition(vector3_1, clothInstance1.worldVertices[equivalentVertex[index]]);
|
||||
Vector3 vector3_2 = Vector3.op_Division(vector3_1, (float)equivalentVertex.Count);
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
clothInstance1.worldVertices[equivalentVertex[index]] = vector3_2;
|
||||
}
|
||||
}
|
||||
if (!AutoMorpherDev.isDeveloperMode)
|
||||
return;
|
||||
stopwatch2.Stop();
|
||||
Debug.Log((object)$"[Expand] Renderer Move Vector Calculate: {((Object)((Component)clothInstance.smr).gameObject).name} : {num1}");
|
||||
Debug.Log((object)$"[Expand] Other Renderer Move Vector Calculate: {((Object)((Component)clothInstance.smr).gameObject).name} : {num2}");
|
||||
Debug.Log((object)$"[Expand] Total Move Vector Calculate: {((Object)((Component)clothInstance.smr).gameObject).name} : {stopwatch2.ElapsedMilliseconds}");
|
||||
stopwatch1.Stop();
|
||||
Debug.Log((object)$"[Expand] TOTAL ShrinkClothes time: {stopwatch1.ElapsedMilliseconds} ms");
|
||||
Debug.Log((object)$"[Expand] End {((Object)((Component)clothInstance.smr).gameObject).name}//===============================================================================================================");
|
||||
}
|
||||
}
|
||||
|
||||
public void ShrinkClothes_World(
|
||||
ClothInstance clothInstance,
|
||||
List<ClothInstance> clothInstances,
|
||||
MeshMatcher meshMatcher,
|
||||
EdenAutoMorpherConfig config,
|
||||
float fittingRadius)
|
||||
{
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
Debug.Log((object)$"[Shrink] Start {((Object)((Component)clothInstance.smr).gameObject).name}//===============================================================================================================");
|
||||
Stopwatch stopwatch1 = AutoMorpherDev.isDeveloperMode ? Stopwatch.StartNew() : (Stopwatch)null;
|
||||
using (AutoMorpherDev.Profile("[Shrink] BVH Mesh Matching time"))
|
||||
clothInstance.deltas = meshMatcher.ShrinkVertexMatch(clothInstance, config.minMargin);
|
||||
List<int> intList = (List<int>)null;
|
||||
using (AutoMorpherDev.Profile("[Shrink] Select Anchors time"))
|
||||
intList = this.SelectAnchors(clothInstance, fittingRadius);
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
Debug.Log((object)$"[Shrink] Anchor Count {intList.Count}");
|
||||
if (intList.Count == 0)
|
||||
{
|
||||
if (!AutoMorpherDev.isDeveloperMode)
|
||||
return;
|
||||
stopwatch1.Stop();
|
||||
Debug.Log((object)$"[Shrink] TOTAL ShrinkClothes time: {stopwatch1.ElapsedMilliseconds} ms");
|
||||
Debug.Log((object)$"[Shrink] End {((Object)((Component)clothInstance.smr).gameObject).name}//===============================================================================================================");
|
||||
}
|
||||
else
|
||||
{
|
||||
Stopwatch stopwatch2 = AutoMorpherDev.isDeveloperMode ? Stopwatch.StartNew() : (Stopwatch)null;
|
||||
float num1 = 0.0f;
|
||||
float num2 = 0.0f;
|
||||
VertexMoverUtil vertexMoverUtil = new VertexMoverUtil();
|
||||
foreach (int targetVertexIdx in intList)
|
||||
{
|
||||
if (!clothInstance.excludedVertices[targetVertexIdx])
|
||||
{
|
||||
Stopwatch stopwatch3 = AutoMorpherDev.isDeveloperMode ? Stopwatch.StartNew() : (Stopwatch)null;
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
{
|
||||
Debug.Log((object)$"[Shrink] Selected Expand Vertes: {((Object)((Component)clothInstance.smr).gameObject).name} / {targetVertexIdx}");
|
||||
Debug.Log((object)$"[Shrink] SelectedCEnter {targetVertexIdx} {clothInstance.deltas[targetVertexIdx]} {clothInstance.worldVertices[targetVertexIdx]}");
|
||||
}
|
||||
Vector3[] vector3Array1 = vertexMoverUtil.MoveVertices(clothInstance, targetVertexIdx, clothInstance.isLeftLegVertex[targetVertexIdx], clothInstance.isRightLegVertex[targetVertexIdx], fittingRadius, config.sigma, clothInstance.deltas[targetVertexIdx]);
|
||||
if (vector3Array1 == null)
|
||||
{
|
||||
stopwatch3.Stop();
|
||||
num1 += (float)stopwatch3.ElapsedMilliseconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int index = 0; index < clothInstance.worldVertices.Length && index < vector3Array1.Length; ++index)
|
||||
{
|
||||
if (Vector3.op_Inequality(vector3Array1[index], Vector3.zero))
|
||||
{
|
||||
ref Vector3 local = ref clothInstance.deltasLocal[index];
|
||||
local = Vector3.op_Addition(local, vector3Array1[index]);
|
||||
}
|
||||
}
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
{
|
||||
stopwatch3.Stop();
|
||||
num1 += (float)stopwatch3.ElapsedMilliseconds;
|
||||
}
|
||||
Stopwatch stopwatch4 = AutoMorpherDev.isDeveloperMode ? Stopwatch.StartNew() : (Stopwatch)null;
|
||||
using (List<ClothInstance>.Enumerator enumerator = clothInstances.GetEnumerator())
|
||||
{
|
||||
label_37:
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
ClothInstance current = enumerator.Current;
|
||||
if (current != clothInstance)
|
||||
{
|
||||
Vector3[] vector3Array2 = vertexMoverUtil.MoveVertices(current, clothInstance.worldVertices[targetVertexIdx], clothInstance.isLeftLegVertex[targetVertexIdx], clothInstance.isRightLegVertex[targetVertexIdx], fittingRadius, config.sigma, clothInstance.deltas[targetVertexIdx]);
|
||||
if (vector3Array2 != null)
|
||||
{
|
||||
int index = 0;
|
||||
while (true)
|
||||
{
|
||||
if (index < current.worldVertices.Length && index < vector3Array2.Length)
|
||||
{
|
||||
if (Vector3.op_Inequality(vector3Array2[index], Vector3.zero))
|
||||
{
|
||||
ref Vector3 local = ref current.deltasLocal[index];
|
||||
local = Vector3.op_Addition(local, vector3Array2[index]);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
else
|
||||
goto label_37;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AutoMorpherDev.isDeveloperMode)
|
||||
{
|
||||
stopwatch4.Stop();
|
||||
num2 += (float)stopwatch4.ElapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.SmoothAllClothesDeltasByDistance(clothInstances, fittingRadius, config.smoothingIteration, config.sigma);
|
||||
foreach (ClothInstance clothInstance1 in clothInstances)
|
||||
{
|
||||
for (int index = 0; index < clothInstance1.worldVertices.Length; ++index)
|
||||
{
|
||||
if (!clothInstance1.excludedVertices[index])
|
||||
{
|
||||
ref Vector3 local = ref clothInstance1.worldVertices[index];
|
||||
local = Vector3.op_Addition(local, clothInstance1.deltasLocal[index]);
|
||||
}
|
||||
clothInstance1.deltasLocal[index] = Vector3.zero;
|
||||
}
|
||||
foreach (List<int> equivalentVertex in clothInstance1.equivalentVertices)
|
||||
{
|
||||
Vector3 vector3_1 = Vector3.zero;
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
vector3_1 = Vector3.op_Addition(vector3_1, clothInstance1.worldVertices[equivalentVertex[index]]);
|
||||
Vector3 vector3_2 = Vector3.op_Division(vector3_1, (float)equivalentVertex.Count);
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
clothInstance1.worldVertices[equivalentVertex[index]] = vector3_2;
|
||||
}
|
||||
}
|
||||
if (!AutoMorpherDev.isDeveloperMode)
|
||||
return;
|
||||
stopwatch2.Stop();
|
||||
Debug.Log((object)$"[Shrink] Renderer Move Vector Calculate: {((Object)((Component)clothInstance.smr).gameObject).name} : {num1}");
|
||||
Debug.Log((object)$"[Shrink] Other Renderer Move Vector Calculate: {((Object)((Component)clothInstance.smr).gameObject).name} : {num2}");
|
||||
Debug.Log((object)$"[Shrink] Total Move Vector Calculate: {((Object)((Component)clothInstance.smr).gameObject).name} : {stopwatch2.ElapsedMilliseconds}");
|
||||
stopwatch1.Stop();
|
||||
Debug.Log((object)$"[Shrink] TOTAL ShrinkClothes time: {stopwatch1.ElapsedMilliseconds} ms");
|
||||
Debug.Log((object)$"[Shrink] End {((Object)((Component)clothInstance.smr).gameObject).name}//===============================================================================================================");
|
||||
}
|
||||
}
|
||||
|
||||
public void ExpandFitClothes_World(
|
||||
ClothInstance clothInstance,
|
||||
List<ClothInstance> clothInstances,
|
||||
MeshMatcher meshMatcher,
|
||||
float worldRadius,
|
||||
float sigma,
|
||||
float minMargin)
|
||||
{
|
||||
Debug.Log((object)$"[Expand] {((Object)((Component)clothInstance.smr).gameObject).name}//===============================================================================================================");
|
||||
Stopwatch stopwatch1 = Stopwatch.StartNew();
|
||||
Stopwatch stopwatch2 = Stopwatch.StartNew();
|
||||
clothInstance.deltas = meshMatcher.ExpandVertexMatch(clothInstance, minMargin);
|
||||
stopwatch2.Stop();
|
||||
Debug.Log((object)$"[Expand] BVH Mesh Matching time: {stopwatch2.ElapsedMilliseconds} ms");
|
||||
for (int index = 0; index < clothInstance.worldVertices.Length; ++index)
|
||||
{
|
||||
ref Vector3 local = ref clothInstance.worldVertices[index];
|
||||
local = Vector3.op_Addition(local, clothInstance.deltas[index]);
|
||||
clothInstance.deltasLocal[index] = Vector3.zero;
|
||||
}
|
||||
foreach (List<int> equivalentVertex in clothInstance.equivalentVertices)
|
||||
{
|
||||
Vector3 vector3_1 = Vector3.zero;
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
vector3_1 = Vector3.op_Addition(vector3_1, clothInstance.worldVertices[equivalentVertex[index]]);
|
||||
Vector3 vector3_2 = Vector3.op_Division(vector3_1, (float)equivalentVertex.Count);
|
||||
for (int index = 0; index < equivalentVertex.Count; ++index)
|
||||
clothInstance.worldVertices[equivalentVertex[index]] = vector3_2;
|
||||
}
|
||||
stopwatch1.Stop();
|
||||
Debug.Log((object)$"[Expand] TOTAL ShrinkClothes time: {stopwatch1.ElapsedMilliseconds} ms");
|
||||
Debug.Log((object)$"[Expand] {((Object)((Component)clothInstance.smr).gameObject).name}//===============================================================================================================");
|
||||
}
|
||||
|
||||
private List<int> SelectAnchors(
|
||||
ClothInstance clothInstance,
|
||||
float worldRadius,
|
||||
float minDeltaSq = 1E-05f,
|
||||
float maxDelta = 0.1f)
|
||||
{
|
||||
List<int> intList1 = new List<int>();
|
||||
List<int> intList2 = new List<int>();
|
||||
int length = clothInstance.worldVertices.Length;
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
if (!clothInstance.isInsideVertex[index] && (double)((Vector3)ref clothInstance.deltas[index]).sqrMagnitude > (double)minDeltaSq)
|
||||
intList2.Add(index);
|
||||
}
|
||||
if (intList2.Count == 0)
|
||||
return intList1;
|
||||
intList2.Sort((Comparison<int>)((a, b) =>
|
||||
{
|
||||
float sqrMagnitude = ((Vector3)ref clothInstance.deltas[a]).sqrMagnitude;
|
||||
float num = ((Vector3)ref clothInstance.deltas[b]).sqrMagnitude - sqrMagnitude;
|
||||
if ((double)Mathf.Abs(num) <= 9.9999999747524271E-07)
|
||||
return clothInstance.minDistance[a].CompareTo(clothInstance.minDistance[b]);
|
||||
return (double)num <= 0.0 ? -1 : 1;
|
||||
}));
|
||||
float num1 = worldRadius * 2f;
|
||||
float num2 = num1 * num1;
|
||||
float cellSize = num1;
|
||||
Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>();
|
||||
foreach (int index1 in intList2)
|
||||
{
|
||||
Vector3Int cellIndex = GetCellIndex(clothInstance.worldVertices[index1]);
|
||||
bool flag = false;
|
||||
for (int index2 = -1; index2 <= 1 && !flag; ++index2)
|
||||
{
|
||||
for (int index3 = -1; index3 <= 1 && !flag; ++index3)
|
||||
{
|
||||
for (int index4 = -1; index4 <= 1 && !flag; ++index4)
|
||||
{
|
||||
Vector3Int key;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3Int)ref key).\u002Ector(((Vector3Int)ref cellIndex).x + index2, ((Vector3Int)ref cellIndex).y + index3, ((Vector3Int)ref cellIndex).z + index4);
|
||||
List<int> intList3;
|
||||
if (dictionary.TryGetValue(key, out intList3))
|
||||
{
|
||||
for (int index5 = 0; index5 < intList3.Count; ++index5)
|
||||
{
|
||||
int index6 = intList3[index5];
|
||||
Vector3 vector3 = Vector3.op_Subtraction(clothInstance.worldVertices[index1], clothInstance.worldVertices[index6]);
|
||||
if ((double)((Vector3)ref vector3).sqrMagnitude < (double)num2)
|
||||
{
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
intList1.Add(index1);
|
||||
List<int> intList4;
|
||||
if (!dictionary.TryGetValue(cellIndex, out intList4))
|
||||
{
|
||||
intList4 = new List<int>();
|
||||
dictionary[cellIndex] = intList4;
|
||||
}
|
||||
intList4.Add(index1);
|
||||
}
|
||||
}
|
||||
return intList1;
|
||||
|
||||
Vector3Int GetCellIndex(Vector3 p)
|
||||
{
|
||||
return new Vector3Int(Mathf.FloorToInt(p.x / cellSize), Mathf.FloorToInt(p.y / cellSize), Mathf.FloorToInt(p.z / cellSize));
|
||||
}
|
||||
}
|
||||
|
||||
public void SmoothDeltasByDistance(
|
||||
Vector3[] positions,
|
||||
ref Vector3[] deltas,
|
||||
List<int>[] adjacency,
|
||||
float radius,
|
||||
int maxDepth = 3,
|
||||
int iterations = 1,
|
||||
float smoothFactor = 0.5f,
|
||||
float gaussianSigma = -1f)
|
||||
{
|
||||
if (positions == null || deltas == null || adjacency == null || positions.Length != deltas.Length || positions.Length != adjacency.Length)
|
||||
return;
|
||||
int length = positions.Length;
|
||||
if (length == 0)
|
||||
return;
|
||||
if ((double)gaussianSigma <= 0.0)
|
||||
gaussianSigma = radius * 0.5f;
|
||||
float num1 = radius * radius;
|
||||
float num2 = 2f * gaussianSigma * gaussianSigma;
|
||||
Vector3[] vector3Array = new Vector3[length];
|
||||
Queue<VertexFittingUtil.Node> nodeQueue1 = new Queue<VertexFittingUtil.Node>();
|
||||
List<int> intList1 = new List<int>(32 /*0x20*/);
|
||||
int[] numArray = new int[length];
|
||||
int num3 = 1;
|
||||
for (int index1 = 0; index1 < iterations; ++index1)
|
||||
{
|
||||
for (int index2 = 0; index2 < length; ++index2)
|
||||
{
|
||||
if (Vector3.op_Equality(deltas[index2], Vector3.zero))
|
||||
{
|
||||
vector3Array[index2] = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
intList1.Clear();
|
||||
nodeQueue1.Clear();
|
||||
++num3;
|
||||
numArray[index2] = num3;
|
||||
Queue<VertexFittingUtil.Node> nodeQueue2 = nodeQueue1;
|
||||
VertexFittingUtil.Node node1 = new VertexFittingUtil.Node();
|
||||
node1.index = index2;
|
||||
node1.depth = 0;
|
||||
VertexFittingUtil.Node node2 = node1;
|
||||
nodeQueue2.Enqueue(node2);
|
||||
Vector3 position1 = positions[index2];
|
||||
Vector3 vector3_1;
|
||||
while (nodeQueue1.Count > 0)
|
||||
{
|
||||
VertexFittingUtil.Node node3 = nodeQueue1.Dequeue();
|
||||
int index3 = node3.index;
|
||||
int depth = node3.depth;
|
||||
Vector3 position2 = positions[index3];
|
||||
vector3_1 = Vector3.op_Subtraction(position2, position1);
|
||||
float sqrMagnitude = ((Vector3)ref vector3_1).sqrMagnitude;
|
||||
if (index3 != index2 && (double)sqrMagnitude <= (double)num1)
|
||||
intList1.Add(index3);
|
||||
if (depth < maxDepth)
|
||||
{
|
||||
List<int> intList2 = adjacency[index3];
|
||||
if (intList2 != null)
|
||||
{
|
||||
for (int index4 = 0; index4 < intList2.Count; ++index4)
|
||||
{
|
||||
int index5 = intList2[index4];
|
||||
if (numArray[index5] != num3)
|
||||
{
|
||||
vector3_1 = Vector3.op_Subtraction(positions[index5], position2);
|
||||
if ((double)((Vector3)ref vector3_1).sqrMagnitude <= (double)num1)
|
||||
{
|
||||
numArray[index5] = num3;
|
||||
Queue<VertexFittingUtil.Node> nodeQueue3 = nodeQueue1;
|
||||
node1 = new VertexFittingUtil.Node();
|
||||
node1.index = index5;
|
||||
node1.depth = depth + 1;
|
||||
VertexFittingUtil.Node node4 = node1;
|
||||
nodeQueue3.Enqueue(node4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intList1.Count == 0)
|
||||
{
|
||||
vector3Array[index2] = deltas[index2];
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 vector3_2 = Vector3.zero;
|
||||
float num4 = 0.0f;
|
||||
for (int index6 = 0; index6 < intList1.Count; ++index6)
|
||||
{
|
||||
int index7 = intList1[index6];
|
||||
vector3_1 = Vector3.op_Subtraction(positions[index7], position1);
|
||||
float sqrMagnitude = ((Vector3)ref vector3_1).sqrMagnitude;
|
||||
if ((double)sqrMagnitude <= (double)num1)
|
||||
{
|
||||
float num5 = Mathf.Exp(-sqrMagnitude / num2);
|
||||
vector3_2 = Vector3.op_Addition(vector3_2, Vector3.op_Multiply(deltas[index7], num5));
|
||||
num4 += num5;
|
||||
}
|
||||
}
|
||||
if ((double)num4 > 9.99999993922529E-09)
|
||||
{
|
||||
Vector3 vector3_3 = Vector3.op_Division(vector3_2, num4);
|
||||
vector3Array[index2] = Vector3.Lerp(deltas[index2], vector3_3, smoothFactor);
|
||||
}
|
||||
else
|
||||
vector3Array[index2] = deltas[index2];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int index8 = 0; index8 < length; ++index8)
|
||||
deltas[index8] = vector3Array[index8];
|
||||
}
|
||||
}
|
||||
|
||||
public void SmoothAllClothesDeltasByDistance(
|
||||
List<ClothInstance> clothesInstances,
|
||||
float radius,
|
||||
int iterations = 1,
|
||||
float gaussianSigma = -1f,
|
||||
int maxDepth = 3,
|
||||
float smoothFactor = 0.5f)
|
||||
{
|
||||
if (clothesInstances == null || clothesInstances.Count == 0)
|
||||
return;
|
||||
int length1 = 0;
|
||||
for (int index = 0; index < clothesInstances.Count; ++index)
|
||||
{
|
||||
ClothInstance clothesInstance = clothesInstances[index];
|
||||
if (clothesInstance != null && clothesInstance.worldVertices != null)
|
||||
length1 += clothesInstance.worldVertices.Length;
|
||||
}
|
||||
if (length1 == 0)
|
||||
return;
|
||||
Vector3[] positions = new Vector3[length1];
|
||||
Vector3[] deltas = new Vector3[length1];
|
||||
List<int>[] adjacency = new List<int>[length1];
|
||||
int[] numArray = new int[clothesInstances.Count];
|
||||
int num1 = 0;
|
||||
for (int index1 = 0; index1 < clothesInstances.Count; ++index1)
|
||||
{
|
||||
ClothInstance clothesInstance = clothesInstances[index1];
|
||||
if (clothesInstance != null)
|
||||
{
|
||||
numArray[index1] = num1;
|
||||
Vector3[] worldVertices = clothesInstance.worldVertices;
|
||||
Vector3[] deltasLocal = clothesInstance.deltasLocal;
|
||||
List<int>[] vertexAdjacency = clothesInstance.vertexAdjacency;
|
||||
int length2 = worldVertices.Length;
|
||||
for (int index2 = 0; index2 < length2; ++index2)
|
||||
{
|
||||
positions[num1 + index2] = worldVertices[index2];
|
||||
deltas[num1 + index2] = deltasLocal[index2];
|
||||
adjacency[num1 + index2] = new List<int>();
|
||||
}
|
||||
for (int index3 = 0; index3 < length2; ++index3)
|
||||
{
|
||||
List<int> intList1 = vertexAdjacency[index3];
|
||||
if (intList1 != null)
|
||||
{
|
||||
int index4 = num1 + index3;
|
||||
List<int> intList2 = adjacency[index4];
|
||||
for (int index5 = 0; index5 < intList1.Count; ++index5)
|
||||
{
|
||||
int num2 = intList1[index5];
|
||||
int num3 = num1 + num2;
|
||||
intList2.Add(num3);
|
||||
}
|
||||
}
|
||||
}
|
||||
num1 += length2;
|
||||
}
|
||||
}
|
||||
this.SmoothDeltasByDistance(positions, ref deltas, adjacency, radius, maxDepth, iterations, smoothFactor, gaussianSigma);
|
||||
for (int index6 = 0; index6 < clothesInstances.Count; ++index6)
|
||||
{
|
||||
ClothInstance clothesInstance = clothesInstances[index6];
|
||||
if (clothesInstance != null)
|
||||
{
|
||||
int num4 = numArray[index6];
|
||||
int length3 = clothesInstance.deltasLocal.Length;
|
||||
for (int index7 = 0; index7 < length3; ++index7)
|
||||
clothesInstance.deltasLocal[index7] = deltas[num4 + index7];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct Node
|
||||
{
|
||||
public int index;
|
||||
public int depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a1a63abd53fc6e42b650aa11a54bdc1
|
||||
174
Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs
Normal file
174
Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.VertexMoverUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class VertexMoverUtil
|
||||
{
|
||||
public Vector3[] MoveVertices(
|
||||
ClothInstance cloth,
|
||||
Vector3 targetPoint,
|
||||
bool centerIsLeftLeg,
|
||||
bool centerIsRightLeg,
|
||||
float maxRadius,
|
||||
float param,
|
||||
Vector3 vertexMovement)
|
||||
{
|
||||
Vector3[] verts = cloth != null && cloth.worldVertices != null ? cloth.worldVertices : throw new AutoMorpherException("Cloth or World Vertices are Missing", "[MoveVertices] MoveVertices\n - cloth is null or cloth.worldVertices is null");
|
||||
int length = verts.Length;
|
||||
bool[] isInboundVerts;
|
||||
float[] euclideanDistances = this.ComputeEuclideanDistances(verts, targetPoint, maxRadius, out isInboundVerts);
|
||||
if (euclideanDistances == null)
|
||||
return (Vector3[])null;
|
||||
float[] kernelWeights = this.ComputeKernelWeights(euclideanDistances, isInboundVerts, maxRadius, WeightKernel.Gaussian, param);
|
||||
Vector3[] vector3Array = new Vector3[length];
|
||||
bool[] isLeftLegVertex = cloth.isLeftLegVertex;
|
||||
bool[] isRightLegVertex = cloth.isRightLegVertex;
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
if (!isInboundVerts[index])
|
||||
vector3Array[index] = Vector3.zero;
|
||||
else if (centerIsLeftLeg && this.IsRightLegVertex(isRightLegVertex, index))
|
||||
vector3Array[index] = Vector3.zero;
|
||||
else if (centerIsRightLeg && this.IsLeftLegVertex(isLeftLegVertex, index))
|
||||
{
|
||||
vector3Array[index] = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
float num = kernelWeights[index];
|
||||
vector3Array[index] = Vector3.op_Multiply(vertexMovement, num);
|
||||
}
|
||||
}
|
||||
return vector3Array;
|
||||
}
|
||||
|
||||
public Vector3[] MoveVertices(
|
||||
ClothInstance cloth,
|
||||
int targetVertexIdx,
|
||||
bool centerIsLeftLeg,
|
||||
bool centerIsRightLeg,
|
||||
float maxRadius,
|
||||
float param,
|
||||
Vector3 vertexMovement)
|
||||
{
|
||||
Vector3[] verts = cloth != null && cloth.worldVertices != null ? cloth.worldVertices : throw new AutoMorpherException("Cloth or World Vertices are Missing", "[MoveVertices] MoveVertices\n - cloth is null or cloth.worldVertices is null");
|
||||
int length = verts.Length;
|
||||
bool[] isInboundVerts;
|
||||
float[] euclideanDistances = this.ComputeEuclideanDistances(verts, targetVertexIdx, maxRadius, out isInboundVerts);
|
||||
if (euclideanDistances == null)
|
||||
return (Vector3[])null;
|
||||
float[] kernelWeights = this.ComputeKernelWeights(euclideanDistances, isInboundVerts, maxRadius, WeightKernel.Gaussian, param);
|
||||
Vector3[] vector3Array = new Vector3[length];
|
||||
bool[] isLeftLegVertex = cloth.isLeftLegVertex;
|
||||
bool[] isRightLegVertex = cloth.isRightLegVertex;
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
if (!isInboundVerts[index])
|
||||
vector3Array[index] = Vector3.zero;
|
||||
else if (centerIsLeftLeg && this.IsRightLegVertex(isRightLegVertex, index))
|
||||
vector3Array[index] = Vector3.zero;
|
||||
else if (centerIsRightLeg && this.IsLeftLegVertex(isLeftLegVertex, index))
|
||||
{
|
||||
vector3Array[index] = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
float num = kernelWeights[index];
|
||||
vector3Array[index] = Vector3.op_Multiply(vertexMovement, num);
|
||||
}
|
||||
}
|
||||
return vector3Array;
|
||||
}
|
||||
|
||||
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 length = verts.Length;
|
||||
float[] numArray = new float[length];
|
||||
isInboundVerts = new bool[length];
|
||||
bool flag = false;
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
numArray[index] = Vector3.Distance(verts[index], targetVert);
|
||||
isInboundVerts[index] = (double)numArray[index] <= (double)maxRadius;
|
||||
flag |= isInboundVerts[index];
|
||||
}
|
||||
return !flag ? (float[])null : numArray;
|
||||
}
|
||||
|
||||
private float ComputeGaussianWeight(float distance, float alpah)
|
||||
{
|
||||
return Mathf.Exp((float)(-((double)distance * (double)distance) / (2.0 * (double)alpah * (double)alpah)));
|
||||
}
|
||||
|
||||
private float ComputeLaplacianWeight(float distance, float beta)
|
||||
{
|
||||
return Mathf.Exp((float)-((double)distance / (double)beta));
|
||||
}
|
||||
|
||||
private float[] ComputeKernelWeights(
|
||||
float[] dist,
|
||||
bool[] isInboundVerts,
|
||||
float maxRadius,
|
||||
WeightKernel kernel,
|
||||
float param)
|
||||
{
|
||||
int length = dist.Length;
|
||||
float[] kernelWeights = new float[length];
|
||||
float num1 = Mathf.Max(1E-08f, param);
|
||||
for (int index = 0; index < length; ++index)
|
||||
{
|
||||
if (!isInboundVerts[index])
|
||||
{
|
||||
kernelWeights[index] = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (kernel)
|
||||
{
|
||||
case WeightKernel.Gaussian:
|
||||
kernelWeights[index] = this.ComputeGaussianWeight(dist[index], num1);
|
||||
break;
|
||||
case WeightKernel.Laplacian:
|
||||
kernelWeights[index] = this.ComputeLaplacianWeight(dist[index], num1);
|
||||
break;
|
||||
default:
|
||||
kernelWeights[index] = 0.0f;
|
||||
break;
|
||||
}
|
||||
float num2 = (float)(1.0 - (double)dist[index] / (double)maxRadius);
|
||||
kernelWeights[index] *= num2 * num2;
|
||||
}
|
||||
}
|
||||
return kernelWeights;
|
||||
}
|
||||
|
||||
private bool IsLeftLegVertex(bool[] leftMask, int index)
|
||||
{
|
||||
return leftMask != null && index >= 0 && index < leftMask.Length && leftMask[index];
|
||||
}
|
||||
|
||||
private bool IsRightLegVertex(bool[] rightMask, int index)
|
||||
{
|
||||
return rightMask != null && index >= 0 && index < rightMask.Length && rightMask[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 058c2009c6947e940b398fab24dc792b
|
||||
14
Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs
Normal file
14
Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.WeightKernel
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public enum WeightKernel
|
||||
{
|
||||
Gaussian,
|
||||
Laplacian,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca1fec127574c814a8c8306fd2f9aaf0
|
||||
1599
Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs
Normal file
1599
Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e599bc491f46ff142ba063735375547c
|
||||
@@ -0,0 +1,62 @@
|
||||
// Decompiled with JetBrains decompiler
|
||||
// Type: Eden.AutoMorpher.WorldVertexUtil
|
||||
// Assembly: EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
// MVID: D39968B3-E151-4276-BDB4-E82752BBAFF0
|
||||
// Assembly location: D:\dev\AutoMorpher\Assets\@Eden_Tools\Eden_AutoMorpher\Script\EdenAutoMorpherScript.dll
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Eden.AutoMorpher
|
||||
{
|
||||
public class WorldVertexUtil
|
||||
{
|
||||
public Vector3[] GetWorldVertices(SkinnedMeshRenderer smr)
|
||||
{
|
||||
Mesh bakedMesh = new Mesh();
|
||||
return this.GetWorldVertices(smr, ref bakedMesh);
|
||||
}
|
||||
|
||||
public Vector3[] GetWorldVertices(SkinnedMeshRenderer smr, ref Mesh bakedMesh)
|
||||
{
|
||||
if (Object.op_Equality((Object)smr, (Object)null))
|
||||
throw new AutoMorpherException("SkinnedMeshRenderer is Missing", "[SkinnedMeshWorldUtil] GetWorldVertices\n - smr is null");
|
||||
if (Object.op_Equality((Object)bakedMesh, (Object)null))
|
||||
bakedMesh = new Mesh();
|
||||
else
|
||||
bakedMesh.Clear();
|
||||
smr.BakeMesh(bakedMesh);
|
||||
Transform transform = ((Component)smr).transform;
|
||||
Vector3 lossyScale = transform.lossyScale;
|
||||
Vector3 vector3;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3)ref vector3).\u002Ector(1f / Mathf.Max(lossyScale.x, 1E-08f), 1f / Mathf.Max(lossyScale.y, 1E-08f), 1f / Mathf.Max(lossyScale.z, 1E-08f));
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.op_Multiply(transform.localToWorldMatrix, Matrix4x4.Scale(vector3));
|
||||
Vector3[] vertices = bakedMesh.vertices;
|
||||
int length = vertices.Length;
|
||||
Vector3[] worldVertices = new Vector3[length];
|
||||
for (int index = 0; index < length; ++index)
|
||||
worldVertices[index] = ((Matrix4x4)ref matrix4x4).MultiplyPoint3x4(vertices[index]);
|
||||
return worldVertices;
|
||||
}
|
||||
|
||||
public Vector3[] GetWorldVerticesWithBakedMesh(SkinnedMeshRenderer smr, Mesh bakedMesh)
|
||||
{
|
||||
if (Object.op_Equality((Object)smr, (Object)null))
|
||||
throw new AutoMorpherException("SkinnedMeshRenderer is Missing", "[SkinnedMeshWorldUtil] GetWorldVerticesWithBakedMesh\n - smr is null");
|
||||
if (Object.op_Equality((Object)bakedMesh, (Object)null))
|
||||
return (Vector3[])null;
|
||||
Transform transform = ((Component)smr).transform;
|
||||
Vector3 lossyScale = transform.lossyScale;
|
||||
Vector3 vector3;
|
||||
// ISSUE: explicit constructor call
|
||||
((Vector3)ref vector3).\u002Ector(1f / Mathf.Max(lossyScale.x, 1E-08f), 1f / Mathf.Max(lossyScale.y, 1E-08f), 1f / Mathf.Max(lossyScale.z, 1E-08f));
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.op_Multiply(transform.localToWorldMatrix, Matrix4x4.Scale(vector3));
|
||||
Vector3[] vertices = bakedMesh.vertices;
|
||||
int length = vertices.Length;
|
||||
Vector3[] verticesWithBakedMesh = new Vector3[length];
|
||||
for (int index = 0; index < length; ++index)
|
||||
verticesWithBakedMesh[index] = ((Matrix4x4)ref matrix4x4).MultiplyPoint3x4(vertices[index]);
|
||||
return verticesWithBakedMesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 063c5c8305e754148942a0cca1bb8518
|
||||
Reference in New Issue
Block a user