// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts, // for ex. property getter/setter access. To get optimal decompilation results, please manually add the missing references to the list of loaded assemblies. // EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // Eden.AutoMorpher.MeshClassifier using System; using System.Collections.Generic; using Eden.AutoMorpher; using UnityEngine; public class MeshClassifier { private HumanBodyBones[] bodyBones = new HumanBodyBones[28] { HumanBodyBones.Hips, HumanBodyBones.Spine, HumanBodyBones.Chest, HumanBodyBones.Neck, HumanBodyBones.LeftShoulder, HumanBodyBones.LeftUpperArm, HumanBodyBones.LeftLowerArm, HumanBodyBones.LeftHand, HumanBodyBones.LeftThumbProximal, HumanBodyBones.LeftIndexProximal, HumanBodyBones.LeftMiddleProximal, HumanBodyBones.LeftRingProximal, HumanBodyBones.LeftLittleProximal, HumanBodyBones.RightShoulder, HumanBodyBones.RightUpperArm, HumanBodyBones.RightLowerArm, HumanBodyBones.RightHand, HumanBodyBones.RightThumbProximal, HumanBodyBones.RightIndexProximal, HumanBodyBones.RightMiddleProximal, HumanBodyBones.RightRingProximal, HumanBodyBones.RightLittleProximal, HumanBodyBones.LeftUpperLeg, HumanBodyBones.LeftLowerLeg, HumanBodyBones.LeftFoot, HumanBodyBones.RightUpperLeg, HumanBodyBones.RightLowerLeg, HumanBodyBones.RightFoot }; private HumanBodyBones[] headBones = new HumanBodyBones[3] { HumanBodyBones.Head, HumanBodyBones.LeftEye, HumanBodyBones.RightEye }; public SkinnedMeshRenderer GetBodyMesh(Transform root, Animator animator) { List list = HumanBodyBonesTrsnforms(bodyBones, animator); if (list.Count != bodyBones.Length) { if (AutoMorpherDev.isDeveloperMode) { Debug.LogWarning("[Body Mesh] Animator Bone is not enough"); } return null; } return GetBoneMatchedMesh(root, list); } public SkinnedMeshRenderer GetHeadMesh(Transform root, Animator animator) { List list = HumanBodyBonesTrsnforms(headBones, animator); if (list.Count != headBones.Length) { return null; } return GetBoneMatchedMesh(root, list); } private List HumanBodyBonesTrsnforms(HumanBodyBones[] humanBonesList, Animator animator) { List list = new List(); List list2 = new List(); foreach (HumanBodyBones humanBodyBones in humanBonesList) { Transform boneTransform = animator.GetBoneTransform(humanBodyBones); if (boneTransform == null) { list2.Add(humanBodyBones); } else { list.Add(boneTransform); } } if (list2.Count > 0) { string text = string.Join(", ", list2); throw new AutoMorpherException("[Body Mesh Finding] Required Humanoid Bones are Missing", "[BodyMeshUtil] HumanBodyBonesTrsnforms\n - Missing Humanoid Bones: [" + text + "]\n - Animator Humanoid mapping may be broken\n - Please check whether the missing humanoid bones are correctly assigned in [Animator → Avatar → Configure]."); } return list; } private SkinnedMeshRenderer GetBoneMatchedMesh(Transform root, List humanBoneTransforms) { SkinnedMeshRenderer[] componentsInChildren = root.GetComponentsInChildren(includeInactive: false); foreach (SkinnedMeshRenderer skinnedMeshRenderer in componentsInChildren) { bool flag = true; HashSet activeBones = GetActiveBones(skinnedMeshRenderer); if (AutoMorpherDev.isDeveloperMode) { Debug.Log($"[Body Mesh] {skinnedMeshRenderer.gameObject.name} have bone Set {activeBones.Count}"); } foreach (Transform humanBoneTransform in humanBoneTransforms) { if (!activeBones.Contains(humanBoneTransform) && !BoneExistsByPosition(humanBoneTransform, activeBones)) { flag = false; if (AutoMorpherDev.isDeveloperMode) { Debug.Log("[Body Mesh] " + skinnedMeshRenderer.gameObject.name + " Doesn't hav bone " + humanBoneTransform.name); } break; } } if (flag) { return skinnedMeshRenderer; } } return null; } private bool BoneExistsByPosition(Transform boneToCheck, HashSet smrBoneSet, float posTolerance = 0.0001f) { foreach (Transform item in smrBoneSet) { if ((item.position - boneToCheck.position).sqrMagnitude <= posTolerance * posTolerance) { return true; } } return false; } public HashSet GetActiveBones(SkinnedMeshRenderer smr, float weightThreshold = 0.0001f) { Mesh sharedMesh = smr.sharedMesh; if (sharedMesh == null) { Debug.LogWarning("SkinnedMeshRenderer에 연결된 Mesh가 없습니다."); return new HashSet(); } Transform[] bones = smr.bones; BoneWeight[] boneWeights = sharedMesh.boneWeights; HashSet hashSet = new HashSet(); BoneWeight[] array = boneWeights; for (int i = 0; i < array.Length; i++) { BoneWeight boneWeight = array[i]; if (boneWeight.weight0 > weightThreshold) { hashSet.Add(boneWeight.boneIndex0); } if (boneWeight.weight1 > weightThreshold) { hashSet.Add(boneWeight.boneIndex1); } if (boneWeight.weight2 > weightThreshold) { hashSet.Add(boneWeight.boneIndex2); } if (boneWeight.weight3 > weightThreshold) { hashSet.Add(boneWeight.boneIndex3); } } HashSet hashSet2 = new HashSet(); foreach (int item in hashSet) { if (item >= 0 && item < bones.Length) { hashSet2.Add(bones[item]); } } return hashSet2; } public Dictionary> MeshHumanoidBoneMatcher(Animator animator, IReadOnlyList bodyMeshes, float posTolerance = 0.0001f, float weightThreshold = 0.0001f) { Dictionary> dictionary = new Dictionary>(); if (animator == null) { throw new AutoMorpherException("Animator is Missing", "[MeshHumanoidBoneMatcher] MeshHumanoidBoneMatcher\n - animator is null"); } HashSet hashSet = new HashSet(); if (bodyMeshes != null) { foreach (SkinnedMeshRenderer bodyMesh in bodyMeshes) { if (bodyMesh == null) { continue; } foreach (Transform activeBone in GetActiveBones(bodyMesh, weightThreshold)) { if (activeBone != null) { hashSet.Add(activeBone); } } } } for (int i = 0; i < 55; i++) { HumanBodyBones humanBodyBones = (HumanBodyBones)i; Transform boneTransform = animator.GetBoneTransform(humanBodyBones); if (boneTransform == null) { continue; } HashSet hashSet2 = new HashSet(); hashSet2.Add(boneTransform); foreach (Transform item in FindBonesByPosition(boneTransform, hashSet, posTolerance)) { hashSet2.Add(item); } dictionary[humanBodyBones] = hashSet2; } return dictionary; } private List FindBonesByPosition(Transform boneToCheck, HashSet smrBoneSet, float posTolerance = 0.0001f) { List list = new List(); if (boneToCheck == null) { return list; } float num = posTolerance * posTolerance; Vector3 position = boneToCheck.position; foreach (Transform item in smrBoneSet) { if (!(item == null) && !(item == boneToCheck) && NameMatches(item.gameObject.name, boneToCheck.gameObject.name) && (item.position - position).sqrMagnitude <= num) { list.Add(item); } } return list; } 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[] array = TokenizeBoneName(boneToCheckName); string[] array2 = TokenizeBoneName(candidateName); if (array.Length == 0 || array2.Length == 0) { return false; } if (!array[0].Equals(array2[0], StringComparison.OrdinalIgnoreCase)) { return false; } if (array.Length > 1 && array2.Length > 1 && !array[1].Equals(array2[1], StringComparison.OrdinalIgnoreCase)) { return false; } return true; } }