private void ScoreBoneMatch(BoneMatch match) { int num = this.BoneHasBadKeyword(match.bone, match.item.keywords); match.score += num; if (kDebug && (num != 0)) { match.debugTracker.Add(string.Concat(new object[] { num, ": ", this.GetMatchString(match), " matched bad keywords" })); } if (num >= 0) { int num2 = this.BoneHasKeyword(match.bone, match.item.keywords); match.score += num2; if (kDebug && (num2 != 0)) { match.debugTracker.Add(string.Concat(new object[] { num2, ": ", this.GetMatchString(match), " matched keywords" })); } if ((match.item.keywords.Length == 0) && match.item.alwaysInclude) { match.score++; if (kDebug) { match.debugTracker.Add(string.Concat(new object[] { 1, ": ", this.GetMatchString(match), " always-include point" })); } } } }
private void ScoreBoneMatch(BoneMatch match) { int badKeywordScore = BoneHasBadKeyword(match.bone, match.item.keywords); match.score += badKeywordScore; if (kDebug && badKeywordScore != 0) { match.debugTracker.Add(badKeywordScore + ": " + GetMatchString(match) + " matched bad keywords"); } if (badKeywordScore < 0) { return; } int keywordScore = BoneHasKeyword(match.bone, match.item.keywords); match.score += keywordScore; if (kDebug && keywordScore != 0) { match.debugTracker.Add(keywordScore + ": " + GetMatchString(match) + " matched keywords"); } // If child bone with no required keywords, give a minimal score so it can still be included in mapping if (match.item.keywords.Length == 0 && match.item.alwaysInclude) { match.score += 1; if (kDebug) { match.debugTracker.Add(1 + ": " + GetMatchString(match) + " always-include point"); } } }
private int GetBoneSideMatchPoints(BoneMatch match) { string boneName = match.bone.name; if (match.item.side == Side.None) { if (MatchesSideKeywords(boneName, false) || MatchesSideKeywords(boneName, true)) { return(-1000); } } bool left = (match.item.side == Side.Left); if (MatchesSideKeywords(boneName, left)) { return(15); } if (MatchesSideKeywords(boneName, !left)) { return(-1000); } return(0); }
private void ApplyMapping(BoneMatch match, Dictionary <int, Transform> mapping) { if (match.doMap) { mapping[match.item.bone] = match.bone; } foreach (BoneMatch child in match.children) { ApplyMapping(child, mapping); } }
private void MapBonesFromRootDown(BoneMatch rootMatch, Dictionary <int, Transform> mapping) { List <BoneMatch> list = this.RecursiveFindPotentialBoneMatches(rootMatch, this.m_MappingData[0], true); if ((list != null) && (list.Count > 0)) { if (kDebug) { this.EvaluateBoneMatch(list[0], true); } this.ApplyMapping(list[0], mapping); } }
private void MapBonesFromRootDown(BoneMatch rootMatch, Dictionary <int, Transform> mapping) { // Perform mapping List <BoneMatch> childMatches = RecursiveFindPotentialBoneMatches(rootMatch, m_MappingData[0], true); if (childMatches != null && childMatches.Count > 0) { if (kDebug) { EvaluateBoneMatch(childMatches[0], true); } ApplyMapping(childMatches[0], mapping); } }
private int GetMatchKey(BoneMatch parentMatch, Transform t, BoneMappingItem goalItem) { int num = goalItem.bone + (t.GetInstanceID() * 0x3e8); if (parentMatch != null) { num += parentMatch.bone.GetInstanceID() * 0xf4240; if (parentMatch.parent != null) { num += parentMatch.parent.bone.GetInstanceID() * 0x3b9aca00; } } return(num); }
private int GetMatchKey(BoneMatch parentMatch, Transform t, BoneMappingItem goalItem) { SimpleProfiler.Begin("GetMatchKey"); int key = goalItem.bone; key += t.GetInstanceID() * 1000; if (parentMatch != null) { key += parentMatch.bone.GetInstanceID() * 1000000; if (parentMatch.parent != null) { key += parentMatch.parent.bone.GetInstanceID() * 1000000000; } } SimpleProfiler.End(); return(key); }
private int GetBoneSideMatchPoints(BoneMatch match) { string name = match.bone.name; if ((match.item.side == Side.None) && (this.MatchesSideKeywords(name, false) || this.MatchesSideKeywords(name, true))) { return(-1000); } bool left = match.item.side == Side.Left; if (this.MatchesSideKeywords(name, left)) { return(15); } if (this.MatchesSideKeywords(name, !left)) { return(-1000); } return(0); }
private List <BoneMatch> GetBestChildMatches(BoneMatch parentMatch, List <List <BoneMatch> > childMatchesLists) { float num; List <BoneMatch> list = new List <BoneMatch>(); if (childMatchesLists.Count == 1) { list.Add(childMatchesLists[0][0]); return(list); } int[] choices = new int[childMatchesLists.Count]; choices = this.GetBestChildMatchChoices(parentMatch, childMatchesLists, choices, out num); for (int i = 0; i < choices.Length; i++) { if (choices[i] >= 0) { list.Add(childMatchesLists[i][choices[i]]); } } return(list); }
private List <BoneMatch> GetBestChildMatches(BoneMatch parentMatch, List <List <BoneMatch> > childMatchesLists) { List <BoneMatch> bestMatches = new List <BoneMatch>(); if (childMatchesLists.Count == 1) { bestMatches.Add(childMatchesLists[0][0]); return(bestMatches); } int[] choices = new int[childMatchesLists.Count]; float dummyScore; choices = GetBestChildMatchChoices(parentMatch, childMatchesLists, choices, out dummyScore); for (int i = 0; i < choices.Length; i++) { if (choices[i] >= 0) { bestMatches.Add(childMatchesLists[i][choices[i]]); } } return(bestMatches); }
private int[] GetBestChildMatchChoices(BoneMatch parentMatch, List <List <BoneMatch> > childMatchesLists, int[] choices, out float score) { List <int> list = new List <int>(); for (int i = 0; i < choices.Length; i++) { if (choices[i] >= 0) { list.Clear(); list.Add(i); for (int k = i + 1; k < choices.Length; k++) { if ((choices[k] >= 0) && this.ShareTransformPath(parentMatch.bone, childMatchesLists[i][choices[i]].bone, childMatchesLists[k][choices[k]].bone)) { list.Add(k); } } if (list.Count > 1) { break; } } } if (list.Count <= 1) { score = 0f; for (int m = 0; m < choices.Length; m++) { if (choices[m] >= 0) { score += childMatchesLists[m][choices[m]].totalSiblingScore; } } return(choices); } float num4 = 0f; int[] numArray2 = choices; for (int j = 0; j < list.Count; j++) { float num7; int[] destinationArray = new int[choices.Length]; Array.Copy(choices, destinationArray, choices.Length); for (int n = 0; n < list.Count; n++) { if (j != n) { if (list[n] >= destinationArray.Length) { Debug.LogError(string.Concat(new object[] { "sharedIndices[j] (", list[n], ") >= altChoices.Length (", destinationArray.Length, ")" })); } if (list[n] >= childMatchesLists.Count) { Debug.LogError(string.Concat(new object[] { "sharedIndices[j] (", list[n], ") >= childMatchesLists.Count (", childMatchesLists.Count, ")" })); } if (destinationArray[list[n]] < (childMatchesLists[list[n]].Count - 1)) { destinationArray[list[n]]++; } else { destinationArray[list[n]] = -1; } } } destinationArray = this.GetBestChildMatchChoices(parentMatch, childMatchesLists, destinationArray, out num7); if (num7 > num4) { num4 = num7; numArray2 = destinationArray; } } score = num4; return(numArray2); }
// Returns possible matches sorted with best-scoring ones first in the list private List <BoneMatch> RecursiveFindPotentialBoneMatches(BoneMatch parentMatch, BoneMappingItem goalItem, bool confirmedChoice) { List <BoneMatch> matches = new List <BoneMatch>(); // We want to search with breadh first search so we have to use a queue Queue <QueuedBone> queue = new Queue <QueuedBone>(); // Find matches queue.Enqueue(new QueuedBone(parentMatch.bone, 0)); while (queue.Count > 0) { QueuedBone current = queue.Dequeue(); Transform t = current.bone; if (current.level >= goalItem.minStep && (m_TreatDummyBonesAsReal || m_ValidBones == null || (m_ValidBones.ContainsKey(t) && m_ValidBones[t]))) { BoneMatch match; var key = GetMatchKey(parentMatch, t, goalItem); if (m_BoneMatchDict.ContainsKey(key)) { match = m_BoneMatchDict[key]; } else { match = new BoneMatch(parentMatch, t, goalItem); // RECURSIVE CALL EvaluateBoneMatch(match, false); m_BoneMatchDict[key] = match; } if (match.score > 0 || kDebug) { matches.Add(match); } } SimpleProfiler.Begin("Queue"); if (current.level < goalItem.maxStep) { foreach (Transform child in t) { if (m_ValidBones == null || m_ValidBones.ContainsKey(child)) { if (!m_TreatDummyBonesAsReal && m_ValidBones != null && !m_ValidBones[child]) { queue.Enqueue(new QueuedBone(child, current.level)); } else { queue.Enqueue(new QueuedBone(child, current.level + 1)); } } } } SimpleProfiler.End(); } if (matches.Count == 0) { return(null); } // Sort by match score with best matches first SimpleProfiler.Begin("SortAndTrim"); matches.Sort(); if (matches[0].score <= 0) { return(null); } if (kDebug && confirmedChoice) { DebugMatchChoice(matches); } // Keep top 3 priorities only for optimization while (matches.Count > 3) { matches.RemoveAt(matches.Count - 1); } matches.TrimExcess(); SimpleProfiler.End(); return(matches); }
private string GetMatchString(BoneMatch match) { return(GetNameOfBone(match.item.bone) + ":" + (match.bone == null ? "null" : match.bone.name)); }
private string GetMatchString(BoneMatch match) => (this.GetNameOfBone(match.item.bone) + ":" + ((match.bone != null) ? match.bone.name : "null"));
public Dictionary <int, Transform> MapBones(Transform root) { InitGlobalMappingData(); Dictionary <int, Transform> mapping = new Dictionary <int, Transform>(); this.m_Orientation = Quaternion.identity; this.m_MappingData = s_MappingDataBody; this.m_MappingIndexOffset = 0; this.m_BoneMatchDict.Clear(); BoneMatch rootMatch = new BoneMatch(null, root, this.m_MappingData[0]); this.m_TreatDummyBonesAsReal = false; this.MapBonesFromRootDown(rootMatch, mapping); if (mapping.Count < 15) { this.m_TreatDummyBonesAsReal = true; this.MapBonesFromRootDown(rootMatch, mapping); } if ((mapping.ContainsKey(1) && mapping.ContainsKey(2)) && (mapping.ContainsKey(13) && mapping.ContainsKey(14))) { this.m_Orientation = AvatarSetupTool.AvatarComputeOrientation(mapping[1].position, mapping[2].position, mapping[13].position, mapping[14].position); if ((Vector3.Angle((Vector3)(this.m_Orientation * Vector3.up), Vector3.up) > 20f) || (Vector3.Angle((Vector3)(this.m_Orientation * Vector3.forward), Vector3.forward) > 20f)) { if (kDebug) { Debug.Log("*** Mapping with new computed orientation"); } mapping.Clear(); this.m_BoneMatchDict.Clear(); this.MapBonesFromRootDown(rootMatch, mapping); } } if ((!(!this.m_ValidBones.ContainsKey(root) ? false : this.m_ValidBones[root]) && (mapping.Count > 0)) && mapping.ContainsKey(0)) { while (true) { Transform parent = mapping[0].parent; if (((parent == null) || (parent == rootMatch.bone)) || (!this.m_ValidBones.ContainsKey(parent) || !this.m_ValidBones[parent])) { break; } mapping[0] = parent; } } int num = 3; Quaternion orientation = this.m_Orientation; if (mapping.ContainsKey(0x11)) { Transform bone = mapping[15]; Transform transform3 = mapping[0x11]; this.m_Orientation = Quaternion.FromToRotation((Vector3)(orientation * -Vector3.right), transform3.position - bone.position) * orientation; this.m_MappingData = s_LeftMappingDataHand; this.m_MappingIndexOffset = 0x18; this.m_BoneMatchDict.Clear(); BoneMatch match2 = new BoneMatch(null, bone, this.m_MappingData[0]); this.m_TreatDummyBonesAsReal = true; int count = mapping.Count; this.MapBonesFromRootDown(match2, mapping); if (mapping.Count < (count + num)) { for (int i = 0x18; i <= 0x26; i++) { mapping.Remove(i); } } } if (mapping.ContainsKey(0x12)) { Transform transform4 = mapping[0x10]; Transform transform5 = mapping[0x12]; this.m_Orientation = Quaternion.FromToRotation((Vector3)(orientation * Vector3.right), transform5.position - transform4.position) * orientation; this.m_MappingData = s_RightMappingDataHand; this.m_MappingIndexOffset = 0x27; this.m_BoneMatchDict.Clear(); BoneMatch match3 = new BoneMatch(null, transform4, this.m_MappingData[0]); this.m_TreatDummyBonesAsReal = true; int num4 = mapping.Count; this.MapBonesFromRootDown(match3, mapping); if (mapping.Count >= (num4 + num)) { return(mapping); } for (int j = 0x27; j <= 0x35; j++) { mapping.Remove(j); } } return(mapping); }
private List <BoneMatch> RecursiveFindPotentialBoneMatches(BoneMatch parentMatch, BoneMappingItem goalItem, bool confirmedChoice) { List <BoneMatch> matches = new List <BoneMatch>(); Queue <QueuedBone> queue = new Queue <QueuedBone>(); queue.Enqueue(new QueuedBone(parentMatch.bone, 0)); while (queue.Count > 0) { QueuedBone bone = queue.Dequeue(); Transform key = bone.bone; if ((bone.level >= goalItem.minStep) && ((this.m_TreatDummyBonesAsReal || (this.m_ValidBones == null)) || (this.m_ValidBones.ContainsKey(key) && this.m_ValidBones[key]))) { BoneMatch match; int num = this.GetMatchKey(parentMatch, key, goalItem); if (this.m_BoneMatchDict.ContainsKey(num)) { match = this.m_BoneMatchDict[num]; } else { match = new BoneMatch(parentMatch, key, goalItem); this.EvaluateBoneMatch(match, false); this.m_BoneMatchDict[num] = match; } if ((match.score > 0f) || kDebug) { matches.Add(match); } } if (bone.level < goalItem.maxStep) { IEnumerator enumerator = key.GetEnumerator(); try { while (enumerator.MoveNext()) { Transform current = (Transform)enumerator.Current; if ((this.m_ValidBones == null) || this.m_ValidBones.ContainsKey(current)) { if ((!this.m_TreatDummyBonesAsReal && (this.m_ValidBones != null)) && !this.m_ValidBones[current]) { queue.Enqueue(new QueuedBone(current, bone.level)); } else { queue.Enqueue(new QueuedBone(current, bone.level + 1)); } } } } finally { IDisposable disposable = enumerator as IDisposable; if (disposable != null) { disposable.Dispose(); } } } } if (matches.Count == 0) { return(null); } matches.Sort(); if (matches[0].score <= 0f) { return(null); } if (kDebug && confirmedChoice) { this.DebugMatchChoice(matches); } while (matches.Count > 3) { matches.RemoveAt(matches.Count - 1); } matches.TrimExcess(); return(matches); }
private int[] GetBestChildMatchChoices(BoneMatch parentMatch, List <List <BoneMatch> > childMatchesLists, int[] choices, out float score) { // See if any choices share the same transform path. List <int> sharedIndices = new List <int>(); for (int i = 0; i < choices.Length; i++) { if (choices[i] < 0) { continue; } sharedIndices.Clear(); sharedIndices.Add(i); for (int j = i + 1; j < choices.Length; j++) { if (choices[j] < 0) { continue; } if (ShareTransformPath(parentMatch.bone, childMatchesLists[i][choices[i]].bone, childMatchesLists[j][choices[j]].bone)) { sharedIndices.Add(j); } } if (sharedIndices.Count > 1) { break; } } if (sharedIndices.Count <= 1) { // If no shared transform paths, calculate score and return choices. score = 0; for (int i = 0; i < choices.Length; i++) { if (choices[i] >= 0) { score += childMatchesLists[i][choices[i]].totalSiblingScore; } } return(choices); } else { // If transform paths are shared by multiple choices, call function recursively. float bestScore = 0; int[] bestChoices = choices; for (int i = 0; i < sharedIndices.Count; i++) { int[] altChoices = new int[choices.Length]; Array.Copy(choices, altChoices, choices.Length); // In each call, one of the choices retains their priority while the remaining are bumped one priority down. for (int j = 0; j < sharedIndices.Count; j++) { if (i != j) { if (sharedIndices[j] >= altChoices.Length) { Debug.LogError("sharedIndices[j] (" + sharedIndices[j] + ") >= altChoices.Length (" + altChoices.Length + ")"); } if (sharedIndices[j] >= childMatchesLists.Count) { Debug.LogError("sharedIndices[j] (" + sharedIndices[j] + ") >= childMatchesLists.Count (" + childMatchesLists.Count + ")"); } if (altChoices[sharedIndices[j]] < childMatchesLists[sharedIndices[j]].Count - 1) { altChoices[sharedIndices[j]]++; } else { altChoices[sharedIndices[j]] = -1; } } } float altScore; altChoices = GetBestChildMatchChoices(parentMatch, childMatchesLists, altChoices, out altScore); if (altScore > bestScore) { bestScore = altScore; bestChoices = altChoices; } } // Return the choices with the best score score = bestScore; return(bestChoices); } }
public Dictionary <int, Transform> MapBones(Transform root) { InitGlobalMappingData(); Dictionary <int, Transform> mapping = new Dictionary <int, Transform>(); // Perform body mapping { m_Orientation = Quaternion.identity; m_MappingData = s_MappingDataBody; m_MappingIndexOffset = 0; m_BoneMatchDict.Clear(); BoneMatch rootMatch = new BoneMatch(null, root, m_MappingData[0]); m_TreatDummyBonesAsReal = false; MapBonesFromRootDown(rootMatch, mapping); // There are 15 required bones. If we mapped less than that, check if we can do better. if (mapping.Count < 15) { m_TreatDummyBonesAsReal = true; MapBonesFromRootDown(rootMatch, mapping); } // Check if character has correct alignment if (mapping.ContainsKey((int)HumanBodyBones.LeftUpperLeg) && mapping.ContainsKey((int)HumanBodyBones.RightUpperLeg) && mapping.ContainsKey((int)HumanBodyBones.LeftUpperArm) && mapping.ContainsKey((int)HumanBodyBones.RightUpperArm)) { m_Orientation = AvatarSetupTool.AvatarComputeOrientation( mapping[(int)HumanBodyBones.LeftUpperLeg].position, mapping[(int)HumanBodyBones.RightUpperLeg].position, mapping[(int)HumanBodyBones.LeftUpperArm].position, mapping[(int)HumanBodyBones.RightUpperArm].position); // If not standard aligned, try to map again with correct alignment assumptions if (Vector3.Angle(m_Orientation * Vector3.up, Vector3.up) > 20 || Vector3.Angle(m_Orientation * Vector3.forward, Vector3.forward) > 20) { if (kDebug) { Debug.Log("*** Mapping with new computed orientation"); } mapping.Clear(); m_BoneMatchDict.Clear(); MapBonesFromRootDown(rootMatch, mapping); } } // For models that don't have meshes, all bones are marked valid; even the root. // So we use this to check if this model has meshes or not. bool modelHasMeshes = !(m_ValidBones.ContainsKey(root) && m_ValidBones[root] == true); // Fix up hips to be valid bone closest to the root // For models with meshes, valid bones further up are mapped to part of the mesh (otherwise they wouldn't be valid). // For models with no meshes we don't know which transforms are valid bones and which aren't // so we skip this step and use the found hips bone as-is. if (modelHasMeshes && mapping.Count > 0 && mapping.ContainsKey((int)HumanBodyBones.Hips)) { while (true) { Transform parent = mapping[(int)HumanBodyBones.Hips].parent; if (parent != null && parent != rootMatch.bone && m_ValidBones.ContainsKey(parent) && m_ValidBones[parent] == true) { mapping[(int)HumanBodyBones.Hips] = parent; } else { break; } } } // Move upper chest to chest if no chest was found if (!mapping.ContainsKey((int)HumanBodyBones.Chest) && mapping.ContainsKey((int)HumanBodyBones.UpperChest)) { mapping.Add((int)HumanBodyBones.Chest, mapping[(int)HumanBodyBones.UpperChest]); mapping.Remove((int)HumanBodyBones.UpperChest); } } int kMinFingerBones = 3; Quaternion bodyOrientation = m_Orientation; // Perform left hand mapping if (mapping.ContainsKey((int)HumanBodyBones.LeftHand)) { Transform lowerArm = mapping[(int)HumanBodyBones.LeftLowerArm]; Transform hand = mapping[(int)HumanBodyBones.LeftHand]; // Use reference orientation based on lower arm for mapping hand m_Orientation = Quaternion.FromToRotation(bodyOrientation * -Vector3.right, hand.position - lowerArm.position) * bodyOrientation; m_MappingData = s_LeftMappingDataHand; m_MappingIndexOffset = (int)HumanBodyBones.LeftThumbProximal; m_BoneMatchDict.Clear(); BoneMatch rootMatch = new BoneMatch(null, lowerArm, m_MappingData[0]); m_TreatDummyBonesAsReal = true; int mappingCountBefore = mapping.Count; MapBonesFromRootDown(rootMatch, mapping); // If we only mapped 2 finger bones or less, then cancel mapping of fingers if (mapping.Count < mappingCountBefore + kMinFingerBones) { for (int i = (int)HumanBodyBones.LeftThumbProximal; i <= (int)HumanBodyBones.LeftLittleDistal; i++) { mapping.Remove(i); } } } // Perform right hand mapping if (mapping.ContainsKey((int)HumanBodyBones.RightHand)) { Transform lowerArm = mapping[(int)HumanBodyBones.RightLowerArm]; Transform hand = mapping[(int)HumanBodyBones.RightHand]; // Use reference orientation based on lower arm for mapping hand m_Orientation = Quaternion.FromToRotation(bodyOrientation * Vector3.right, hand.position - lowerArm.position) * bodyOrientation; m_MappingData = s_RightMappingDataHand; m_MappingIndexOffset = (int)HumanBodyBones.RightThumbProximal; m_BoneMatchDict.Clear(); BoneMatch rootMatch = new BoneMatch(null, lowerArm, m_MappingData[0]); m_TreatDummyBonesAsReal = true; int mappingCountBefore = mapping.Count; MapBonesFromRootDown(rootMatch, mapping); // If we only mapped 2 finger bones or less, then cancel mapping of fingers if (mapping.Count < mappingCountBefore + kMinFingerBones) { for (int i = (int)HumanBodyBones.RightThumbProximal; i <= (int)HumanBodyBones.RightLittleDistal; i++) { mapping.Remove(i); } } } return(mapping); }
private void EvaluateBoneMatch(BoneMatch match, bool confirmedChoice) { match.score = 0; match.siblingScore = 0; // Things to copy from identical match: score, siblingScore, children, doMap // Iterate child BoneMappingitems List <List <BoneMatch> > childMatchesLists = new List <List <BoneMatch> >(); int intendedChildCount = 0; foreach (int c in match.item.GetChildren(m_MappingData)) { BoneMappingItem i = m_MappingData[c]; if (i.parent == match.item.bone) { intendedChildCount++; // RECURSIVE CALL List <BoneMatch> childMatches = RecursiveFindPotentialBoneMatches(match, i, confirmedChoice); if (childMatches == null || childMatches.Count == 0) { continue; } childMatchesLists.Add(childMatches); } } // Best best child matches bool sameAsParentOrChild = (match.bone == match.humanBoneParent.bone); if (childMatchesLists.Count > 0) { SimpleProfiler.Begin("GetBestChildMatches"); match.children = GetBestChildMatches(match, childMatchesLists); SimpleProfiler.End(); // Handle child matches foreach (BoneMatch childMatch in match.children) { // RECURSIVE CALL for debugging purposes if (kDebug && confirmedChoice) { EvaluateBoneMatch(childMatch, confirmedChoice); } // Transfer info from best child match to parent match.score += childMatch.score; if (kDebug) { match.debugTracker.AddRange(childMatch.debugTracker); } if (childMatch.bone == match.bone && childMatch.item.bone >= 0) { sameAsParentOrChild = true; } } } SimpleProfiler.Begin("ScoreBoneMatch"); // Keyword score the bone if it's not optional or if it's different from both parent bone and all child bones if (!match.item.optional || !sameAsParentOrChild) { ScoreBoneMatch(match); } SimpleProfiler.End(); // Rate bone according to how well it matches goal direction SimpleProfiler.Begin("MatchesDir"); if (match.item.dir != Vector3.zero) { Vector3 goalDir = match.item.dir; if (m_MappingIndexOffset >= (int)HumanBodyBones.LeftThumbProximal && m_MappingIndexOffset < (int)HumanBodyBones.RightThumbProximal) { goalDir.x *= -1; } Vector3 dir = (match.bone.position - match.humanBoneParent.bone.position).normalized; dir = Quaternion.Inverse(m_Orientation) * dir; float dirMatchingScore = Vector3.Dot(dir, goalDir) * (match.item.optional ? 5 : 10); match.siblingScore += dirMatchingScore; if (kDebug) { match.debugTracker.Add("* " + dirMatchingScore + ": " + GetMatchString(match) + " matched dir (" + (match.bone.position - match.humanBoneParent.bone.position).normalized + " , " + goalDir + ")"); } if (dirMatchingScore > 0) { match.score += 10; if (kDebug) { match.debugTracker.Add(10 + ": " + GetMatchString(match) + " matched dir (" + (match.bone.position - match.humanBoneParent.bone.position).normalized + " , " + goalDir + ")"); } } } SimpleProfiler.End(); // Give small score if bone matches side it belongs to. SimpleProfiler.Begin("MatchesSide"); if (m_MappingIndexOffset == 0) { int sideMatchingScore = GetBoneSideMatchPoints(match); if (match.parent.item.side == Side.None || sideMatchingScore < 0) { match.siblingScore += sideMatchingScore; if (kDebug) { match.debugTracker.Add("* " + sideMatchingScore + ": " + GetMatchString(match) + " matched side"); } } } SimpleProfiler.End(); // These criteria can not push a bone above the threshold, but they can help to break ties. if (match.score > 0) { // Reward optional bones being included if (match.item.optional && !sameAsParentOrChild) { match.score += 5; if (kDebug) { match.debugTracker.Add(5 + ": " + GetMatchString(match) + " optional bone is included"); } } // Handle end bones if (intendedChildCount == 0 && match.bone.childCount > 0) { // Reward end bones having a dummy child transform match.score += 1; if (kDebug) { match.debugTracker.Add(1 + ": " + GetMatchString(match) + " has dummy child bone"); } } // Give score to bones length ratio according to match with goal ratio. SimpleProfiler.Begin("LengthRatio"); if (match.item.lengthRatio != 0) { float parentLength = Vector3.Distance(match.bone.position, match.humanBoneParent.bone.position); if (parentLength == 0 && match.bone != match.humanBoneParent.bone) { match.score -= 1000; if (kDebug) { match.debugTracker.Add((-1000) + ": " + GetMatchString(match.humanBoneParent) + " has zero length"); } } float grandParentLength = Vector3.Distance(match.humanBoneParent.bone.position, match.humanBoneParent.humanBoneParent.bone.position); if (grandParentLength > 0) { float logRatio = Mathf.Log(parentLength / grandParentLength, 2); float logGoalRatio = Mathf.Log(match.item.lengthRatio, 2); float ratioScore = 10 * Mathf.Clamp(1 - 0.6f * Mathf.Abs(logRatio - logGoalRatio), 0, 1); match.score += ratioScore; if (kDebug) { match.debugTracker.Add(ratioScore + ": parent " + GetMatchString(match.humanBoneParent) + " matched lengthRatio - " + parentLength + " / " + grandParentLength + " = " + (parentLength / grandParentLength) + " (" + logRatio + ") goal: " + match.item.lengthRatio + " (" + logGoalRatio + ")"); } } } SimpleProfiler.End(); } // Only map optional bones if they're not the same as the parent or child. if (match.item.bone >= 0 && (!match.item.optional || !sameAsParentOrChild)) { match.doMap = true; } }
private void EvaluateBoneMatch(BoneMatch match, bool confirmedChoice) { match.score = 0f; match.siblingScore = 0f; List <List <BoneMatch> > childMatchesLists = new List <List <BoneMatch> >(); int num = 0; foreach (int num2 in match.item.GetChildren(this.m_MappingData)) { BoneMappingItem goalItem = this.m_MappingData[num2]; if (goalItem.parent == match.item.bone) { num++; List <BoneMatch> item = this.RecursiveFindPotentialBoneMatches(match, goalItem, confirmedChoice); if ((item != null) && (item.Count != 0)) { childMatchesLists.Add(item); } } } bool flag = match.bone == match.humanBoneParent.bone; int num4 = 0; if (childMatchesLists.Count > 0) { match.children = this.GetBestChildMatches(match, childMatchesLists); foreach (BoneMatch match2 in match.children) { if (kDebug && confirmedChoice) { this.EvaluateBoneMatch(match2, confirmedChoice); } num4++; match.score += match2.score; if (kDebug) { match.debugTracker.AddRange(match2.debugTracker); } if ((match2.bone == match.bone) && (match2.item.bone >= 0)) { flag = true; } } } if (!match.item.optional || !flag) { this.ScoreBoneMatch(match); } if (match.item.dir != Vector3.zero) { Vector3 dir = match.item.dir; if ((this.m_MappingIndexOffset >= 0x18) && (this.m_MappingIndexOffset < 0x27)) { dir.x *= -1f; } Vector3 vector3 = match.bone.position - match.humanBoneParent.bone.position; Vector3 normalized = vector3.normalized; normalized = (Vector3)(Quaternion.Inverse(this.m_Orientation) * normalized); float num5 = Vector3.Dot(normalized, dir) * (!match.item.optional ? ((float)10) : ((float)5)); match.siblingScore += num5; if (kDebug) { object[] objArray1 = new object[9]; objArray1[0] = "* "; objArray1[1] = num5; objArray1[2] = ": "; objArray1[3] = this.GetMatchString(match); objArray1[4] = " matched dir ("; Vector3 vector4 = match.bone.position - match.humanBoneParent.bone.position; objArray1[5] = vector4.normalized; objArray1[6] = " , "; objArray1[7] = dir; objArray1[8] = ")"; match.debugTracker.Add(string.Concat(objArray1)); } if (num5 > 0f) { match.score += 10f; if (kDebug) { object[] objArray2 = new object[8]; objArray2[0] = 10; objArray2[1] = ": "; objArray2[2] = this.GetMatchString(match); objArray2[3] = " matched dir ("; Vector3 vector5 = match.bone.position - match.humanBoneParent.bone.position; objArray2[4] = vector5.normalized; objArray2[5] = " , "; objArray2[6] = dir; objArray2[7] = ")"; match.debugTracker.Add(string.Concat(objArray2)); } } } if (this.m_MappingIndexOffset == 0) { int boneSideMatchPoints = this.GetBoneSideMatchPoints(match); if ((match.parent.item.side == Side.None) || (boneSideMatchPoints < 0)) { match.siblingScore += boneSideMatchPoints; if (kDebug) { match.debugTracker.Add(string.Concat(new object[] { "* ", boneSideMatchPoints, ": ", this.GetMatchString(match), " matched side" })); } } } if (match.score > 0f) { if (match.item.optional && !flag) { match.score += 5f; if (kDebug) { match.debugTracker.Add(string.Concat(new object[] { 5, ": ", this.GetMatchString(match), " optional bone is included" })); } } if ((num == 0) && (match.bone.childCount > 0)) { match.score++; if (kDebug) { match.debugTracker.Add(string.Concat(new object[] { 1, ": ", this.GetMatchString(match), " has dummy child bone" })); } } if (match.item.lengthRatio != 0f) { float num7 = Vector3.Distance(match.bone.position, match.humanBoneParent.bone.position); if ((num7 == 0f) && (match.bone != match.humanBoneParent.bone)) { match.score -= 1000f; if (kDebug) { match.debugTracker.Add(string.Concat(new object[] { -1000, ": ", this.GetMatchString(match.humanBoneParent), " has zero length" })); } } float num8 = Vector3.Distance(match.humanBoneParent.bone.position, match.humanBoneParent.humanBoneParent.bone.position); if (num8 > 0f) { float num9 = Mathf.Log(num7 / num8, 2f); float num10 = Mathf.Log(match.item.lengthRatio, 2f); float num11 = 10f * Mathf.Clamp((float)(1f - (0.6f * Mathf.Abs((float)(num9 - num10)))), (float)0f, (float)1f); match.score += num11; if (kDebug) { match.debugTracker.Add(string.Concat(new object[] { num11, ": parent ", this.GetMatchString(match.humanBoneParent), " matched lengthRatio - ", num7, " / ", num8, " = ", num7 / num8, " (", num9, ") goal: ", match.item.lengthRatio, " (", num10, ")" })); } } } } if ((match.item.bone >= 0) && (!match.item.optional || !flag)) { match.doMap = true; } }