public static void InitGlobalMappingData() { if (!s_DidPerformInit) { List <BoneMappingItem> list = new List <BoneMappingItem>(s_MappingDataBody); int count = list.Count; for (int i = 0; i < count; i++) { BoneMappingItem item = list[i]; if (item.side == Side.Right) { int leftBoneIndexFromRight = GetLeftBoneIndexFromRight(item.bone); int parent = GetLeftBoneIndexFromRight(item.parent); list.Add(new BoneMappingItem(parent, leftBoneIndexFromRight, item.minStep, item.maxStep, item.lengthRatio, new Vector3(-item.dir.x, item.dir.y, item.dir.z), Side.Left, item.optional, item.alwaysInclude, item.keywords)); } } s_MappingDataBody = list.ToArray(); for (int j = 0; j < s_MappingDataBody.Length; j++) { s_MappingDataBody[j].GetChildren(s_MappingDataBody); } for (int k = 0; k < s_LeftMappingDataHand.Length; k++) { s_LeftMappingDataHand[k].GetChildren(s_LeftMappingDataHand); } for (int m = 0; m < s_RightMappingDataHand.Length; m++) { s_RightMappingDataHand[m].GetChildren(s_RightMappingDataHand); } s_DidPerformInit = true; } }
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); }
public static void InitGlobalMappingData() { if (s_DidPerformInit) { return; } List <BoneMappingItem> mappingData = new List <BoneMappingItem>(s_MappingDataBody); // Add left side bones to match right side ones. int size = mappingData.Count; for (int i = 0; i < size; i++) { BoneMappingItem item = mappingData[i]; if (item.side == Side.Right) { // Get left HumanBodyBones that mirrors right one. int bone = GetLeftBoneIndexFromRight(item.bone); // Get left parent HumanBodyBones that mirrors parent of right one int parentBone = GetLeftBoneIndexFromRight(item.parent); // Add left BoneMappingItem that mirrors right one. mappingData.Add(new BoneMappingItem(parentBone, bone, item.minStep, item.maxStep, item.lengthRatio, new Vector3(-item.dir.x, item.dir.y, item.dir.z), Side.Left, item.optional, item.alwaysInclude, item.keywords)); } } s_MappingDataBody = mappingData.ToArray(); // Cache children for each BoneMappingItem for (int i = 0; i < s_MappingDataBody.Length; i++) { s_MappingDataBody[i].GetChildren(s_MappingDataBody); } for (int i = 0; i < s_LeftMappingDataHand.Length; i++) { s_LeftMappingDataHand[i].GetChildren(s_LeftMappingDataHand); } for (int i = 0; i < s_RightMappingDataHand.Length; i++) { s_RightMappingDataHand[i].GetChildren(s_RightMappingDataHand); } s_DidPerformInit = true; }
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; } }
// 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); }
public BoneMatch(BoneMatch parent, Transform bone, BoneMappingItem item) { this.parent = parent; this.bone = bone; this.item = item; }
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 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; } }