// 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; } } }