From f9c4088ef403a483866727cc2106f3caa9fa0ba7 Mon Sep 17 00:00:00 2001 From: tymmkang Date: Sun, 1 Feb 2026 14:57:52 +0900 Subject: [PATCH] =?UTF-8?q?EdenAutoMorpherScript=20dll=EC=9D=84=20?= =?UTF-8?q?=EB=94=94=EC=BB=B4=ED=8C=8C=EC=9D=BC=ED=95=9C=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EB=A5=BC=20=EA=B7=B8=EB=8C=80=EB=A1=9C=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../@Eden_Tools/Eden_AutoMorpher/Script.meta | 8 + .../Eden_AutoMorpher/Script/AutoMorpherDev.cs | 53 + .../Script/AutoMorpherDev.cs.meta | 2 + .../Script/AutoMorpherException.cs | 21 + .../Script/AutoMorpherException.cs.meta | 2 + .../Eden_AutoMorpher/Script/BakedBodyMesh.cs | 32 + .../Script/BakedBodyMesh.cs.meta | 2 + .../Script/BodyPoseMatchSetupUtil.cs | 191 ++ .../Script/BodyPoseMatchSetupUtil.cs.meta | 2 + .../Script/BodyPoseMatchUtil.cs | 107 ++ .../Script/BodyPoseMatchUtil.cs.meta | 2 + .../Script/BodyPoseMatch_Arm.cs | 557 ++++++ .../Script/BodyPoseMatch_Arm.cs.meta | 2 + .../Script/BodyPoseMatch_CommonUtil.cs | 269 +++ .../Script/BodyPoseMatch_CommonUtil.cs.meta | 2 + .../Script/BodyPoseMatch_Leg.cs | 748 ++++++++ .../Script/BodyPoseMatch_Leg.cs.meta | 2 + .../Script/BodyPoseMatch_Torso.cs | 158 ++ .../Script/BodyPoseMatch_Torso.cs.meta | 2 + .../Script/BodyPoseToClothApplier.cs | 208 +++ .../Script/BodyPoseToClothApplier.cs.meta | 2 + .../Script/BoneAlignmentUtil.cs | 143 ++ .../Script/BoneAlignmentUtil.cs.meta | 2 + .../Script/BoneCorrespondenceUtil.cs | 158 ++ .../Script/BoneCorrespondenceUtil.cs.meta | 2 + .../Eden_AutoMorpher/Script/BoneMatchUtil.cs | 516 ++++++ .../Script/BoneMatchUtil.cs.meta | 2 + .../Eden_AutoMorpher/Script/BvhNode.cs | 20 + .../Eden_AutoMorpher/Script/BvhNode.cs.meta | 2 + .../Eden_AutoMorpher/Script/BvhTriangle.cs | 19 + .../Script/BvhTriangle.cs.meta | 2 + .../Script/BvhTriangleMesh.cs | 701 ++++++++ .../Script/BvhTriangleMesh.cs.meta | 2 + .../Eden_AutoMorpher/Script/ClothBoneType.cs | 14 + .../Script/ClothBoneType.cs.meta | 2 + .../Script/ClothHumanoidMaskUtil.cs | 285 +++ .../Script/ClothHumanoidMaskUtil.cs.meta | 2 + .../Eden_AutoMorpher/Script/ClothInstance.cs | 518 ++++++ .../Script/ClothInstance.cs.meta | 2 + .../Script/ClothInstanceTotal.cs | 283 +++ .../Script/ClothInstanceTotal.cs.meta | 2 + .../Script/EdenAutoMorpher.cs | 575 ++++++ .../Script/EdenAutoMorpher.cs.meta | 2 + .../Script/EdenAutoMorpherConfig.cs | 38 + .../Script/EdenAutoMorpherConfig.cs.meta | 2 + .../Script/EdenAutoMorpherManager.cs | 362 ++++ .../Script/EdenAutoMorpherManager.cs.meta | 2 + .../Script/EdenAutoMorpher_SetUpUtil.cs | 552 ++++++ .../Script/EdenAutoMorpher_SetUpUtil.cs.meta | 2 + .../Eden_AutoMorpher/Script/MeshClassifier.cs | 218 +++ .../Script/MeshClassifier.cs.meta | 2 + .../Eden_AutoMorpher/Script/MeshMatcher.cs | 208 +++ .../Script/MeshMatcher.cs.meta | 2 + .../Eden_AutoMorpher/Script/MorpherMode.cs | 16 + .../Script/MorpherMode.cs.meta | 2 + .../Eden_AutoMorpher/Script/MorpherState.cs | 17 + .../Script/MorpherState.cs.meta | 2 + .../Eden_AutoMorpher/Script/PcaUtil.cs | 184 ++ .../Eden_AutoMorpher/Script/PcaUtil.cs.meta | 2 + .../Eden_AutoMorpher/Script/ProcessInfo.cs | 15 + .../Script/ProcessInfo.cs.meta | 2 + .../Eden_AutoMorpher/Script/ProfileLoader.cs | 244 +++ .../Script/ProfileLoader.cs.meta | 2 + .../Script/ProfilePoseMatchUtil.cs | 72 + .../Script/ProfilePoseMatchUtil.cs.meta | 2 + .../Eden_AutoMorpher/Script/RegionStats.cs | 18 + .../Script/RegionStats.cs.meta | 2 + .../Eden_AutoMorpher/Script/SkinningUtil.cs | 248 +++ .../Script/SkinningUtil.cs.meta | 2 + .../Eden_AutoMorpher/Script/TempBoneMarker.cs | 15 + .../Script/TempBoneMarker.cs.meta | 2 + .../Eden_AutoMorpher/Script/TransformInfo.cs | 64 + .../Script/TransformInfo.cs.meta | 2 + .../Eden_AutoMorpher/Script/TriangleUtil.cs | 56 + .../Script/TriangleUtil.cs.meta | 2 + .../Script/VertexFittingUtil.cs | 680 +++++++ .../Script/VertexFittingUtil.cs.meta | 2 + .../Script/VertexMoverUtil.cs | 174 ++ .../Script/VertexMoverUtil.cs.meta | 2 + .../Eden_AutoMorpher/Script/WeightKernel.cs | 14 + .../Script/WeightKernel.cs.meta | 2 + .../Script/WeightTransferUtil.cs | 1599 +++++++++++++++++ .../Script/WeightTransferUtil.cs.meta | 2 + .../Script/WorldVertexUtil.cs | 62 + .../Script/WorldVertexUtil.cs.meta | 2 + 85 files changed, 10524 insertions(+) create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherException.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherException.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchSetupUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchSetupUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_CommonUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_CommonUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Torso.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Torso.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseToClothApplier.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseToClothApplier.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneCorrespondenceUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneCorrespondenceUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothHumanoidMaskUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothHumanoidMaskUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherConfig.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherConfig.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherManager.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherManager.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher_SetUpUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher_SetUpUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfilePoseMatchUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfilePoseMatchUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs.meta create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/WorldVertexUtil.cs create mode 100644 Assets/@Eden_Tools/Eden_AutoMorpher/Script/WorldVertexUtil.cs.meta diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script.meta new file mode 100644 index 0000000..d98e91a --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c4603c2167fca184b81e3c38f3c116c0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs new file mode 100644 index 0000000..7fa8478 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs @@ -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"); + } + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs.meta new file mode 100644 index 0000000..4e5732a --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherDev.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 74e149c92cc858147bcd96dbf83bfce5 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherException.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherException.cs new file mode 100644 index 0000000..f5ce66d --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherException.cs @@ -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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherException.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherException.cs.meta new file mode 100644 index 0000000..f1679f9 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/AutoMorpherException.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c3893985c83ce4847ba97b12c88c7792 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs new file mode 100644 index 0000000..f3ae050 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs @@ -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; + } + } + +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs.meta new file mode 100644 index 0000000..35f50e8 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BakedBodyMesh.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 83084f45d44ba1c4088b9c47d504847d \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchSetupUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchSetupUtil.cs new file mode 100644 index 0000000..f4684b2 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchSetupUtil.cs @@ -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> 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 sourceBodyMeshes, + out List proxyBodyMeshes, + out Dictionary sourceToProxy) + { + proxyBodyMeshes = (List)null; + if (Object.op_Equality((Object)sourceAvatar, (Object)null)) + { + Debug.LogError((object)"[AvatarBodyMatchUtil] CreateSourceBodyProxy: sourceAvatar == null"); + sourceToProxy = new Dictionary(); + return (GameObject)null; + } + GameObject clone = Object.Instantiate(((Component)sourceAvatar).gameObject); + ((Object)clone).name = ((Object)sourceAvatar).name + "_BodyProxy"; + HashSet remainTransforms = new HashSet(); + remainTransforms.Add(clone.transform); + Animator component = clone.GetComponent(); + 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 meshSet = new HashSet(); + if (sourceBodyMeshes != null) + { + foreach (SkinnedMeshRenderer sourceBodyMesh in (IEnumerable)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(true); + List skinnedMeshRendererList = new List(); + 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 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()) + AddWithParents(t); + Transform[] componentsInChildren2 = clone.GetComponentsInChildren(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> 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 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); + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchSetupUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchSetupUtil.cs.meta new file mode 100644 index 0000000..1a25dce --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchSetupUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: feba191d9b996fb4f92fb50b0bdc9c66 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs new file mode 100644 index 0000000..b34a230 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs @@ -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 sourceBodyMeshes, + GameObject targetAvatar, + IReadOnlyList targetBodyMeshes, + out Dictionary sourceToProxy, + float neckTargetHeight = 1.5f, + bool onlyScaling = false) + { + Animator component1 = sourceAvatar.GetComponent(); + Animator component2 = targetAvatar.GetComponent(); + 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(); + return (GameObject)null; + } + Dictionary> humanBoneMap = this.meshClassifier.MeshHumanoidBoneMatcher(component1, sourceBodyMeshes); + Dictionary> dictionary1 = this.meshClassifier.MeshHumanoidBoneMatcher(component2, targetBodyMeshes); + BodyPoseMatchSetupUtil poseMatchSetupUtil = new BodyPoseMatchSetupUtil(); + poseMatchSetupUtil.AdjustAvatarScaleByNeck(sourceAvatar.transform, humanBoneMap, neckTargetHeight); + poseMatchSetupUtil.AdjustAvatarScaleByNeck(targetAvatar.transform, dictionary1, neckTargetHeight); + List proxyBodyMeshes; + GameObject bodyProxy = poseMatchSetupUtil.CreateBodyProxy(component1, sourceBodyMeshes, out proxyBodyMeshes, out sourceToProxy); + Animator component3 = bodyProxy.GetComponent(); + if (onlyScaling) + { + bodyProxy.transform.SetParent(targetAvatar.transform); + bodyProxy.transform.localPosition = Vector3.zero; + return bodyProxy; + } + Dictionary> dictionary2 = this.meshClassifier.MeshHumanoidBoneMatcher(component3, (IReadOnlyList)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 bakedBodyMeshList1 = new List(); + foreach (SkinnedMeshRenderer _smr in proxyBodyMeshes) + bakedBodyMeshList1.Add(new BakedBodyMesh(_smr)); + List bakedBodyMeshList2 = new List(); + foreach (SkinnedMeshRenderer targetBodyMesh in (IEnumerable)targetBodyMeshes) + bakedBodyMeshList2.Add(new BakedBodyMesh(targetBodyMesh)); + BodyPoseMatch_Torso bodyPoseMatchTorso = new BodyPoseMatch_Torso(); + bodyPoseMatchTorso.AlignTorsoByNeck(bodyProxy, (IReadOnlyList)bakedBodyMeshList1, dictionary2, targetAvatar, (IReadOnlyList)bakedBodyMeshList2, dictionary1); + if (this.doDebug) + { + bodyPoseMatchTorso.DrawTorsoPcaDebug(bodyProxy, (IReadOnlyList)bakedBodyMeshList1, dictionary2, Color.yellow, Color.cyan, duration: 20f); + bodyPoseMatchTorso.DrawTorsoPcaDebug(targetAvatar, (IReadOnlyList)bakedBodyMeshList2, dictionary1, Color.red, Color.green, duration: 20f); + } + foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1) + bakedBodyMesh.ReBakeMesh(); + BodyPoseMatch_Arm bodyPoseMatchArm = new BodyPoseMatch_Arm(); + bodyPoseMatchArm.AlignUpperArmByArmPcaCenters((IReadOnlyList)bakedBodyMeshList1, dictionary2, (IReadOnlyList)bakedBodyMeshList2, dictionary1); + if (this.doDebug) + { + bodyPoseMatchArm.DrawArmPcaDebug(bodyProxy, (IReadOnlyList)bakedBodyMeshList1, dictionary2, true, Color.yellow, Color.cyan, duration: 20f); + bodyPoseMatchArm.DrawArmPcaDebug(targetAvatar, (IReadOnlyList)bakedBodyMeshList2, dictionary1, true, Color.red, Color.green, duration: 20f); + } + foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1) + bakedBodyMesh.ReBakeMesh(); + bodyPoseMatchArm.ScalingBothArmsLength((IReadOnlyList)bakedBodyMeshList1, dictionary2, (IReadOnlyList)bakedBodyMeshList2, dictionary1); + foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1) + bakedBodyMesh.ReBakeMesh(); + BodyPoseMatch_Leg bodyPoseMatchLeg = new BodyPoseMatch_Leg(); + bodyPoseMatchLeg.AlignBothUpperLegs(bodyProxy, (IReadOnlyList)bakedBodyMeshList1, dictionary2, targetAvatar, (IReadOnlyList)bakedBodyMeshList2, dictionary1); + foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1) + bakedBodyMesh.ReBakeMesh(); + bodyPoseMatchLeg.ScalingBothLegsAndFoots(bodyProxy, (IReadOnlyList)bakedBodyMeshList1, dictionary2, targetAvatar, (IReadOnlyList)bakedBodyMeshList2, dictionary1); + if (this.doDebug) + { + foreach (BakedBodyMesh bakedBodyMesh in bakedBodyMeshList1) + bakedBodyMesh.ReBakeMesh(); + bodyPoseMatchLeg.DrawLegPcaDebug(bodyProxy, (IReadOnlyList)bakedBodyMeshList1, dictionary2, true, Color.yellow, Color.cyan, duration: 5f); + bodyPoseMatchLeg.DrawLegPcaDebug(bodyProxy, (IReadOnlyList)bakedBodyMeshList1, dictionary2, false, Color.yellow, Color.cyan, duration: 5f); + bodyPoseMatchLeg.DrawLegPcaDebug(targetAvatar, (IReadOnlyList)bakedBodyMeshList2, dictionary1, true, Color.magenta, Color.green, duration: 5f); + bodyPoseMatchLeg.DrawLegPcaDebug(targetAvatar, (IReadOnlyList)bakedBodyMeshList2, dictionary1, false, Color.magenta, Color.green, duration: 5f); + bodyPoseMatchArm.DrawForearmExtremeDebugPair(bodyProxy.gameObject, (IReadOnlyList)proxyBodyMeshes, targetAvatar, targetBodyMeshes, true, 1f, 5f); + } + return bodyProxy; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs.meta new file mode 100644 index 0000000..9f3952c --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatchUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a85962b0b9eb9ec4094079c0f62db81d \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs new file mode 100644 index 0000000..3423a64 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs @@ -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 sourceLeftUpperArmSet, + IReadOnlyCollection 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)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)sourceRightUpperArmSet) + { + if (!Object.op_Equality((Object)sourceRightUpperArm, (Object)null)) + { + Transform transform = sourceRightUpperArm; + transform.position = Vector3.op_Addition(transform.position, vector3); + } + } + } + + public void AlignUpperArmByArmPcaCenters( + IReadOnlyList proxyBakedBodyMeshes, + Dictionary> proxyBoneMap, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> 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 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 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)sourceLeftUpperArmSet, (IReadOnlyCollection)sourceRightUpperArmSet, shoulderCenter1, shoulderCenter2, axisReferenceTransform); + } + } + } + + public void AlignUpperArmByArmPcaCenters( + IReadOnlyList targetBakedBodyMeshes, + Dictionary> targetBoneMap, + Dictionary> 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 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 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)sourceLeftUpperArmSet, (IReadOnlyCollection)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 avatarBakedBodyMeshes, + Dictionary> avatarBoneMap, + bool isLeft) + { + // ISSUE: unable to decompile the method. + } + + private void ScalingUpperArmLength( + Dictionary> sourceBoneMap, + Dictionary> 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 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> sourceBoneMap, + Dictionary> 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 proxyBakedBodyMeshes, + Dictionary> proxyBoneMap, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> 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)proxyBakedBodyMeshes) + proxyBakedBodyMesh.ReBakeMesh(); + } + this.ScalingLowerArmLength_BodyMatch(proxyBakedBodyMeshes, proxyBoneMap, targetBakedBodyMeshes, targetBoneMap, autoDetectAxis, forceAxisIndex); + } + + private void ScalingLowerArmLength_BodyMatch( + IReadOnlyList proxyBakedBodyMeshes, + Dictionary> proxyBoneMap, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> 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 targetBakedBodyMeshes, + Dictionary> targetBoneMap, + Dictionary> 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 targetBakedBodyMeshes, + Dictionary> targetBoneMap, + Dictionary> 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 bakedBodyMeshes, + Dictionary> boneMap, + HumanBodyBones targetBone, + bool isLeft, + out float extremeX, + float weightThreshold = 0.15f, + int sampleStep = 1) + { + extremeX = isLeft ? float.PositiveInfinity : float.NegativeInfinity; + HashSet targetBoneSet; + if (bakedBodyMeshes == null || boneMap == null || !boneMap.TryGetValue(targetBone, out targetBoneSet) || targetBoneSet == null || targetBoneSet.Count == 0) + return false; + List 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> 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 avatarBakedBodyMeshes, + Dictionary> 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 proxyBodyMeshes, + GameObject targetObject, + IReadOnlyList 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 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(); + 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 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 targetBoneSet = new HashSet() + { + boneTransform + }; + List bakedBodyMeshes = new List(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 vector3List = this.poseMatchCommonUtil.CollectWeightedVerticesWorld((IReadOnlyList)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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs.meta new file mode 100644 index 0000000..6cbd8e4 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Arm.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5e4304e521b929546b171b5c3eedf84b \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_CommonUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_CommonUtil.cs new file mode 100644 index 0000000..3f9a8a0 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_CommonUtil.cs @@ -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> boneMap, + HumanBodyBones bone) + { + HashSet source; + return boneMap == null || !boneMap.TryGetValue(bone, out source) || source == null ? (Transform)null : source.FirstOrDefault(); + } + + public Vector3 GetProfilePcaCenterWorld( + Dictionary> 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> clothBoneMap, + BoneSpatialData spatialData, + int axis, + Vector3 comprehensiveScale) + { + return this.GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, true); + } + + public Vector3 GetProfileVolumeMaxWorld( + Dictionary> clothBoneMap, + BoneSpatialData spatialData, + int axis, + Vector3 comprehensiveScale) + { + return this.GetProfileVolumeWorld(clothBoneMap, spatialData, axis, comprehensiveScale, false); + } + + public Vector3 GetProfileVolumeWorld( + Dictionary> 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 CollectWeightedVerticesWorld( + IReadOnlyList bakedBodyMeshes, + HashSet targetBoneSet, + float weightThreshold = 0.15f, + int sampleStep = 1) + { + List vector3List = new List(); + if (bakedBodyMeshes == null || targetBoneSet == null || targetBoneSet.Count == 0) + return vector3List; + foreach (BakedBodyMesh bakedBodyMesh in (IEnumerable)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 CollectHumanoidVerticesWorld( + IReadOnlyList targetHumanBones, + IReadOnlyList bakedBodyMeshes, + Dictionary> boneMap, + float weightThreshold = 0.15f, + int sampleStep = 1) + { + List vector3List = new List(); + 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 targetBoneSet = new HashSet(); + foreach (HumanBodyBones targetHumanBone in (IEnumerable)targetHumanBones) + { + HashSet 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 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 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.originalParent = parentTransform; + tempBoneMarker.additionalInfo = ""; + tempBoneMarker.wrappedChildNames = new List(); + 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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_CommonUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_CommonUtil.cs.meta new file mode 100644 index 0000000..6a9b0b7 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_CommonUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e11035ab0ef1a734eae6c759861df3b3 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs new file mode 100644 index 0000000..6115fd9 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs @@ -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 proxyBakedBodyMeshes, + Dictionary> proxyBoneMap, + GameObject targetObject, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> 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 targetBakedBodyMeshes, + Dictionary> targetBoneMap, + Transform clothesTransform, + Dictionary> 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 proxyBakedBodyMeshes, + Dictionary> proxyBoneMap, + GameObject targetObject, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> 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 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)upperLegSet, legRegionStats1.center, legRegionStats2.center); + } + } + + public void AlignUpperLeg_Profile( + Transform targetTransform, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> targetBoneMap, + Transform clothesTransform, + Dictionary> 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 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)upperLegSet, profilePcaCenterWorld, legRegionStats.center); + } + } + } + + private void AlignUpperLegCore( + IReadOnlyCollection 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)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 avatarBakedBodyMeshes, + Dictionary> 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 points = this.poseMatchCommonUtil.CollectHumanoidVerticesWorld((IReadOnlyList)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)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 proxyBakedBodyMeshes, + Dictionary> proxyBoneMap, + GameObject targetObject, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> 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)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 targetBakedBodyMeshes, + Dictionary> targetBoneMap, + Transform clothTransform, + Dictionary> 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> proxyBoneMap, + Dictionary> 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 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 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 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> dictionary = new Dictionary>(); + foreach (Transform footBone in footBoneSet) + { + if (!Object.op_Equality((Object)footBone, (Object)null)) + { + Transform parent = footBone.parent; + List transformList; + if (!dictionary.TryGetValue(parent, out transformList)) + { + transformList = new List(); + dictionary.Add(parent, transformList); + } + transformList.Add(footBone); + } + } + foreach (KeyValuePair> keyValuePair in dictionary) + { + Transform key = keyValuePair.Key; + List 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)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 proxyBakedBodyMeshes, + Dictionary> proxyBoneMap, + GameObject targetObject, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> 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 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> clothBoneMap, + Transform targetTransform, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> 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 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 avatarBakedBodyMeshes, + Dictionary> 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 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 targetBoneSet = new HashSet(); + 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 transformStack = new Stack(); + 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 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 avatarBakedBodyMeshes, + Dictionary> 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 avatarBakedBodyMeshes, + Dictionary> 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 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); + } + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs.meta new file mode 100644 index 0000000..9c88801 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Leg.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7326179703ed48e489335a16b7d53a33 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Torso.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Torso.cs new file mode 100644 index 0000000..09ace80 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Torso.cs @@ -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 sourceHipSet, + Vector3 sourceNeckCenterWorld, + Vector3 targetNeckCenterWorld) + { + Transform transform1 = sourceHipSet != null && sourceHipSet.Count != 0 ? sourceHipSet.FirstOrDefault((Func)(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)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 proxyBakedBodyMeshes, + Dictionary> proxyBoneMap, + GameObject targetObject, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> 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 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)sourceHipSet, neckRegionStats1.center, neckRegionStats2.center); + } + } + + public void AlignTorsoByNeck( + Transform targetTransform, + IReadOnlyList targetBakedBodyMeshes, + Dictionary> targetBoneMap, + Dictionary> 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 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)sourceHipSet, profilePcaCenterWorld, neckRegionStats.center); + } + } + + public RegionStats ComputeNeckRegionStats( + Transform avatarTransform, + IReadOnlyList avatarBakedBodyMeshes, + Dictionary> avatarBoneMap) + { + List points = this.poseMatchCommonUtil.CollectHumanoidVerticesWorld((IReadOnlyList)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)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 avatarBakedBodyMeshes, + Dictionary> 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}"); + } + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Torso.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Torso.cs.meta new file mode 100644 index 0000000..984bd71 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseMatch_Torso.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7d84554c6dcbe7b42b908fabb48c3d66 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseToClothApplier.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseToClothApplier.cs new file mode 100644 index 0000000..33bfd97 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseToClothApplier.cs @@ -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 clothToBodyMatched, + Dictionary 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(); + 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 proxyDepthMap = this.BuildDepthMap(transform); + Dictionary proxyToCloth = new Dictionary(); + List boneMappingList = new List(); + HashSet transformSet = new HashSet(); + foreach (KeyValuePair 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((Func)(m => m != null && Object.op_Inequality((Object)m.proxyBone, (Object)null) && Object.op_Inequality((Object)m.clothBone, (Object)null))).OrderBy((Func)(m => m.depth)).ToList()) + { + 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 BuildDepthMap(Transform root) + { + Dictionary dictionary = new Dictionary(); + if (Object.op_Equality((Object)root, (Object)null)) + return dictionary; + foreach (Transform componentsInChild in ((Component)root).GetComponentsInChildren(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 proxyToCloth, + Dictionary proxyDepthMap, + List mappings) + { + if (Object.op_Equality((Object)proxyArmature, (Object)null) || proxyToCloth == null || mappings == null) + return; + TempBoneMarker[] componentsInChildren = ((Component)proxyArmature).GetComponentsInChildren(true); + if (componentsInChildren == null || componentsInChildren.Length == 0) + return; + HashSet transformSet = new HashSet(); + 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)componentsInChildren).Where((Func)(bm => Object.op_Inequality((Object)bm, (Object)null) && Object.op_Inequality((Object)((Component)bm).transform, (Object)null))).OrderBy((Func)(bm => proxyDepthMap != null && proxyDepthMap.TryGetValue(((Component)bm).transform, out num1) ? num1 : int.MaxValue)).ToList()) + { + 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 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(); + } + else + tempBoneMarker2 = ((Component)transform3).GetComponent(); + 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(), (Object)null)) + return child; + } + return (Transform)null; + } + + private List CollectDirectChilds(Transform parentTransform) + { + int childCount = parentTransform.childCount; + List transformList = new List(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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseToClothApplier.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseToClothApplier.cs.meta new file mode 100644 index 0000000..86d1d02 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BodyPoseToClothApplier.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 95106b6438eaf82418391056865c4a34 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs new file mode 100644 index 0000000..bc66df3 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs @@ -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> 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(); + if (Object.op_Equality((Object)component, (Object)null) || !component.isHuman) + return; + Dictionary dictionary = new Dictionary(); + if (config.clothesHumanoidMatchedBones != null) + { + foreach (KeyValuePair> 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 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 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 transformList = new List(); + 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(true); + if (componentsInChildren == null || componentsInChildren.Length == 0) + return; + foreach (TempBoneMarker tempBoneMarker in ((IEnumerable)componentsInChildren).Where((Func)(m => Object.op_Inequality((Object)m, (Object)null))).OrderByDescending((Func)(m => GetDepth(((Component)m).transform))).ToArray()) + { + 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; + } + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs.meta new file mode 100644 index 0000000..f60f59d --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneAlignmentUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 51afb8fce54e96444b9da90ac17f1983 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneCorrespondenceUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneCorrespondenceUtil.cs new file mode 100644 index 0000000..04de99f --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneCorrespondenceUtil.cs @@ -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 values = new Stack(); + 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)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)p.Split('/', StringSplitOptions.None)).Where((Func)(x => !string.IsNullOrEmpty(x))).Select(new Func(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(); + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneCorrespondenceUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneCorrespondenceUtil.cs.meta new file mode 100644 index 0000000..7860b91 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneCorrespondenceUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5e62c972f6f7fb242aaf2e7182fc85bb \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs new file mode 100644 index 0000000..83487d1 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs @@ -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 ConvertProfileBoneDataToRootLocalData( + List boneDataList) + { + List rootLocalData = boneDataList != null && boneDataList.Count != 0 ? new List(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 GetMeshBones(List meshRenderers) + { + HashSet meshBones = new HashSet(); + 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 GetRootLocalBones( + Transform rootT, + HashSet boneList) + { + BoneCorrespondenceUtil correspondenceUtil = new BoneCorrespondenceUtil(); + return boneList.Where((Func)(t => Object.op_Inequality((Object)t, (Object)null))).Distinct().Select((Func)(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(); + } + + public List GetBodyRootLocalBones( + Transform bodyTransform, + Animator bodyAnimator, + List bodyMeshes) + { + if (Object.op_Equality((Object)bodyTransform, (Object)null)) + throw new AutoMorpherException("Body Transform is Missing", "[BoneMatchUtil] GetBodyRootLocalBones\n - bodyTransform is null"); + Dictionary 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 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> dictionary2 = new MeshClassifier().MeshHumanoidBoneMatcher(bodyAnimator, (IReadOnlyList)bodyMeshes); + HashSet boneList = new HashSet(); + HashSet transformSet2 = new HashSet(); + foreach (KeyValuePair keyValuePair in dictionary1) + { + if (keyValuePair.Value != 55 && !Object.op_Equality((Object)keyValuePair.Key, (Object)null)) + { + HashSet transformSet3; + if (!dictionary2.TryGetValue(keyValuePair.Value, out transformSet3) || transformSet3 == null) + { + transformSet3 = new HashSet(); + dictionary2[keyValuePair.Value] = transformSet3; + } + transformSet3.Add(keyValuePair.Key); + } + } + foreach (KeyValuePair> keyValuePair in dictionary2) + { + HumanBodyBones key = keyValuePair.Key; + if (key != 55) + { + HashSet 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(); + 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 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 GetHumanoidBoneList(Animator bodyAnimator) + { + Dictionary humanoidBoneList = new Dictionary(); + 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 bodyBones, + List clothesBones, + out Dictionary> clothHumanBones, + out Dictionary clothBoneTypeMap, + out Dictionary clothToBodyMatched) + { + clothHumanBones = new Dictionary>(); + clothBoneTypeMap = new Dictionary(); + clothToBodyMatched = new Dictionary(); + 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 dictionary = new Dictionary(); + foreach (IGrouping 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 transformSet; + if (!clothHumanBones.TryGetValue(hBone, out transformSet)) + { + transformSet = new HashSet(); + 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 BuildTransformMatchMap( + List sourceBones, + List 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 dictionary1 = new Dictionary(); + Dictionary dictionary2 = new Dictionary(); + Dictionary dictionary3 = new Dictionary(); + Dictionary> dictionary4 = new Dictionary>(); + 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 boneRootLocalDataList; + if (!dictionary4.TryGetValue(key1, out boneRootLocalDataList)) + { + boneRootLocalDataList = new List(); + dictionary4[key1] = boneRootLocalDataList; + } + boneRootLocalDataList.Add(destBone); + } + } + } + HashSet transformSet = new HashSet(); + 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 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> sourceClothHumanBones, + Dictionary sourceClothBoneTypeMap, + out Dictionary> targetClothHumanBones, + out Dictionary targetClothBoneTypeMap) + { + targetClothHumanBones = new Dictionary>(); + targetClothBoneTypeMap = new Dictionary(); + 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 boneList = new HashSet(); + foreach (KeyValuePair sourceClothBoneType in sourceClothBoneTypeMap) + { + if (Object.op_Inequality((Object)sourceClothBoneType.Key, (Object)null)) + boneList.Add(sourceClothBoneType.Key); + } + foreach (KeyValuePair> sourceClothHumanBone in sourceClothHumanBones) + { + HashSet 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 meshBones = this.GetMeshBones(((IEnumerable)((Component)targetClothRoot).GetComponentsInChildren(true)).ToList()); + 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 rootLocalBones1 = this.GetRootLocalBones(sourceClothRoot, boneList); + List 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 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 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> sourceClothHumanBone in sourceClothHumanBones) + { + HumanBodyBones key3 = sourceClothHumanBone.Key; + HashSet 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 transformSet2; + if (!targetClothHumanBones.TryGetValue(key3, out transformSet2)) + { + transformSet2 = new HashSet(); + targetClothHumanBones[key3] = transformSet2; + } + transformSet2.Add(transform); + } + } + } + } + } + + public void BuildSourceToProxyBoneMap( + Animator sourceAvatar, + Animator proxyAvatar, + out Dictionary sourceToProxy) + { + sourceToProxy = new Dictionary(); + 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 meshBones1 = this.GetMeshBones(((IEnumerable)((Component)transform2).GetComponentsInChildren(true)).ToList()); + 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 meshBones2 = this.GetMeshBones(((IEnumerable)((Component)transform1).GetComponentsInChildren(true)).ToList()); + 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 rootLocalBones1 = this.GetRootLocalBones(transform2, meshBones1); + List 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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs.meta new file mode 100644 index 0000000..e2906d1 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BoneMatchUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 39ce956a348f7e24095c2239c465fb1e \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs new file mode 100644 index 0000000..255555f --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs @@ -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; + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs.meta new file mode 100644 index 0000000..1fcd56e --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhNode.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 10c3a2ab07ede5146a5d92236e6735b6 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs new file mode 100644 index 0000000..ea81901 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs @@ -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; + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs.meta new file mode 100644 index 0000000..ec21e37 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangle.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4947000410991e449b49bad5e74aec76 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs new file mode 100644 index 0000000..c519856 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs @@ -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 renderers, + Animator animator) + { + if (renderers == null || renderers.Count == 0) + return (BvhTriangleMesh)null; + BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh(); + int length = 0; + foreach (SkinnedMeshRenderer renderer in (IEnumerable)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)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 outNodes = new List(); + 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 dictionary1 = new Dictionary(); + 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> dictionary2 = new MeshClassifier().MeshHumanoidBoneMatcher(animator, (IReadOnlyList)new SkinnedMeshRenderer[1] + { + smr + }); + for (int index1 = 0; index1 < bodyBones.Length; ++index1) + { + HumanBodyBones bodyBone = (HumanBodyBones)(int)bodyBones[index1]; + HashSet 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 renderers) + { + if (renderers == null || renderers.Count == 0) + return (BvhTriangleMesh)null; + BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh(); + int length = 0; + foreach (SkinnedMeshRenderer renderer in (IEnumerable)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)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 outNodes = new List(); + 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 outNodes = new List(); + 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 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 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 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 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 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 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 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 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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs.meta new file mode 100644 index 0000000..a358551 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/BvhTriangleMesh.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: feac9ce49c744e7458ea3f9a49d761d9 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs new file mode 100644 index 0000000..ff2be05 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs @@ -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, + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs.meta new file mode 100644 index 0000000..222566c --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothBoneType.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5d1467eb46bc3ce4abdcee64c9422a25 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothHumanoidMaskUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothHumanoidMaskUtil.cs new file mode 100644 index 0000000..cd3bf99 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothHumanoidMaskUtil.cs @@ -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 excludedBones = new HashSet(); + Dictionary> humanoidMatchedBones = clothInstance.humanoidMatchedBones; + HashSet 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 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 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 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 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 transformStack = new Stack(); + 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> humanoidMatchedBones = clothInstance.humanoidMatchedBones; + HashSet set1 = new HashSet(); + HashSet set2 = new HashSet(); + HashSet 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 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 set) + { + if (Object.op_Equality((Object)root, (Object)null)) + return; + Stack transformStack = new Stack(); + 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)); + } + } + } + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothHumanoidMaskUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothHumanoidMaskUtil.cs.meta new file mode 100644 index 0000000..22d4427 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothHumanoidMaskUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4e30cb89b417c4648ab8278d89cce772 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs new file mode 100644 index 0000000..37d94cb --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs @@ -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[] vertexAdjacency; + public List> equivalentVertices; + public bool[] isInsideVertex; + public bool[] excludedVertices; + public bool[] isLeftLegVertex; + public bool[] isRightLegVertex; + public Vector3[] bakedWorldNormals; + public Vector4[] bakedWorldTangents; + public Dictionary> humanoidMatchedBones; + + public ClothInstance(SkinnedMeshRenderer clotheSMR, bool duplicateMesh = true) + { + this.smr = clotheSMR; + if (duplicateMesh) + { + string name = ((Object)this.smr.sharedMesh).name; + this.editableMesh = Object.Instantiate(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>(); + 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[] 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[] adj = new List[length]; + for (int index = 0; index < length; ++index) + adj[index] = new List(); + 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> dictionary = new Dictionary>(); + 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 intList; + if (!dictionary.TryGetValue(key, out intList)) + { + intList = new List(); + dictionary[key] = intList; + } + intList.Add(index); + } + foreach (KeyValuePair> keyValuePair in dictionary) + { + Vector3Int key1 = keyValuePair.Key; + List 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 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> dictionary = new Dictionary>(); + 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 intList; + if (!dictionary.TryGetValue(key, out intList)) + { + intList = new List(); + dictionary[key] = intList; + } + intList.Add(index); + } + foreach (KeyValuePair> keyValuePair in dictionary) + { + Vector3Int key3 = keyValuePair.Key; + List 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 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[] adj, int from, int to) + { + List 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>(); + else + this.equivalentVertices.Clear(); + float num1 = maxDistance; + float num2 = maxDistance * maxDistance; + Dictionary> dictionary1 = new Dictionary>(); + 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 intList; + if (!dictionary1.TryGetValue(key, out intList)) + { + intList = new List(); + dictionary1[key] = intList; + } + intList.Add(index); + } + foreach (KeyValuePair> keyValuePair in dictionary1) + { + List 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> dictionary2 = new Dictionary>(); + for (int index = 0; index < count; ++index) + { + int key = Find(index); + List intList2; + if (!dictionary2.TryGetValue(key, out intList2)) + { + intList2 = new List(); + dictionary2[key] = intList2; + } + intList2.Add(intList1[index]); + } + foreach (List 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[])null; + if (this.equivalentVertices != null) + { + for (int index = 0; index < this.equivalentVertices.Count; ++index) + this.equivalentVertices[index]?.Clear(); + this.equivalentVertices.Clear(); + this.equivalentVertices = (List>)null; + } + this.humanoidMatchedBones = (Dictionary>)null; + this.smr = (SkinnedMeshRenderer)null; + this.editableMesh = (Mesh)null; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs.meta new file mode 100644 index 0000000..2eea868 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstance.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7baaee02374c83c47924c148c233808f \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs new file mode 100644 index 0000000..d55a7a4 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs @@ -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 clothInstances; + + public int TotalVertexCount { get; private set; } + + public Vector3[] GlobalPositions { get; private set; } + + public Vector3[] GlobalDeltas { get; private set; } + + public List[] GlobalAdjacencyTopology { get; private set; } + + public List[] GlobalAdjacencyDistance { get; private set; } + + public List[] GlobalAdjacencyMerged { get; private set; } + + public int[] VertexOffsets { get; private set; } + + public ClothInstanceTotal( + List 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[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 intList = clothInstance.vertexAdjacency[index2]; + // ISSUE: explicit non-virtual call + int count = intList != null ? __nonvirtual(intList.Count) : 0; + this.GlobalAdjacencyTopology[num1 + index2] = new List(count); + } + for (int index3 = 0; index3 < length; ++index3) + { + List intList1 = clothInstance.vertexAdjacency[index3]; + if (intList1 != null) + { + List 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[length]; + for (int index1 = 0; index1 < length; ++index1) + { + List intList1 = this.GlobalAdjacencyTopology[index1]; + // ISSUE: explicit non-virtual call + int count1 = intList1 != null ? __nonvirtual(intList1.Count) : 0; + List intList2 = this.GlobalAdjacencyDistance[index1]; + // ISSUE: explicit non-virtual call + int count2 = intList2 != null ? __nonvirtual(intList2.Count) : 0; + List intList3 = new List(count1 + count2); + HashSet intSet = new HashSet(); + List 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 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 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[] 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[] intListArray = new List[length]; + for (int index = 0; index < length; ++index) + intListArray[index] = new List(8); + float num1 = 1f / Mathf.Max(radius, 1E-12f); + float num2 = radius * radius; + Dictionary> dictionary = new Dictionary>(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 intList; + if (!dictionary.TryGetValue(key, out intList)) + { + intList = new List(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 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 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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs.meta new file mode 100644 index 0000000..133c49d --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ClothInstanceTotal.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c3515d0fa4131c9439e99aec94e163bb \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs new file mode 100644 index 0000000..39bf30a --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs @@ -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 sourceBodyMeshes = new List(); + [SerializeField] + private IReadOnlyList sourceBodyMeshesReadOnly = (IReadOnlyList)new List(); + [SerializeField] + public string profileName; + [SerializeField] + public GameObject targetAvatarObject; + [SerializeField] + private GameObject targetClothesObject; + [SerializeField] + private GameObject targetClothesObjectOriginal; + [SerializeField] + private List targetBodyMeshes = new List(); + [SerializeField] + private IReadOnlyList targetBodyMeshesReadOnly = (IReadOnlyList)new List(); + [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> clothesHumanoidMatchedBones; + private Dictionary 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)null; + autoMorpherConfig.profileName = this.profileName; + break; + default: + autoMorpherConfig.sourceAvatarObject = (GameObject)null; + autoMorpherConfig.sourceClothesObject = (GameObject)null; + autoMorpherConfig.sourceBodyMeshes = (IReadOnlyList)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)morpherSetUpUtil.SetupBodyMeshes(this.sourceAvatarObject, this.isBodyAutoSetup, this.sourceBodyMeshes, "Source ").AsReadOnly(); + this.targetBodyMeshesReadOnly = (IReadOnlyList)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)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)morpherSetUpUtil.SetupBodyMeshes(this.sourceAvatarObject, this.isBodyAutoSetup, this.sourceBodyMeshes, "Source ").AsReadOnly(); + this.targetBodyMeshesReadOnly = (IReadOnlyList)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)morpherSetUpUtil.SetupBodyMeshes(this.sourceAvatarObject, this.isBodyAutoSetup, this.sourceBodyMeshes, "Source ").AsReadOnly(); + this.targetBodyMeshesReadOnly = (IReadOnlyList)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)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(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(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()); + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs.meta new file mode 100644 index 0000000..7ad848b --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: eaae26efe7cd8314ab19e85cd1c4c1fa \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherConfig.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherConfig.cs new file mode 100644 index 0000000..eb9347b --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherConfig.cs @@ -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 sourceBodyMeshes; + public GameObject targetAvatarObject; + public GameObject targetClothesObject; + public IReadOnlyList 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> clothesHumanoidMatchedBones; + public Dictionary clothBoneTypeMap; + public string tagEdenMorpehrCloth; + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherConfig.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherConfig.cs.meta new file mode 100644 index 0000000..6f82805 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherConfig.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5a6e56a2e3d0f314a96d690af08d87a9 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherManager.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherManager.cs new file mode 100644 index 0000000..d92c4a6 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherManager.cs @@ -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 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> clothesHumanoidMatchedBones, + bool duplicateMesh = true) + { + this.clothInstances = new List(); + SkinnedMeshRenderer[] targetClothesSMRs = targetClothesObject.GetComponentsInChildren(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> clothesHumanoidMatchedBones, + GameObject sourceClothesObject, + MeshMatcher meshMatcher) + { + this.clothInstances = new List(); + SkinnedMeshRenderer[] targetClothesSMRs = targetClothesObject.GetComponentsInChildren(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(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()); + 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()); + 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()); + 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)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()) == null) + throw new AutoMorpherException("targetBodyBVH is Null", "[EdenAutoMorpherManater] FittingIteration\n - targetBodyBVH is null"); + yield return (object)null; + List bakedTargetBodyMeshes = new List(); + foreach (SkinnedMeshRenderer bodyMesh in (IEnumerable)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 clonedBoneMap = (Dictionary)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(), config.targetBodyMeshes, (IReadOnlyList)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)null; + yield return (object)null; + } + + private void SaveEditedMeshesToAssets( + List 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(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() + { + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherManager.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherManager.cs.meta new file mode 100644 index 0000000..908df4d --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpherManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: db28ab8ea782f894bb3ca3288606e842 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher_SetUpUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher_SetUpUtil.cs new file mode 100644 index 0000000..bcedffd --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher_SetUpUtil.cs @@ -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 gameObjectList = new List(); + foreach (Transform componentsInChild in targetAvatarObject.GetComponentsInChildren(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(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> clothesHumanoidMatchedBones, + out Dictionary 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 bodyRootLocalBones = boneMatchUtil.GetBodyRootLocalBones(config.sourceAvatarObject.transform, config.sourceAvatarObject.GetComponent(), config.sourceBodyMeshes.ToList()); + List rootLocalBones = boneMatchUtil.GetRootLocalBones(config.targetClothesObject.transform, boneMatchUtil.GetMeshBones(((IEnumerable)config.targetClothesObject.GetComponentsInChildren()).ToList())); + Dictionary clothToBodyMatched; + boneMatchUtil.MatchClothesToBodyBones(bodyRootLocalBones, rootLocalBones, out clothesHumanoidMatchedBones, out clothBoneTypeMap, out clothToBodyMatched); + Dictionary 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 clothToBodyMatched, + Dictionary 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> dictionary = new Dictionary>(); + foreach (KeyValuePair keyValuePair in sourceToProxy) + { + Transform key = keyValuePair.Key; + if (!Object.op_Equality((Object)key, (Object)null)) + { + List transformList; + if (!dictionary.TryGetValue(((Object)key).name, out transformList)) + { + transformList = new List(); + 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 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 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> clothesHumanoidMatchedBones, + out Dictionary clothBoneTypeMap) + { + BoneMatchUtil boneMatchUtil = new BoneMatchUtil(); + List bodyRootLocalBones = boneMatchUtil.GetBodyRootLocalBones(config.sourceAvatarObject.transform, config.sourceAvatarObject.GetComponent(), config.sourceBodyMeshes.ToList()); + List rootLocalBones = boneMatchUtil.GetRootLocalBones(config.sourceClothesObject.transform, boneMatchUtil.GetMeshBones(((IEnumerable)config.sourceClothesObject.GetComponentsInChildren()).ToList())); + Dictionary> clothHumanBones; + Dictionary clothBoneTypeMap1; + boneMatchUtil.MatchClothesToBodyBones(bodyRootLocalBones, rootLocalBones, out clothHumanBones, out clothBoneTypeMap1, out Dictionary _); + 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> humanBoneMap1 = meshClassifier.MeshHumanoidBoneMatcher(config.sourceAvatarObject.GetComponent(), config.sourceBodyMeshes); + Dictionary> humanBoneMap2 = meshClassifier.MeshHumanoidBoneMatcher(config.targetAvatarObject.GetComponent(), 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> clothesHumanoidMatchedBones, + out Dictionary 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 rootLocalData = boneMatchUtil.ConvertProfileBoneDataToRootLocalData(profileData.bones); + List rootLocalBones = boneMatchUtil.GetRootLocalBones(config.targetClothesObject.transform, boneMatchUtil.GetMeshBones(((IEnumerable)config.targetClothesObject.GetComponentsInChildren()).ToList())); + boneMatchUtil.MatchClothesToBodyBones(rootLocalData, rootLocalBones, out clothesHumanoidMatchedBones, out clothBoneTypeMap, out Dictionary _); + 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 SetupBodyMeshes( + GameObject bodyObject, + bool isBodyAutoSetup, + List userAllocatedBoeyMeshes, + string errorPreFix = "") + { + EdenAutoMorpherManager autoMorpherManager = new EdenAutoMorpherManager(); + List 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 GetBodyMeshes(GameObject avatarObject) + { + MeshClassifier meshClassifier = new MeshClassifier(); + List bodyMeshes = new List(); + Animator component = avatarObject.GetComponent(); + 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> 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> 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)clothInstance.minDistanceVector).Select((Func)(v => ((Vector3)ref v).magnitude)).ToArray(); + 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 clonedBoneMap) + { + clonedBoneMap = (Dictionary)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() : 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 dictionary1 = new Dictionary(); + if (config.clothesHumanoidMatchedBones != null && config.clothesHumanoidMatchedBones.Count > 0) + { + foreach (KeyValuePair> humanoidMatchedBone in config.clothesHumanoidMatchedBones) + { + HumanBodyBones key2 = humanoidMatchedBone.Key; + HashSet 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 collection = new HashSet(); + for (int index = 0; index < config.targetBodyMeshes.Count; ++index) + { + SkinnedMeshRenderer targetBodyMesh = config.targetBodyMeshes[index]; + if (!Object.op_Equality((Object)targetBodyMesh, (Object)null)) + { + HashSet activeBones = meshClassifier.GetActiveBones(targetBodyMesh); + if (activeBones != null) + { + foreach (Transform transform5 in activeBones) + { + if (Object.op_Inequality((Object)transform5, (Object)null)) + collection.Add(transform5); + } + } + } + } + HashSet transformSet1 = new HashSet((IEnumerable)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 dictionary2 = new Dictionary(transformSet1.Count); + Dictionary dictionary3 = new Dictionary(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> humanoidMatchedBone in config.clothesHumanoidMatchedBones) + { + HashSet 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 resultList = new List(); + List vector3List = new List(); + List quaternionList = new List(); + 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 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); + } + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher_SetUpUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher_SetUpUtil.cs.meta new file mode 100644 index 0000000..e1df727 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/EdenAutoMorpher_SetUpUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 084d635978a925d4caec9538d24f3114 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs new file mode 100644 index 0000000..a693317 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs @@ -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 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 humanBoneTransforms = this.HumanBodyBonesTrsnforms(this.headBones, animator); + return humanBoneTransforms.Count != this.headBones.Length ? (SkinnedMeshRenderer)null : this.GetBoneMatchedMesh(root, humanBoneTransforms); + } + + private List HumanBodyBonesTrsnforms( + HumanBodyBones[] humanBonesList, + Animator animator) + { + List transformList = new List(); + List values = new List(); + 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(", ", (IEnumerable)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 humanBoneTransforms) + { + foreach (SkinnedMeshRenderer componentsInChild in ((Component)root).GetComponentsInChildren(false)) + { + bool flag = true; + HashSet 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 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 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[] bones = smr.bones; + BoneWeight[] boneWeights = sharedMesh.boneWeights; + HashSet intSet = new HashSet(); + 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 activeBones = new HashSet(); + foreach (int index in intSet) + { + if (index >= 0 && index < bones.Length) + activeBones.Add(bones[index]); + } + return activeBones; + } + + public Dictionary> MeshHumanoidBoneMatcher( + Animator animator, + IReadOnlyList bodyMeshes, + float posTolerance = 0.0001f, + float weightThreshold = 0.0001f) + { + Dictionary> dictionary = new Dictionary>(); + if (Object.op_Equality((Object)animator, (Object)null)) + throw new AutoMorpherException("Animator is Missing", "[MeshHumanoidBoneMatcher] MeshHumanoidBoneMatcher\n - animator is null"); + HashSet smrBoneSet = new HashSet(); + if (bodyMeshes != null) + { + foreach (SkinnedMeshRenderer bodyMesh in (IEnumerable)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 transformSet = new HashSet(); + transformSet.Add(boneTransform); + foreach (Transform transform in this.FindBonesByPosition(boneTransform, smrBoneSet, posTolerance)) + transformSet.Add(transform); + dictionary[key] = transformSet; + } + } + return dictionary; + } + + private List FindBonesByPosition( + Transform boneToCheck, + HashSet smrBoneSet, + float posTolerance = 0.0001f) + { + List bonesByPosition = new List(); + 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(); + 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. + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs.meta new file mode 100644 index 0000000..06d8b4f --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshClassifier.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d30a49a0209cbf44282af1dc59c279df \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs new file mode 100644 index 0000000..7cffe15 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs @@ -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 LeftLegBones = new HashSet() + { + (HumanBodyBones) 1, + (HumanBodyBones) 3, + (HumanBodyBones) 5, + (HumanBodyBones) 19 + }; + private readonly HashSet RightLegBones = new HashSet() + { + (HumanBodyBones) 2, + (HumanBodyBones) 4, + (HumanBodyBones) 6, + (HumanBodyBones) 20 + }; + + public BvhTriangleMesh BuildBvhMulti( + IReadOnlyList 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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs.meta new file mode 100644 index 0000000..781c1d4 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MeshMatcher.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d8f0e392696b1cc4b84a811342b1c9a4 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs new file mode 100644 index 0000000..38c02aa --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs @@ -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 + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs.meta new file mode 100644 index 0000000..e40ea11 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherMode.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 051a6a1f505d3684eaff6e056eb3daf5 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs new file mode 100644 index 0000000..ee7d3f2 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs @@ -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, + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs.meta new file mode 100644 index 0000000..5bb5306 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/MorpherState.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e2cbda2228845b345bd4473f31dbbf7f \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs new file mode 100644 index 0000000..399fe32 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs @@ -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 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]); + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs.meta new file mode 100644 index 0000000..75dd1a3 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/PcaUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 19d0bd017b9aa7f4681275eda30241ed \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs new file mode 100644 index 0000000..367d821 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs @@ -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; + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs.meta new file mode 100644 index 0000000..d0738b5 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProcessInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0d43dcdb2d1bafb4a97b6a14f9f954e5 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs new file mode 100644 index 0000000..48a01a9 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs @@ -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 GetProfileList() + { + string path1 = Path.Combine(Application.dataPath, new ProfileUtils().GetProfileBasePath()); + List profileList = new List(); + 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(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(capacity), + datas = new profileBVHData[length1], + nodes = new profileBVHNode[length2], + dataIndices = new int[length3] + }; + profileBvh.vertices.AddRange((IEnumerable)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); + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs.meta new file mode 100644 index 0000000..f1be6a0 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfileLoader.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0a9626ae72afe0240b059a130fd80049 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfilePoseMatchUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfilePoseMatchUtil.cs new file mode 100644 index 0000000..cf9acf8 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfilePoseMatchUtil.cs @@ -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 targetBodyMeshes, + GameObject targetCloth, + ProfileData profileData, + Dictionary> clothHumanBonesMap, + Dictionary 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(), (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> dictionary = this.meshClassifier.MeshHumanoidBoneMatcher(targetAvatar.GetComponent(), 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 targetBakedBodyMeshes = new List(); + foreach (SkinnedMeshRenderer targetBodyMesh in (IEnumerable)targetBodyMeshes) + targetBakedBodyMeshes.Add(new BakedBodyMesh(targetBodyMesh)); + new BodyPoseMatch_Torso().AlignTorsoByNeck(transform1, (IReadOnlyList)targetBakedBodyMeshes, dictionary, clothHumanBonesMap, transform2, profileData, comprehensiveScale); + BodyPoseMatch_Arm bodyPoseMatchArm = new BodyPoseMatch_Arm(); + bodyPoseMatchArm.AlignUpperArmByArmPcaCenters((IReadOnlyList)targetBakedBodyMeshes, dictionary, clothHumanBonesMap, transform2, profileData, comprehensiveScale); + bodyPoseMatchArm.ScalingBothArmsLength((IReadOnlyList)targetBakedBodyMeshes, dictionary, clothHumanBonesMap, profileData, comprehensiveScale); + BodyPoseMatch_Leg bodyPoseMatchLeg = new BodyPoseMatch_Leg(); + bodyPoseMatchLeg.AlignBothUpperLegs(transform1, (IReadOnlyList)targetBakedBodyMeshes, dictionary, transform2, clothHumanBonesMap, profileData, comprehensiveScale); + bodyPoseMatchLeg.ScalingBothLegsAndFoots(transform1, (IReadOnlyList)targetBakedBodyMeshes, dictionary, transform2, clothHumanBonesMap, profileData, comprehensiveScale); + transform1.SetParent(parent1, true); + transform2.SetParent(parent2, true); + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfilePoseMatchUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfilePoseMatchUtil.cs.meta new file mode 100644 index 0000000..0e6292d --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/ProfilePoseMatchUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fed47961631fd674ba17c72e9df7d471 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs new file mode 100644 index 0000000..3959e58 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs @@ -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; + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs.meta new file mode 100644 index 0000000..19abdb6 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/RegionStats.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: daf685816cce49240b2ff0f269905ef5 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs new file mode 100644 index 0000000..9437935 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs @@ -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; + } + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs.meta new file mode 100644 index 0000000..8d2ddfe --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/SkinningUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7ac3681bc6b089040940247042effe43 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs new file mode 100644 index 0000000..2090f34 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs @@ -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 wrappedChildNames = new List(); +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs.meta new file mode 100644 index 0000000..320f75b --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TempBoneMarker.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 87c4265006020574d9a04594d52dc1af \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs new file mode 100644 index 0000000..da7e40a --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs @@ -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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs.meta new file mode 100644 index 0000000..362e47d --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TransformInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9fd2f46f9215e90489540d2e347e6601 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs new file mode 100644 index 0000000..2d70c95 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs @@ -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)); + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs.meta new file mode 100644 index 0000000..c7831d8 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/TriangleUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 309eb633b62714c4e9fe0151790830cb \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs new file mode 100644 index 0000000..7865820 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs @@ -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 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 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 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 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 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 intList = (List)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.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 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 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 intList = (List)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.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 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 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 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 SelectAnchors( + ClothInstance clothInstance, + float worldRadius, + float minDeltaSq = 1E-05f, + float maxDelta = 0.1f) + { + List intList1 = new List(); + List intList2 = new List(); + 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)((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> dictionary = new Dictionary>(); + 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 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 intList4; + if (!dictionary.TryGetValue(cellIndex, out intList4)) + { + intList4 = new List(); + 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[] 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 nodeQueue1 = new Queue(); + List intList1 = new List(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 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 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 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 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[] adjacency = new List[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[] 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(); + } + for (int index3 = 0; index3 < length2; ++index3) + { + List intList1 = vertexAdjacency[index3]; + if (intList1 != null) + { + int index4 = num1 + index3; + List 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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs.meta new file mode 100644 index 0000000..6df64c1 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexFittingUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5a1a63abd53fc6e42b650aa11a54bdc1 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs new file mode 100644 index 0000000..6a8f316 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs @@ -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]; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs.meta new file mode 100644 index 0000000..2306183 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/VertexMoverUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 058c2009c6947e940b398fab24dc792b \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs new file mode 100644 index 0000000..83a8907 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs @@ -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, + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs.meta new file mode 100644 index 0000000..587dbe3 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightKernel.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ca1fec127574c814a8c8306fd2f9aaf0 \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs new file mode 100644 index 0000000..ca27fa0 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs @@ -0,0 +1,1599 @@ +// Decompiled with JetBrains decompiler +// Type: Eden.AutoMorpher.WeightTransferUtil +// 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; +using System.Collections.Generic; +using System.Linq; +using Unity.Collections; +using UnityEditor; +using UnityEngine; + +namespace Eden.AutoMorpher +{ + public class WeightTransferUtil + { + private bool NameContainsAny(string lowerName, string[] patterns) + { + for (int index = 0; index < patterns.Length; ++index) + { + if (lowerName.Contains(patterns[index])) + return true; + } + return false; + } + + private bool IsBreastOrButtBone(Transform t) + { + if (Object.op_Equality((Object)t, (Object)null)) + return false; + string[] patterns1 = new string[6] + { + "breast", + "boob", + "bust", + "oppai", + "chichi", + "mune" + }; + string[] patterns2 = new string[6] + { + "butt", + "buttock", + "buttox", + "glute", + "glutes", + "gluteus" + }; + string lowerInvariant = ((Object)t).name.ToLowerInvariant(); + return this.NameContainsAny(lowerInvariant, patterns1) || this.NameContainsAny(lowerInvariant, patterns2); + } + + public IEnumerator RetargetAndTransfer( + ClothInstance cloth, + Animator avatarAnimator, + IReadOnlyList bodyMeshes, + IReadOnlyList bodyBakedMeshes, + int referenceBodyIndex = 0, + WeightTransferUtil.Settings settings = null, + Dictionary boneTypeMap = null, + Dictionary bodyToClothesMap = null) + { + if (cloth == null || Object.op_Equality((Object)cloth.smr, (Object)null) || Object.op_Equality((Object)cloth.editableMesh, (Object)null)) + throw new AutoMorpherException("Cloth Instance is Invalid", "[WeightTransferUtil] RetargetAndTransfer\n - cloth is null or cloth.smr is null or cloth.editableMesh is null"); + if (cloth.worldVertices == null || cloth.worldVertices.Length == 0) + throw new AutoMorpherException("Cloth World Vertices are Missing", "[WeightTransferUtil] RetargetAndTransfer\n - cloth.worldVertices is null or empty"); + if (Object.op_Equality((Object)cloth.bakedMesh, (Object)null)) + throw new AutoMorpherException("Cloth Baked Mesh is Missing", "[WeightTransferUtil] RetargetAndTransfer\n - cloth.bakedMesh is null"); + if (Object.op_Equality((Object)avatarAnimator, (Object)null) || !avatarAnimator.isHuman) + throw new AutoMorpherException("Avatar Animator is Invalid", "[WeightTransferUtil] RetargetAndTransfer\n - avatarAnimator is null or not a Humanoid"); + if (bodyMeshes == null || bodyMeshes.Count == 0) + throw new AutoMorpherException("Body Meshes are Missing", "[WeightTransferUtil] RetargetAndTransfer\n - bodyMeshes is null or empty"); + if (referenceBodyIndex < 0 || referenceBodyIndex >= bodyMeshes.Count) + referenceBodyIndex = 0; + SkinnedMeshRenderer bodyRefSmr = bodyMeshes[referenceBodyIndex]; + if (Object.op_Equality((Object)bodyRefSmr, (Object)null) || Object.op_Equality((Object)bodyRefSmr.sharedMesh, (Object)null)) + throw new AutoMorpherException("Reference Body Mesh is Invalid", "[WeightTransferUtil] RetargetAndTransfer\n - bodyRefSmr is null or bodyRefSmr.sharedMesh is null\n - referenceBodyIndex : " + referenceBodyIndex.ToString()); + if (settings == null) + settings = new WeightTransferUtil.Settings(); + Transform[] accessoryBones = (Transform[])null; + float[,] accessoryWeights = (float[,])null; + int bodyBoneCount = 0; + BoneWeight[] prevBoneWeights = (BoneWeight[])null; + yield return (object)null; + if (boneTypeMap != null && Object.op_Inequality((Object)cloth.smr, (Object)null) && Object.op_Inequality((Object)cloth.editableMesh, (Object)null)) + { + Transform[] bones = cloth.smr.bones; + if (bones != null && bones.Length != 0) + { + HashSet transformSet1 = (HashSet)null; + if (cloth.humanoidMatchedBones != null) + cloth.humanoidMatchedBones.TryGetValue((HumanBodyBones)10, out transformSet1); + HashSet transformSet2 = new HashSet(); + for (int index = 0; index < bones.Length; ++index) + { + Transform key = bones[index]; + ClothBoneType clothBoneType; + if (!Object.op_Equality((Object)key, (Object)null) && boneTypeMap.TryGetValue(key, out clothBoneType) && clothBoneType == ClothBoneType.Accessory) + transformSet2.Add(key); + } + if (transformSet1 != null) + { + foreach (Transform transform in transformSet1) + { + if (!Object.op_Equality((Object)transform, (Object)null) && Array.IndexOf(bones, transform) >= 0) + transformSet2.Add(transform); + } + } + List transformList = new List(); + Dictionary accIndexByTransform = new Dictionary(); + for (int index = 0; index < bones.Length; ++index) + { + Transform transform = bones[index]; + if (!Object.op_Equality((Object)transform, (Object)null) && transformSet2.Contains(transform) && !this.IsBreastOrButtBone(transform) && !accIndexByTransform.ContainsKey(transform)) + { + accIndexByTransform[transform] = transformList.Count; + transformList.Add(transform); + } + } + if (transformList.Count > 0) + { + accessoryBones = transformList.ToArray(); + int vertexCount = cloth.editableMesh.vertexCount; + accessoryWeights = new float[vertexCount, accessoryBones.Length]; + BoneWeight[] boneWeights = cloth.editableMesh.boneWeights; + if (boneWeights != null && boneWeights.Length == vertexCount) + { + float tiny = 1E-06f; + for (int v = 0; v < vertexCount; ++v) + { + BoneWeight boneWeight = boneWeights[v]; + Acc(((BoneWeight)ref boneWeight).boneIndex0, ((BoneWeight)ref boneWeight).weight0, v); + Acc(((BoneWeight)ref boneWeight).boneIndex1, ((BoneWeight)ref boneWeight).weight1, v); + Acc(((BoneWeight)ref boneWeight).boneIndex2, ((BoneWeight)ref boneWeight).weight2, v); + Acc(((BoneWeight)ref boneWeight).boneIndex3, ((BoneWeight)ref boneWeight).weight3, v); + } + + void Acc(int boneIndex, float w, int v) + { + if ((double)w <= (double)tiny || boneIndex < 0 || boneIndex >= bones.Length) + return; + Transform bone = bones[boneIndex]; + int index; + if (Object.op_Equality((Object)bone, (Object)null) || !accIndexByTransform.TryGetValue(bone, out index)) + return; + accessoryWeights[v, index] += w; + } + } + } + } + } + bodyBoneCount = bodyRefSmr.bones.Length; + yield return (object)null; + this.RetargetClothToAvatarSkeleton(cloth, avatarAnimator, bodyRefSmr, accessoryBones); + this.TransferFromBodyToCloth(avatarAnimator, cloth, bodyMeshes, bodyBakedMeshes, settings, accessoryBones, accessoryWeights, bodyBoneCount, prevBoneWeights); + if (settings.weightInClothes) + this.MoveBodyWeightsToClothesBones(cloth.smr, cloth.smr.sharedMesh, bodyToClothesMap, accessoryBones); + } + + private void RetargetClothToAvatarSkeleton( + ClothInstance cloth, + Animator avatarAnimator, + SkinnedMeshRenderer bodyRefSmr, + Transform[] accessoryBones = null) + { + SkinnedMeshRenderer smr = cloth.smr; + Mesh sharedMesh = cloth.smr.sharedMesh; + if (Object.op_Equality((Object)sharedMesh, (Object)null)) + throw new AutoMorpherException("Cloth Mesh is Missing", "[WeightTransferUtil] RetargetClothToAvatarSkeleton\n - clothMesh is null"); + Transform[] bones1 = smr.bones; + Transform[] bones2 = bodyRefSmr.bones; + if (bones1 == null || bones1.Length == 0 || bones2 == null || bones2.Length == 0) + throw new AutoMorpherException("Cloth or Target Bones are Missing", $"[WeightTransferUtil] RetargetClothToAvatarSkeleton\n - clothBones is null/empty or targetBones is null/empty\n - clothBones.Length : {(bones1 == null ? -1 : bones1.Length).ToString()}\n - targetBones.Length : {(bones2 == null ? -1 : bones2.Length).ToString()}"); + Matrix4x4 localToWorldMatrix = ((Component)smr).transform.localToWorldMatrix; + if (accessoryBones == null || accessoryBones.Length == 0) + { + Dictionary clothBoneToHuman = new Dictionary(); + foreach (KeyValuePair> humanoidMatchedBone in cloth.humanoidMatchedBones) + { + HumanBodyBones key1 = humanoidMatchedBone.Key; + HashSet transformSet = humanoidMatchedBone.Value; + if (transformSet != null) + { + foreach (Transform key2 in transformSet) + { + if (!Object.op_Equality((Object)key2, (Object)null) && !clothBoneToHuman.ContainsKey(key2)) + clothBoneToHuman.Add(key2, key1); + } + } + } + Dictionary humanToTargetBoneIndex = new Dictionary(); + Dictionary dictionary = new Dictionary(); + for (int index = 0; index < bones2.Length; ++index) + { + Transform key = bones2[index]; + if (Object.op_Inequality((Object)key, (Object)null) && !dictionary.ContainsKey(key)) + dictionary.Add(key, index); + } + foreach (HumanBodyBones key in Enum.GetValues(typeof(HumanBodyBones))) + { + if (key != 55) + { + Transform boneTransform = avatarAnimator.GetBoneTransform(key); + int num; + if (!Object.op_Equality((Object)boneTransform, (Object)null) && dictionary.TryGetValue(boneTransform, out num)) + humanToTargetBoneIndex[key] = num; + } + } + BoneWeight[] boneWeights1 = sharedMesh.boneWeights; + if (boneWeights1 == null || boneWeights1.Length == 0) + { + Debug.LogWarning((object)"[WeightTransferUtil] clothMesh.boneWeights 가 비어 있음. 리타겟할 weight 가 없음."); + } + else + { + int vertexCount = sharedMesh.vertexCount; + int length = bones2.Length; + float[,] numArray = new float[vertexCount, length]; + for (int vertIndex = 0; vertIndex < vertexCount; ++vertIndex) + { + BoneWeight boneWeight = boneWeights1[vertIndex]; + this.AccumulateRetargetWeight(numArray, vertIndex, ((BoneWeight)ref boneWeight).boneIndex0, ((BoneWeight)ref boneWeight).weight0, bones1, clothBoneToHuman, humanToTargetBoneIndex); + this.AccumulateRetargetWeight(numArray, vertIndex, ((BoneWeight)ref boneWeight).boneIndex1, ((BoneWeight)ref boneWeight).weight1, bones1, clothBoneToHuman, humanToTargetBoneIndex); + this.AccumulateRetargetWeight(numArray, vertIndex, ((BoneWeight)ref boneWeight).boneIndex2, ((BoneWeight)ref boneWeight).weight2, bones1, clothBoneToHuman, humanToTargetBoneIndex); + this.AccumulateRetargetWeight(numArray, vertIndex, ((BoneWeight)ref boneWeight).boneIndex3, ((BoneWeight)ref boneWeight).weight3, bones1, clothBoneToHuman, humanToTargetBoneIndex); + } + BoneWeight[] boneWeights2 = this.CollapseWeightsToBoneWeights(numArray, 4, 0.0001f); + Matrix4x4[] matrix4x4Array = new Matrix4x4[bones2.Length]; + for (int index = 0; index < bones2.Length; ++index) + { + Transform transform = bones2[index]; + matrix4x4Array[index] = !Object.op_Inequality((Object)transform, (Object)null) ? Matrix4x4.identity : Matrix4x4.op_Multiply(transform.worldToLocalMatrix, localToWorldMatrix); + } + sharedMesh.boneWeights = boneWeights2; + sharedMesh.bindposes = matrix4x4Array; + smr.rootBone = bodyRefSmr.rootBone; + smr.bones = bones2; + EditorUtility.SetDirty((Object)sharedMesh); + EditorUtility.SetDirty((Object)smr); + } + } + else + { + Transform[] bones3 = bodyRefSmr.bones; + if (bones3 == null || bones3.Length == 0) + throw new AutoMorpherException("Target Body Bones are Missing", "[WeightTransferUtil] RetargetClothToAvatarSkeleton\n - bodyRefSmr.bones is null or empty"); + Transform[] bones4 = smr.bones; + Matrix4x4[] bindposes = sharedMesh.bindposes; + Dictionary dictionary = new Dictionary(); + if (bones4 != null) + { + for (int index = 0; index < bones4.Length; ++index) + { + Transform key = bones4[index]; + if (!Object.op_Equality((Object)key, (Object)null) && !dictionary.ContainsKey(key)) + dictionary.Add(key, index); + } + } + int length1 = bones3.Length; + int length2 = accessoryBones.Length; + Transform[] transformArray = new Transform[length1 + length2]; + for (int index = 0; index < length1; ++index) + transformArray[index] = bones3[index]; + for (int index = 0; index < length2; ++index) + transformArray[length1 + index] = accessoryBones[index]; + Matrix4x4[] matrix4x4Array = new Matrix4x4[transformArray.Length]; + for (int index = 0; index < length1; ++index) + { + Transform transform = bones3[index]; + matrix4x4Array[index] = !Object.op_Inequality((Object)transform, (Object)null) ? Matrix4x4.identity : Matrix4x4.op_Multiply(transform.worldToLocalMatrix, localToWorldMatrix); + } + for (int index1 = 0; index1 < length2; ++index1) + { + Transform accessoryBone = accessoryBones[index1]; + Matrix4x4 matrix4x4 = Matrix4x4.identity; + int index2; + if (Object.op_Inequality((Object)accessoryBone, (Object)null) && dictionary.TryGetValue(accessoryBone, out index2)) + matrix4x4 = bindposes == null || index2 < 0 || index2 >= bindposes.Length ? Matrix4x4.op_Multiply(accessoryBone.worldToLocalMatrix, localToWorldMatrix) : bindposes[index2]; + matrix4x4Array[length1 + index1] = matrix4x4; + } + sharedMesh.bindposes = matrix4x4Array; + sharedMesh.boneWeights = new BoneWeight[sharedMesh.vertexCount]; + smr.rootBone = bodyRefSmr.rootBone; + smr.bones = transformArray; + EditorUtility.SetDirty((Object)sharedMesh); + EditorUtility.SetDirty((Object)smr); + } + } + + private void AccumulateRetargetWeight( + float[,] W, + int vertIndex, + int clothBoneIndex, + float weight, + Transform[] clothBones, + Dictionary clothBoneToHuman, + Dictionary humanToTargetBoneIndex) + { + if ((double)weight <= 0.0 || clothBoneIndex < 0 || clothBoneIndex >= clothBones.Length) + return; + Transform clothBone = clothBones[clothBoneIndex]; + HumanBodyBones key; + int index; + if (Object.op_Equality((Object)clothBone, (Object)null) || !clothBoneToHuman.TryGetValue(clothBone, out key) || !humanToTargetBoneIndex.TryGetValue(key, out index)) + return; + W[vertIndex, index] += weight; + } + + private void TransferFromBodyToCloth( + Animator avatarAnimator, + ClothInstance cloth, + IReadOnlyList bodyMeshes, + IReadOnlyList bodyBakedMeshes, + WeightTransferUtil.Settings settings, + Transform[] accessoryBones, + float[,] accessoryWeights, + int bodyBoneCount, + BoneWeight[] prevBoneWeights = null) + { + Vector3[] worldVertices = cloth.worldVertices; + if (worldVertices == null || worldVertices.Length == 0) + throw new AutoMorpherException("Cloth World Vertices are Missing", "[WeightTransferUtil] TransferFromBodyToCloth\n - cloth.worldVertices is null or empty"); + int[] triangles1 = cloth.editableMesh.triangles; + Vector3[] clothWorldNormals = this.GetClothWorldNormals(cloth); + if (clothWorldNormals == null || clothWorldNormals.Length != worldVertices.Length) + throw new AutoMorpherException("Cloth World Normals Calculation Failed", $"[WeightTransferUtil] TransferFromBodyToCloth\n - targetNormalsWorld is null or length mismatch\n - targetVertsWorld.Length : {(worldVertices == null ? -1 : worldVertices.Length).ToString()}\n - targetNormalsWorld.Length : {(clothWorldNormals == null ? -1 : clothWorldNormals.Length).ToString()}"); + Transform[] bones1 = cloth.smr.bones; + int length1 = bones1.Length; + Dictionary targetBoneIndexByTransform = new Dictionary(); + for (int index = 0; index < bones1.Length; ++index) + { + Transform key = bones1[index]; + if (Object.op_Inequality((Object)key, (Object)null) && !targetBoneIndexByTransform.ContainsKey(key)) + targetBoneIndexByTransform.Add(key, index); + } + int length2 = 0; + int length3 = 0; + foreach (SkinnedMeshRenderer bodyMesh in (IEnumerable)bodyMeshes) + { + if (!Object.op_Equality((Object)bodyMesh, (Object)null) && !Object.op_Equality((Object)bodyMesh.sharedMesh, (Object)null)) + { + length2 += bodyMesh.sharedMesh.vertexCount; + length3 += bodyMesh.sharedMesh.triangles.Length; + } + } + Vector3[] sourceVerts = length2 != 0 && length3 != 0 ? new Vector3[length2] : throw new AutoMorpherException("Valid Body Mesh is Missing", "[WeightTransferUtil] TransferFromBodyToCloth\n - bodyMeshes has no valid mesh (totalVerts == 0 or totalTris == 0)"); + Vector3[] sourceNormals = new Vector3[length2]; + int[] sourceTris = new int[length3]; + float[,] W = new float[length2, length1]; + int num1 = 0; + int num2 = 0; + for (int index1 = 0; index1 < bodyMeshes.Count; ++index1) + { + SkinnedMeshRenderer bodyMesh = bodyMeshes[index1]; + if (!Object.op_Equality((Object)bodyMesh, (Object)null) && !Object.op_Equality((Object)bodyMesh.sharedMesh, (Object)null)) + { + Mesh sharedMesh = bodyMesh.sharedMesh; + Mesh bodyBakedMesh = bodyBakedMeshes[index1]; + Vector3[] vertices = bodyBakedMesh.vertices; + Vector3[] normals = bodyBakedMesh.normals; + int[] triangles2 = bodyBakedMesh.triangles; + int vertexCount = bodyBakedMesh.vertexCount; + Vector3 lossyScale = ((Component)bodyMesh).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(((Component)bodyMesh).transform.localToWorldMatrix, Matrix4x4.Scale(vector3_1)); + for (int index2 = 0; index2 < vertexCount; ++index2) + { + sourceVerts[num1 + index2] = ((Matrix4x4)ref matrix4x4).MultiplyPoint3x4(vertices[index2]); + Vector3 vector3_2 = ((Matrix4x4)ref matrix4x4).MultiplyVector(normals[index2]); + Vector3 normalized = ((Vector3)ref vector3_2).normalized; + sourceNormals[num1 + index2] = normalized; + } + for (int index3 = 0; index3 < triangles2.Length; ++index3) + sourceTris[num2 + index3] = triangles2[index3] + num1; + BoneWeight[] boneWeights = sharedMesh.boneWeights; + Transform[] bones2 = bodyMesh.bones; + if (boneWeights != null && boneWeights.Length == vertexCount && bones2 != null) + { + for (int index4 = 0; index4 < vertexCount; ++index4) + { + BoneWeight boneWeight = boneWeights[index4]; + this.AccumulateBodyWeight(ref W, num1 + index4, ((BoneWeight)ref boneWeight).boneIndex0, ((BoneWeight)ref boneWeight).weight0, bones2, targetBoneIndexByTransform); + this.AccumulateBodyWeight(ref W, num1 + index4, ((BoneWeight)ref boneWeight).boneIndex1, ((BoneWeight)ref boneWeight).weight1, bones2, targetBoneIndexByTransform); + this.AccumulateBodyWeight(ref W, num1 + index4, ((BoneWeight)ref boneWeight).boneIndex2, ((BoneWeight)ref boneWeight).weight2, bones2, targetBoneIndexByTransform); + this.AccumulateBodyWeight(ref W, num1 + index4, ((BoneWeight)ref boneWeight).boneIndex3, ((BoneWeight)ref boneWeight).weight3, bones2, targetBoneIndexByTransform); + } + } + num1 += vertexCount; + num2 += triangles2.Length; + } + } + List[] adjacency = cloth.vertexAdjacency; + if (adjacency == null || adjacency.Length != worldVertices.Length) + adjacency = this.BuildAdjacencyFromTriangles(worldVertices.Length, triangles1); + bool[] matchedMask; + float[,] matchesClosestSurface = this.FindMatchesClosestSurface(sourceVerts, sourceTris, sourceNormals, worldVertices, clothWorldNormals, W, settings.maxDistance * settings.maxDistance, settings.maxNormalAngleDeg, settings.allowFlippedNormal, out matchedMask); + float[,] numArray = this.InpaintApprox(worldVertices, triangles1, matchesClosestSurface, matchedMask, adjacency, 20, 0.7f); + if (settings.enableSmoothing && settings.smoothingIterations > 0 && (double)settings.smoothingAlpha > 0.0) + numArray = this.SmoothWeightsApprox(worldVertices, numArray, matchedMask, adjacency, settings.smoothingIterations, settings.smoothingAlpha, settings.maxDistance); + this.ApplyLegVertexConstraints(avatarAnimator, cloth, numArray, bodyBoneCount, settings.tinyWeight); + int vertexCount1 = cloth.editableMesh.vertexCount; + int length4 = cloth.smr.bones.Length; + if (accessoryBones != null && accessoryBones.Length != 0 && accessoryWeights != null && bodyBoneCount > 0) + { + HashSet transformSet = (HashSet)null; + if (cloth.humanoidMatchedBones != null) + cloth.humanoidMatchedBones.TryGetValue((HumanBodyBones)10, out transformSet); + Transform transform1 = (Transform)null; + if (Object.op_Inequality((Object)avatarAnimator, (Object)null)) + transform1 = avatarAnimator.GetBoneTransform((HumanBodyBones)10); + if (transformSet != null && Object.op_Inequality((Object)transform1, (Object)null)) + { + int index5 = Array.IndexOf(cloth.smr.bones, transform1); + if (index5 >= 0 && index5 < bodyBoneCount) + { + foreach (Transform transform2 in transformSet) + { + if (!Object.op_Equality((Object)transform2, (Object)null)) + { + int index6 = Array.IndexOf(accessoryBones, transform2); + if (index6 >= 0) + { + for (int index7 = 0; index7 < vertexCount1; ++index7) + { + float accessoryWeight = accessoryWeights[index7, index6]; + if ((double)accessoryWeight > (double)settings.tinyWeight) + { + numArray[index7, index5] += accessoryWeight; + accessoryWeights[index7, index6] = 0.0f; + } + } + } + } + } + } + } + } + BoneWeight[] boneWeightArray; + if (accessoryBones != null && accessoryBones.Length != 0 && accessoryWeights != null && bodyBoneCount > 0 && bodyBoneCount + accessoryBones.Length == length4) + { + boneWeightArray = this.MergeBodyAndAccessoryWeights(numArray, accessoryWeights, bodyBoneCount, settings.tinyWeight, settings.enforceFourBoneLimit); + } + else + { + if (settings.enforceFourBoneLimit) + this.EnforceMaxBonesPerVertex(numArray, 4, settings.tinyWeight); + else + this.ZeroSmallWeights(numArray, settings.tinyWeight); + this.NormalizeWeightsPerVertex(numArray, settings.tinyWeight); + boneWeightArray = this.CollapseWeightsToBoneWeights(numArray, 4, settings.tinyWeight); + } + Mesh sharedMesh1 = cloth.smr.sharedMesh; + if (sharedMesh1.vertexCount != boneWeightArray.Length) + throw new AutoMorpherException("Vertex Count and Weight Length Mismatch", $"[WeightTransferUtil] TransferFromBodyToCloth\n - mesh.vertexCount : {sharedMesh1.vertexCount.ToString()}\n - finalWeights.Length : {boneWeightArray.Length.ToString()}"); + this.EnsureNonZeroAndNormalizeFinalWeights(cloth, boneWeightArray, adjacency, settings.tinyWeight); + this.ApplyEquivalentVertexWeights(cloth, boneWeightArray); + this.NormalizeAllBoneWeightsInPlace(boneWeightArray, settings.tinyWeight); + sharedMesh1.boneWeights = boneWeightArray; + cloth.smr.sharedMesh = sharedMesh1; + int zeroWeightVertexCount; + if (this.TryApplyBoneWeightsWithValidation(sharedMesh1, boneWeightArray, 1E-10f, out zeroWeightVertexCount)) + return; + Debug.LogWarning((object)$"[WeightValidation] Zero-weight vertices detected: {zeroWeightVertexCount}"); + } + + public void MoveBodyWeightsToClothesBones( + SkinnedMeshRenderer clothesSmr, + Mesh clothesMesh, + Dictionary bodyToClothesMap, + Transform[] accessoryBones) + { + if (Object.op_Equality((Object)clothesSmr, (Object)null)) + throw new AutoMorpherException("Clothes SMR is Missing", "[WeightTransferUtil] MoveBodyWeightsToClothesBones\n - clothesSmr is null"); + if (Object.op_Equality((Object)clothesMesh, (Object)null)) + throw new AutoMorpherException("Clothes Mesh is Missing", "[WeightTransferUtil] MoveBodyWeightsToClothesBones\n - clothesMesh is null"); + if (bodyToClothesMap == null) + throw new AutoMorpherException("Body To Clothes Map is Missing", "[WeightTransferUtil] MoveBodyWeightsToClothesBones\n - bodyToClothesMap is null"); + Transform clothesFallbackRoot = Object.op_Inequality((Object)clothesSmr.rootBone, (Object)null) ? clothesSmr.rootBone : ((Component)clothesSmr).transform; + HashSet transformSet = (HashSet)null; + if (accessoryBones != null && accessoryBones.Length != 0) + transformSet = new HashSet((IEnumerable)accessoryBones); + Transform[] bones = clothesSmr.bones; + Transform[] transformArray = bones != null && bones.Length != 0 ? new Transform[bones.Length] : throw new AutoMorpherException("Clothes Bones are Missing", "[WeightTransferUtil] MoveBodyWeightsToClothesBones\n - clothesSmr.bones is null or empty"); + for (int index = 0; index < bones.Length; ++index) + { + Transform bodyBone = bones[index]; + if (Object.op_Equality((Object)bodyBone, (Object)null)) + transformArray[index] = clothesFallbackRoot; + else if (transformSet != null && transformSet.Contains(bodyBone)) + { + transformArray[index] = bodyBone; + } + else + { + Transform transform = EnsureClothesBoneExists(bodyBone); + transformArray[index] = Object.op_Inequality((Object)transform, (Object)null) ? transform : clothesFallbackRoot; + } + } + clothesSmr.bones = transformArray; + if (Object.op_Inequality((Object)clothesSmr.rootBone, (Object)null) && (transformSet == null || !transformSet.Contains(clothesSmr.rootBone))) + { + Transform transform = EnsureClothesBoneExists(clothesSmr.rootBone); + if (Object.op_Inequality((Object)transform, (Object)null)) + clothesSmr.rootBone = transform; + } + Transform transform1 = Object.op_Inequality((Object)clothesSmr.rootBone, (Object)null) ? clothesSmr.rootBone : ((Component)clothesSmr).transform; + Matrix4x4[] matrix4x4Array = new Matrix4x4[transformArray.Length]; + for (int index = 0; index < transformArray.Length; ++index) + { + Transform transform2 = transformArray[index]; + if (Object.op_Equality((Object)transform2, (Object)null)) + throw new AutoMorpherException("Remapped Bone is Null", "[WeightTransferUtil] MoveBodyWeightsToClothesBones\n - remappedBones contains null bone after fallback"); + matrix4x4Array[index] = Matrix4x4.op_Multiply(transform2.worldToLocalMatrix, transform1.localToWorldMatrix); + } + clothesMesh.bindposes = matrix4x4Array; + + Transform EnsureClothesBoneExists(Transform bodyBone) + { + if (Object.op_Equality((Object)bodyBone, (Object)null)) + return (Transform)null; + Transform transform1; + if (bodyToClothesMap.TryGetValue(bodyBone, out transform1) && Object.op_Inequality((Object)transform1, (Object)null)) + return transform1; + Transform transform2 = (Transform)null; + if (Object.op_Inequality((Object)bodyBone.parent, (Object)null)) + transform2 = EnsureClothesBoneExists(bodyBone.parent); + if (Object.op_Equality((Object)transform2, (Object)null)) + transform2 = clothesFallbackRoot; + Transform transform3 = new GameObject(((Object)bodyBone).name).transform; + transform3.SetParent(transform2, false); + transform3.localPosition = bodyBone.localPosition; + transform3.localRotation = bodyBone.localRotation; + transform3.localScale = bodyBone.localScale; + bodyToClothesMap[bodyBone] = transform3; + return transform3; + } + } + + private bool TryApplyBoneWeightsWithValidation( + Mesh mesh, + BoneWeight[] weights, + float tiny, + out int zeroWeightVertexCount) + { + bool flag = true; + zeroWeightVertexCount = 0; + int length = weights.Length; + NativeArray nativeArray1 = new NativeArray(length, (Allocator)2, (NativeArrayOptions)1); + List list = new List(length * 4); + NativeArray nativeArray2 = new NativeArray(); + try + { + for (int index = 0; index < length; ++index) + { + BoneWeight weight = weights[index]; + int count = 0; + this.AddIfValid(list, ((BoneWeight)ref weight).boneIndex0, ((BoneWeight)ref weight).weight0, tiny, ref count); + this.AddIfValid(list, ((BoneWeight)ref weight).boneIndex1, ((BoneWeight)ref weight).weight1, tiny, ref count); + this.AddIfValid(list, ((BoneWeight)ref weight).boneIndex2, ((BoneWeight)ref weight).weight2, tiny, ref count); + this.AddIfValid(list, ((BoneWeight)ref weight).boneIndex3, ((BoneWeight)ref weight).weight3, tiny, ref count); + if (count == 0) + ++zeroWeightVertexCount; + nativeArray1[index] = (byte)count; + } + if (zeroWeightVertexCount > 0) + return false; + nativeArray2 = new NativeArray(list.Count, (Allocator)2, (NativeArrayOptions)1); + for (int index = 0; index < list.Count; ++index) + nativeArray2[index] = list[index]; + mesh.SetBoneWeights(nativeArray1, nativeArray2); + } + catch (Exception ex) + { + Debug.LogWarning((object)("[SetBoneWeights] Failed: " + ex.Message)); + flag = false; + } + finally + { + if (nativeArray2.IsCreated) + nativeArray2.Dispose(); + if (nativeArray1.IsCreated) + nativeArray1.Dispose(); + } + return flag; + } + + private void AddIfValid( + List list, + int boneIndex, + float weight, + float tiny, + ref int count) + { + if (boneIndex < 0 || (double)weight <= (double)tiny) + return; + List boneWeight1List = list; + BoneWeight1 boneWeight1_1 = new BoneWeight1(); + ((BoneWeight1)ref boneWeight1_1).boneIndex = boneIndex; + ((BoneWeight1)ref boneWeight1_1).weight = weight; + BoneWeight1 boneWeight1_2 = boneWeight1_1; + boneWeight1List.Add(boneWeight1_2); + ++count; + } + + private void ApplyEquivalentVertexWeights(ClothInstance cloth, BoneWeight[] finalWeights) + { + if (cloth == null || cloth.equivalentVertices == null || cloth.equivalentVertices.Count == 0 || finalWeights == null || finalWeights.Length == 0) + return; + List> equivalentVertices = cloth.equivalentVertices; + int length = finalWeights.Length; + bool[] flagArray = new bool[length]; + foreach (List intList1 in equivalentVertices) + { + if (intList1 != null && intList1.Count != 0) + { + List intList2 = (List)null; + bool flag = false; + for (int index1 = 0; index1 < intList1.Count; ++index1) + { + int index2 = intList1[index1]; + if (index2 >= 0 && index2 < length) + { + if (intList2 == null) + intList2 = new List(); + intList2.Add(index2); + if (!flagArray[index2]) + flag = true; + } + } + if (intList2 != null && flag) + { + Dictionary weightMap = new Dictionary(); + foreach (int index in intList2) + { + BoneWeight finalWeight = finalWeights[index]; + Accumulate(((BoneWeight)ref finalWeight).boneIndex0, ((BoneWeight)ref finalWeight).weight0); + Accumulate(((BoneWeight)ref finalWeight).boneIndex1, ((BoneWeight)ref finalWeight).weight1); + Accumulate(((BoneWeight)ref finalWeight).boneIndex2, ((BoneWeight)ref finalWeight).weight2); + Accumulate(((BoneWeight)ref finalWeight).boneIndex3, ((BoneWeight)ref finalWeight).weight3); + } + if (weightMap.Count != 0) + { + List> list = weightMap.OrderByDescending, float>((Func, float>)(kv => kv.Value)).Take>(4).ToList>(); + float num1 = 0.0f; + for (int index = 0; index < Math.Min(4, list.Count); ++index) + num1 += list[index].Value; + if ((double)num1 > 9.99999993922529E-09) + { + BoneWeight boneWeight = new BoneWeight(); + for (int index = 0; index < Math.Min(4, list.Count); ++index) + { + KeyValuePair keyValuePair = list[index]; + int key = keyValuePair.Key; + keyValuePair = list[index]; + float num2 = keyValuePair.Value / num1; + switch (index) + { + case 0: + ((BoneWeight)ref boneWeight).boneIndex0 = key; + ((BoneWeight)ref boneWeight).weight0 = num2; + break; + case 1: + ((BoneWeight)ref boneWeight).boneIndex1 = key; + ((BoneWeight)ref boneWeight).weight1 = num2; + break; + case 2: + ((BoneWeight)ref boneWeight).boneIndex2 = key; + ((BoneWeight)ref boneWeight).weight2 = num2; + break; + case 3: + ((BoneWeight)ref boneWeight).boneIndex3 = key; + ((BoneWeight)ref boneWeight).weight3 = num2; + break; + } + } + foreach (int index in intList2) + { + finalWeights[index] = boneWeight; + flagArray[index] = true; + } + } + } + + void Accumulate(int boneIndex, float w) + { + if ((double)w <= 0.0 || boneIndex < 0) + return; + float num; + if (weightMap.TryGetValue(boneIndex, out num)) + weightMap[boneIndex] = num + w; + else + weightMap[boneIndex] = w; + } + } + } + } + } + + private void ApplyLegVertexConstraints( + Animator avatarAnimator, + ClothInstance cloth, + float[,] weights, + int bodyBoneCount, + float tinyWeight) + { + if (cloth == null || Object.op_Equality((Object)cloth.smr, (Object)null)) + return; + bool[] isLeftLegVertex = cloth.isLeftLegVertex; + bool[] isRightLegVertex = cloth.isRightLegVertex; + if (isLeftLegVertex == null && isRightLegVertex == null) + return; + Transform[] bones = cloth.smr.bones; + if (bones == null) + return; + int length1 = weights.GetLength(0); + int length2 = weights.GetLength(1); + Transform boneTransform1 = avatarAnimator.GetBoneTransform((HumanBodyBones)1); + Transform boneTransform2 = avatarAnimator.GetBoneTransform((HumanBodyBones)2); + bool[] flagArray1 = new bool[length2]; + bool[] flagArray2 = new bool[length2]; + int num = Mathf.Min(bodyBoneCount, bones.Length); + for (int index = 0; index < num; ++index) + { + Transform transform = bones[index]; + if (!Object.op_Equality((Object)transform, (Object)null)) + { + if (transform.IsChildOf(boneTransform1)) + flagArray1[index] = true; + else if (transform.IsChildOf(boneTransform2)) + flagArray2[index] = true; + } + } + for (int index1 = 0; index1 < length1; ++index1) + { + bool flag1 = isLeftLegVertex != null && index1 < isLeftLegVertex.Length && isLeftLegVertex[index1]; + bool flag2 = isRightLegVertex != null && index1 < isRightLegVertex.Length && isRightLegVertex[index1]; + if (flag1 || flag2) + { + for (int index2 = 0; index2 < length2; ++index2) + { + if ((double)weights[index1, index2] > (double)tinyWeight) + { + if (flag1) + { + if (flagArray2[index2]) + weights[index1, index2] = 0.0f; + } + else if (flag2 && flagArray1[index2]) + weights[index1, index2] = 0.0f; + } + } + } + } + } + + private Vector3[] GetClothWorldNormals(ClothInstance cloth) + { + if (cloth.worldVertices == null) + return (Vector3[])null; + int length = cloth.worldVertices.Length; + if (Object.op_Equality((Object)cloth.bakedMesh, (Object)null) || cloth.bakedMesh.vertexCount != length) + throw new AutoMorpherException("Cloth Baked Mesh is Invalid", $"[WeightTransferUtil] GetClothWorldNormals\n - bakedMesh is null or vertexCount mismatch\n - bakedMesh.vertexCount : {(Object.op_Equality((Object)cloth.bakedMesh, (Object)null) ? -1 : cloth.bakedMesh.vertexCount).ToString()}\n - worldVertices.Length : {length.ToString()}"); + Vector3[] clothWorldNormals = new Vector3[length]; + Mesh bakedMesh = cloth.bakedMesh; + Vector3[] normals = bakedMesh.normals; + if (normals == null || normals.Length != length) + { + bakedMesh.RecalculateNormals(); + normals = bakedMesh.normals; + } + for (int index = 0; index < length; ++index) + { + Vector3 vector3 = ((Matrix4x4)ref cloth.worldNoScale).MultiplyVector(normals[index]); + Vector3 normalized = ((Vector3)ref vector3).normalized; + clothWorldNormals[index] = normalized; + } + return clothWorldNormals; + } + + private void AccumulateBodyWeight( + ref float[,] W, + int vIndex, + int localBoneIndex, + float weight, + Transform[] bodyBones, + Dictionary targetBoneIndexByTransform) + { + if ((double)weight <= 0.0 || bodyBones == null || localBoneIndex < 0 || localBoneIndex >= bodyBones.Length) + return; + Transform bodyBone = bodyBones[localBoneIndex]; + int index; + if (Object.op_Equality((Object)bodyBone, (Object)null) || !targetBoneIndexByTransform.TryGetValue(bodyBone, out index)) + return; + W[vIndex, index] += weight; + } + + private List[] BuildAdjacencyFromTriangles(int vertexCount, int[] triangles) + { + List[] adj = new List[vertexCount]; + for (int index = 0; index < vertexCount; ++index) + adj[index] = new List(); + int num = triangles.Length / 3; + for (int index = 0; index < num; ++index) + { + int triangle1 = triangles[index * 3]; + int triangle2 = triangles[index * 3 + 1]; + int triangle3 = triangles[index * 3 + 2]; + this.AddEdge(adj, triangle1, triangle2); + this.AddEdge(adj, triangle2, triangle3); + this.AddEdge(adj, triangle3, triangle1); + } + return adj; + } + + private void AddEdge(List[] adj, int a, int b) + { + if (!adj[a].Contains(b)) + adj[a].Add(b); + if (adj[b].Contains(a)) + return; + adj[b].Add(a); + } + + private float[,] FindMatchesClosestSurface( + Vector3[] sourceVerts, + int[] sourceTris, + Vector3[] sourceNormals, + Vector3[] targetVerts, + Vector3[] targetNormals, + float[,] sourceWeights, + float distanceThresholdSqr, + float angleThresholdDeg, + bool flipVertexNormal, + out bool[] matchedMask) + { + int length1 = targetVerts.Length; + int length2 = sourceWeights.GetLength(1); + float[,] matchesClosestSurface = new float[length1, length2]; + matchedMask = new bool[length1]; + int num1 = sourceTris.Length / 3; + float num2 = angleThresholdDeg * ((float)Math.PI / 180f); + for (int index1 = 0; index1 < length1; ++index1) + { + Vector3 targetVert = targetVerts[index1]; + float num3 = float.PositiveInfinity; + int num4 = -1; + Vector3 vector3_1 = Vector3.zero; + for (int index2 = 0; index2 < num1; ++index2) + { + int sourceTri1 = sourceTris[index2 * 3]; + int sourceTri2 = sourceTris[index2 * 3 + 1]; + int sourceTri3 = sourceTris[index2 * 3 + 2]; + Vector3 sourceVert1 = sourceVerts[sourceTri1]; + Vector3 sourceVert2 = sourceVerts[sourceTri2]; + Vector3 sourceVert3 = sourceVerts[sourceTri3]; + Vector3 bary; + Vector3 vector3_2 = this.ClosestPointOnTriangle(targetVert, sourceVert1, sourceVert2, sourceVert3, out bary); + Vector3 vector3_3 = Vector3.op_Subtraction(targetVert, vector3_2); + float sqrMagnitude = ((Vector3)ref vector3_3).sqrMagnitude; + if ((double)sqrMagnitude < (double)num3) + { + num3 = sqrMagnitude; + num4 = index2; + vector3_1 = bary; + } + } + if (num4 < 0) + { + matchedMask[index1] = false; + } + else + { + int num5 = (double)num3 <= (double)distanceThresholdSqr ? 1 : 0; + int sourceTri4 = sourceTris[num4 * 3]; + int sourceTri5 = sourceTris[num4 * 3 + 1]; + int sourceTri6 = sourceTris[num4 * 3 + 2]; + Vector3 sourceNormal1 = sourceNormals[sourceTri4]; + Vector3 sourceNormal2 = sourceNormals[sourceTri5]; + Vector3 sourceNormal3 = sourceNormals[sourceTri6]; + double x = (double)vector3_1.x; + Vector3 vector3_4 = Vector3.op_Addition(Vector3.op_Addition(Vector3.op_Multiply(sourceNormal1, (float)x), Vector3.op_Multiply(sourceNormal2, vector3_1.y)), Vector3.op_Multiply(sourceNormal3, vector3_1.z)); + float num6 = Mathf.Acos(Mathf.Clamp(Vector3.Dot(((Vector3)ref vector3_4).normalized, ((Vector3)ref targetNormals[index1]).normalized), -1f, 1f)); + bool flag1 = (double)num6 <= (double)num2; + if (flipVertexNormal && 3.1415927410125732 - (double)num6 <= (double)num2) + flag1 = true; + int num7 = flag1 ? 1 : 0; + bool flag2 = (num5 & num7) != 0; + matchedMask[index1] = flag2; + for (int index3 = 0; index3 < length2; ++index3) + { + float sourceWeight1 = sourceWeights[sourceTri4, index3]; + float sourceWeight2 = sourceWeights[sourceTri5, index3]; + float sourceWeight3 = sourceWeights[sourceTri6, index3]; + matchesClosestSurface[index1, index3] = (float)((double)sourceWeight1 * (double)vector3_1.x + (double)sourceWeight2 * (double)vector3_1.y + (double)sourceWeight3 * (double)vector3_1.z); + } + } + } + return matchesClosestSurface; + } + + private Vector3 ClosestPointOnTriangle( + Vector3 p, + Vector3 a, + Vector3 b, + Vector3 c, + out Vector3 bary) + { + 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) + { + bary = new Vector3(1f, 0.0f, 0.0f); + 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) + { + bary = new Vector3(0.0f, 1f, 0.0f); + 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); + bary = new Vector3(1f - num6, num6, 0.0f); + return Vector3.op_Addition(a, Vector3.op_Multiply(vector3_1, num6)); + } + 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) + { + bary = new Vector3(0.0f, 0.0f, 1f); + 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); + bary = new Vector3(1f - num10, 0.0f, num10); + return Vector3.op_Addition(a, Vector3.op_Multiply(vector3_2, num10)); + } + 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))); + bary = new Vector3(0.0f, 1f - num12, num12); + return Vector3.op_Addition(b, Vector3.op_Multiply(Vector3.op_Subtraction(c, b), num12)); + } + float num13 = (float)(1.0 / ((double)num11 + (double)num9 + (double)num5)); + float num14 = num9 * num13; + float num15 = num5 * num13; + float num16 = 1f - num14 - num15; + bary = new Vector3(num16, num14, num15); + return Vector3.op_Addition(Vector3.op_Addition(Vector3.op_Multiply(a, num16), Vector3.op_Multiply(b, num14)), Vector3.op_Multiply(c, num15)); + } + + private void ZeroSmallWeights(float[,] weights, float tiny) + { + int length1 = weights.GetLength(0); + int length2 = weights.GetLength(1); + for (int index1 = 0; index1 < length1; ++index1) + { + for (int index2 = 0; index2 < length2; ++index2) + { + if ((double)weights[index1, index2] <= (double)tiny) + weights[index1, index2] = 0.0f; + } + } + } + + private void EnforceMaxBonesPerVertex(float[,] weights, int maxBonesPerVertex, float tinyWeight) + { + int length1 = weights.GetLength(0); + int length2 = weights.GetLength(1); + for (int index1 = 0; index1 < length1; ++index1) + { + List<(int, float)> valueTupleList = new List<(int, float)>(); + for (int index2 = 0; index2 < length2; ++index2) + { + float weight = weights[index1, index2]; + if ((double)weight > (double)tinyWeight) + valueTupleList.Add((index2, weight)); + } + valueTupleList.Sort((Comparison<(int, float)>)((a, b) => b.w.CompareTo(a.w))); + HashSet intSet = new HashSet(); + int num = Mathf.Min(maxBonesPerVertex, valueTupleList.Count); + for (int index3 = 0; index3 < num; ++index3) + intSet.Add(valueTupleList[index3].Item1); + for (int index4 = 0; index4 < length2; ++index4) + { + if (!intSet.Contains(index4) || (double)weights[index1, index4] <= (double)tinyWeight) + weights[index1, index4] = 0.0f; + } + } + } + + private void NormalizeWeightsPerVertex(float[,] weights, float tiny) + { + int length1 = weights.GetLength(0); + int length2 = weights.GetLength(1); + for (int index1 = 0; index1 < length1; ++index1) + { + float num1 = 0.0f; + for (int index2 = 0; index2 < length2; ++index2) + num1 += weights[index1, index2]; + if ((double)num1 >= (double)tiny) + { + float num2 = 1f / num1; + for (int index3 = 0; index3 < length2; ++index3) + weights[index1, index3] *= num2; + } + } + } + + private BoneWeight[] CollapseWeightsToBoneWeights( + float[,] weights, + int maxBonesPerVert, + float tiny) + { + int length1 = weights.GetLength(0); + int length2 = weights.GetLength(1); + BoneWeight[] boneWeights = new BoneWeight[length1]; + for (int index1 = 0; index1 < length1; ++index1) + { + List<(int, float)> valueTupleList = new List<(int, float)>(); + for (int index2 = 0; index2 < length2; ++index2) + { + float weight = weights[index1, index2]; + if ((double)weight > (double)tiny) + valueTupleList.Add((index2, weight)); + } + if (valueTupleList.Count == 0) + { + boneWeights[index1] = new BoneWeight(); + } + else + { + valueTupleList.Sort((Comparison<(int, float)>)((a, b) => b.w.CompareTo(a.w))); + int num1 = Mathf.Min(maxBonesPerVert, valueTupleList.Count); + float num2 = 0.0f; + for (int index3 = 0; index3 < num1; ++index3) + num2 += valueTupleList[index3].Item2; + if ((double)num2 < (double)tiny) + num2 = 1f; + float num3 = 1f / num2; + BoneWeight boneWeight = new BoneWeight(); + for (int index4 = 0; index4 < num1; ++index4) + { + int num4 = valueTupleList[index4].Item1; + float num5 = valueTupleList[index4].Item2 * num3; + switch (index4) + { + case 0: + ((BoneWeight)ref boneWeight).boneIndex0 = num4; + ((BoneWeight)ref boneWeight).weight0 = num5; + break; + case 1: + ((BoneWeight)ref boneWeight).boneIndex1 = num4; + ((BoneWeight)ref boneWeight).weight1 = num5; + break; + case 2: + ((BoneWeight)ref boneWeight).boneIndex2 = num4; + ((BoneWeight)ref boneWeight).weight2 = num5; + break; + case 3: + ((BoneWeight)ref boneWeight).boneIndex3 = num4; + ((BoneWeight)ref boneWeight).weight3 = num5; + break; + } + } + boneWeights[index1] = boneWeight; + } + } + return boneWeights; + } + + private float[,] InpaintApprox( + Vector3[] verts, + int[] triangles, + float[,] weights, + bool[] matched, + List[] adjacency, + int iterations, + float alpha) + { + int length1 = verts.Length; + int length2 = weights.GetLength(1); + float[,] numArray1 = (float[,])weights.Clone(); + float[,] numArray2 = new float[length1, length2]; + for (int index1 = 0; index1 < iterations; ++index1) + { + for (int index2 = 0; index2 < length1; ++index2) + { + if (matched[index2]) + { + for (int index3 = 0; index3 < length2; ++index3) + numArray2[index2, index3] = numArray1[index2, index3]; + } + else + { + List intList = adjacency[index2]; + if (intList == null || intList.Count == 0) + { + for (int index4 = 0; index4 < length2; ++index4) + numArray2[index2, index4] = numArray1[index2, index4]; + } + else + { + for (int index5 = 0; index5 < length2; ++index5) + { + float num1 = 0.0f; + for (int index6 = 0; index6 < intList.Count; ++index6) + { + int index7 = intList[index6]; + num1 += numArray1[index7, index5]; + } + float num2 = num1 / (float)intList.Count; + numArray2[index2, index5] = Mathf.Lerp(numArray1[index2, index5], num2, alpha); + } + } + } + } + float[,] numArray3 = numArray2; + float[,] numArray4 = numArray1; + numArray1 = numArray3; + numArray2 = numArray4; + } + return numArray1; + } + + private float[,] SmoothWeightsApprox( + Vector3[] verts, + float[,] weights, + bool[] matched, + List[] adjacency, + int numSmoothIterSteps, + float smoothAlpha, + float distanceThreshold) + { + int length1 = verts.Length; + int length2 = weights.GetLength(1); + bool[] visited = new bool[length1]; + for (int startIndex = 0; startIndex < length1; ++startIndex) + { + if (!matched[startIndex]) + this.FloodFillWithinDistance(verts, adjacency, startIndex, distanceThreshold, visited); + } + float[,] numArray1 = (float[,])weights.Clone(); + float[,] numArray2 = new float[length1, length2]; + for (int index1 = 0; index1 < numSmoothIterSteps; ++index1) + { + for (int index2 = 0; index2 < length1; ++index2) + { + if (!visited[index2]) + { + for (int index3 = 0; index3 < length2; ++index3) + numArray2[index2, index3] = numArray1[index2, index3]; + } + else + { + List intList = adjacency[index2]; + if (intList == null || intList.Count == 0) + { + for (int index4 = 0; index4 < length2; ++index4) + numArray2[index2, index4] = numArray1[index2, index4]; + } + else + { + for (int index5 = 0; index5 < length2; ++index5) + { + float num1 = 0.0f; + for (int index6 = 0; index6 < intList.Count; ++index6) + { + int index7 = intList[index6]; + num1 += numArray1[index7, index5]; + } + float num2 = num1 / (float)intList.Count; + numArray2[index2, index5] = Mathf.Lerp(numArray1[index2, index5], num2, smoothAlpha); + } + } + } + } + float[,] numArray3 = numArray2; + float[,] numArray4 = numArray1; + numArray1 = numArray3; + numArray2 = numArray4; + } + return numArray1; + } + + private void FloodFillWithinDistance( + Vector3[] verts, + List[] adjacency, + int startIndex, + float maxDistance, + bool[] visited) + { + Queue intQueue = new Queue(); + intQueue.Enqueue(startIndex); + visited[startIndex] = true; + while (intQueue.Count > 0) + { + int index1 = intQueue.Dequeue(); + foreach (int index2 in adjacency[index1]) + { + if (!visited[index2]) + { + Vector3 vector3 = Vector3.op_Subtraction(verts[startIndex], verts[index2]); + if ((double)((Vector3)ref vector3).magnitude < (double)maxDistance) + { + visited[index2] = true; + intQueue.Enqueue(index2); + } + } + } + } + } + + private BoneWeight[] MergeBodyAndAccessoryWeights( + float[,] bodyWeights, + float[,] accessoryWeights, + int bodyBoneCount, + float tiny, + bool enforceFour) + { + int length1 = bodyWeights.GetLength(0); + bodyWeights.GetLength(1); + int length2 = accessoryWeights.GetLength(1); + BoneWeight[] boneWeightArray = new BoneWeight[length1]; + for (int index1 = 0; index1 < length1; ++index1) + { + List<(int, float)> collection1 = new List<(int, float)>(); + float num1 = 0.0f; + for (int index2 = 0; index2 < length2; ++index2) + { + float accessoryWeight = accessoryWeights[index1, index2]; + if ((double)accessoryWeight > (double)tiny) + { + int num2 = bodyBoneCount + index2; + collection1.Add((num2, accessoryWeight)); + num1 += accessoryWeight; + } + } + List<(int, float)> collection2 = new List<(int, float)>(); + float num3 = 0.0f; + for (int index3 = 0; index3 < bodyBoneCount; ++index3) + { + float bodyWeight = bodyWeights[index1, index3]; + if ((double)bodyWeight > (double)tiny) + { + collection2.Add((index3, bodyWeight)); + num3 += bodyWeight; + } + } + float num4; + if ((double)num3 > (double)tiny && (double)num1 < 1.0 - (double)tiny) + { + float num5 = Mathf.Max(0.0f, 1f - num1); + float num6 = num5 / num3; + for (int index4 = 0; index4 < collection2.Count; ++index4) + collection2[index4] = (collection2[index4].Item1, collection2[index4].Item2 * num6); + num4 = num5; + } + else + { + for (int index5 = 0; index5 < collection2.Count; ++index5) + collection2[index5] = (collection2[index5].Item1, 0.0f); + num4 = 0.0f; + } + List<(int, float)> valueTupleList = new List<(int, float)>(); + valueTupleList.AddRange((IEnumerable<(int, float)>)collection1); + valueTupleList.AddRange((IEnumerable<(int, float)>)collection2); + valueTupleList.RemoveAll((Predicate<(int, float)>)(t => (double)t.w <= (double)tiny)); + if (valueTupleList.Count == 0) + { + boneWeightArray[index1] = new BoneWeight(); + } + else + { + if (enforceFour && valueTupleList.Count > 4) + { + valueTupleList.Sort((Comparison<(int, float)>)((a, b) => + { + bool flag1 = a.bone >= bodyBoneCount; + bool flag2 = b.bone >= bodyBoneCount; + if (flag1 == flag2) + return b.w.CompareTo(a.w); + return !flag1 ? 1 : -1; + })); + valueTupleList = valueTupleList.GetRange(0, 4); + } + float num7 = 0.0f; + foreach ((int, float) valueTuple in valueTupleList) + num7 += valueTuple.Item2; + if ((double)num7 < (double)tiny) + num7 = 1f; + float num8 = 1f / num7; + BoneWeight boneWeight = new BoneWeight(); + for (int index6 = 0; index6 < valueTupleList.Count && index6 < 4; ++index6) + { + int num9 = valueTupleList[index6].Item1; + float num10 = valueTupleList[index6].Item2 * num8; + switch (index6) + { + case 0: + ((BoneWeight)ref boneWeight).boneIndex0 = num9; + ((BoneWeight)ref boneWeight).weight0 = num10; + break; + case 1: + ((BoneWeight)ref boneWeight).boneIndex1 = num9; + ((BoneWeight)ref boneWeight).weight1 = num10; + break; + case 2: + ((BoneWeight)ref boneWeight).boneIndex2 = num9; + ((BoneWeight)ref boneWeight).weight2 = num10; + break; + case 3: + ((BoneWeight)ref boneWeight).boneIndex3 = num9; + ((BoneWeight)ref boneWeight).weight3 = num10; + break; + } + } + boneWeightArray[index1] = boneWeight; + } + } + return boneWeightArray; + } + + private void EnsureNonZeroAndNormalizeFinalWeights( + ClothInstance cloth, + BoneWeight[] weights, + List[] adjacency, + float tiny) + { + if (cloth == null || weights == null || weights.Length == 0) + return; + this.PreNormalizeBoneWeightsInPlace(weights, tiny); + this.FillZeroWeightsFromNeighbors(weights, adjacency, tiny); + this.NormalizeAllBoneWeightsInPlace(weights, tiny); + } + + private void PreNormalizeBoneWeightsInPlace(BoneWeight[] weights, float tiny) + { + for (int index = 0; index < weights.Length; ++index) + { + BoneWeight weight = weights[index]; + float num1 = this.Sum(in weights[index]); + if ((double)num1 >= (double)tiny) + { + float num2 = 1f / num1; + ref BoneWeight local1 = ref weight; + ((BoneWeight)ref local1).weight0 = ((BoneWeight)ref local1).weight0 * num2; + ref BoneWeight local2 = ref weight; + ((BoneWeight)ref local2).weight1 = ((BoneWeight)ref local2).weight1 * num2; + ref BoneWeight local3 = ref weight; + ((BoneWeight)ref local3).weight2 = ((BoneWeight)ref local3).weight2 * num2; + ref BoneWeight local4 = ref weight; + ((BoneWeight)ref local4).weight3 = ((BoneWeight)ref local4).weight3 * num2; + weights[index] = weight; + } + } + } + + private void FillZeroWeightsFromNeighbors( + BoneWeight[] weights, + List[] adjacency, + float tiny) + { + int length = weights.Length; + for (int v = 0; v < length; ++v) + { + if ((double)this.Sum(in weights[v]) < (double)tiny) + { + BoneWeight bw = this.AverageFromNeighbors(v, weights, adjacency, tiny, 1); + if ((double)this.Sum(in bw) >= (double)tiny) + weights[v] = bw; + } + } + for (int start = 0; start < length; ++start) + { + if ((double)this.Sum(in weights[start]) < (double)tiny) + { + int nonZeroVertexBfs = this.FindNearestNonZeroVertexBfs(start, weights, adjacency, tiny, 8); + if (nonZeroVertexBfs >= 0) + { + weights[start] = weights[nonZeroVertexBfs]; + } + else + { + BoneWeight boneWeight = new BoneWeight(); + ((BoneWeight)ref boneWeight).boneIndex0 = 0; + ((BoneWeight)ref boneWeight).weight0 = 1f; + weights[start] = boneWeight; + } + } + } + } + + private BoneWeight AverageFromNeighbors( + int v, + BoneWeight[] weights, + List[] adjacency, + float tiny, + int maxRing) + { + Dictionary map = new Dictionary(); + Queue intQueue = new Queue(); + Dictionary dictionary = new Dictionary(); + HashSet intSet = new HashSet(); + intQueue.Enqueue(v); + dictionary[v] = 0; + intSet.Add(v); + while (intQueue.Count > 0) + { + int key1 = intQueue.Dequeue(); + int num = dictionary[key1]; + if (num < maxRing) + { + List intList = adjacency[key1]; + if (intList != null) + { + foreach (int key2 in intList) + { + if (key2 >= 0 && key2 < weights.Length && intSet.Add(key2)) + { + dictionary[key2] = num + 1; + intQueue.Enqueue(key2); + BoneWeight bw = weights[key2]; + if ((double)this.Sum(in bw) >= (double)tiny) + { + this.Acc(map, ((BoneWeight)ref bw).boneIndex0, ((BoneWeight)ref bw).weight0, tiny); + this.Acc(map, ((BoneWeight)ref bw).boneIndex1, ((BoneWeight)ref bw).weight1, tiny); + this.Acc(map, ((BoneWeight)ref bw).boneIndex2, ((BoneWeight)ref bw).weight2, tiny); + this.Acc(map, ((BoneWeight)ref bw).boneIndex3, ((BoneWeight)ref bw).weight3, tiny); + } + } + } + } + } + } + return this.BuildTop4Normalized(map, tiny); + } + + private int FindNearestNonZeroVertexBfs( + int start, + BoneWeight[] weights, + List[] adjacency, + float tiny, + int maxDepth) + { + Queue intQueue = new Queue(); + Dictionary dictionary = new Dictionary(); + HashSet intSet = new HashSet(); + intQueue.Enqueue(start); + dictionary[start] = 0; + intSet.Add(start); + while (intQueue.Count > 0) + { + int key1 = intQueue.Dequeue(); + int num = dictionary[key1]; + if (num > 0 && (double)this.Sum(in weights[key1]) >= (double)tiny) + return key1; + if (num < maxDepth) + { + List intList = adjacency[key1]; + if (intList != null) + { + foreach (int key2 in intList) + { + if (key2 >= 0 && key2 < weights.Length && intSet.Add(key2)) + { + dictionary[key2] = num + 1; + intQueue.Enqueue(key2); + } + } + } + } + } + return -1; + } + + private void NormalizeAllBoneWeightsInPlace(BoneWeight[] weights, float tiny) + { + for (int index = 0; index < weights.Length; ++index) + { + float num1 = this.Sum(in weights[index]); + if ((double)num1 >= (double)tiny) + { + float num2 = 1f / num1; + BoneWeight weight = weights[index]; + ref BoneWeight local1 = ref weight; + ((BoneWeight)ref local1).weight0 = ((BoneWeight)ref local1).weight0 * num2; + ref BoneWeight local2 = ref weight; + ((BoneWeight)ref local2).weight1 = ((BoneWeight)ref local2).weight1 * num2; + ref BoneWeight local3 = ref weight; + ((BoneWeight)ref local3).weight2 = ((BoneWeight)ref local3).weight2 * num2; + ref BoneWeight local4 = ref weight; + ((BoneWeight)ref local4).weight3 = ((BoneWeight)ref local4).weight3 * num2; + weights[index] = weight; + } + } + } + + private float Sum(in BoneWeight bw) + { + BoneWeight boneWeight = bw; + double weight0 = (double)((BoneWeight)ref boneWeight).weight0; + boneWeight = bw; + double weight1 = (double)((BoneWeight)ref boneWeight).weight1; + double num1 = weight0 + weight1; + boneWeight = bw; + double weight2 = (double)((BoneWeight)ref boneWeight).weight2; + double num2 = num1 + weight2; + boneWeight = bw; + double weight3 = (double)((BoneWeight)ref boneWeight).weight3; + return (float)(num2 + weight3); + } + + private void Acc(Dictionary map, int boneIndex, float w, float tiny) + { + if (boneIndex < 0 || (double)w <= (double)tiny) + return; + float num; + if (map.TryGetValue(boneIndex, out num)) + map[boneIndex] = num + w; + else + map[boneIndex] = w; + } + + private BoneWeight BuildTop4Normalized(Dictionary map, float tiny) + { + if (map == null || map.Count == 0) + return new BoneWeight(); + List> list = map.OrderByDescending, float>((Func, float>)(kv => kv.Value)).Take>(4).ToList>(); + float num1 = 0.0f; + for (int index = 0; index < list.Count; ++index) + num1 += list[index].Value; + if ((double)num1 < (double)tiny) + return new BoneWeight(); + float num2 = 1f / num1; + BoneWeight boneWeight = new BoneWeight(); + for (int index = 0; index < list.Count; ++index) + { + KeyValuePair keyValuePair = list[index]; + int key = keyValuePair.Key; + keyValuePair = list[index]; + float num3 = keyValuePair.Value * num2; + switch (index) + { + case 0: + ((BoneWeight)ref boneWeight).boneIndex0 = key; + ((BoneWeight)ref boneWeight).weight0 = num3; + break; + case 1: + ((BoneWeight)ref boneWeight).boneIndex1 = key; + ((BoneWeight)ref boneWeight).weight1 = num3; + break; + case 2: + ((BoneWeight)ref boneWeight).boneIndex2 = key; + ((BoneWeight)ref boneWeight).weight2 = num3; + break; + case 3: + ((BoneWeight)ref boneWeight).boneIndex3 = key; + ((BoneWeight)ref boneWeight).weight3 = num3; + break; + } + } + return boneWeight; + } + + [Serializable] + public class Settings + { + [Header("최근접 표면 매칭")] + public float maxDistance = 0.1f; + public float maxNormalAngleDeg = 35f; + public bool allowFlippedNormal = true; + [Header("추가 스무딩")] + public bool enableSmoothing = true; + public int smoothingIterations = 4; + [Range(0.0f, 1f)] + public float smoothingAlpha = 0.25f; + [Header("본 수 제한 & 임계값")] + public bool enforceFourBoneLimit = true; + public float tinyWeight = 0.0001f; + public bool weightInClothes; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs.meta new file mode 100644 index 0000000..0c61da2 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WeightTransferUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e599bc491f46ff142ba063735375547c \ No newline at end of file diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WorldVertexUtil.cs b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WorldVertexUtil.cs new file mode 100644 index 0000000..1ec1147 --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WorldVertexUtil.cs @@ -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; + } + } +} diff --git a/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WorldVertexUtil.cs.meta b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WorldVertexUtil.cs.meta new file mode 100644 index 0000000..47fc5dc --- /dev/null +++ b/Assets/@Eden_Tools/Eden_AutoMorpher/Script/WorldVertexUtil.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 063c5c8305e754148942a0cca1bb8518 \ No newline at end of file