Skip to content

Commit 7beeb41

Browse files
Andrew Kimfacebook-github-bot
authored andcommitted
fix(Runtime): Optimize performance of retargeting
Summary: Optimize the performance of retargeting by reducing the usage of dictionaries, caching data, removing processors, and skipping the fixed update on retargeting layer. Reviewed By: sohailshafiiWk Differential Revision: D56087086 fbshipit-source-id: 113d361c826480c3df6130556b5a3afdcad6ffbc
1 parent c1ba908 commit 7beeb41

File tree

8 files changed

+151
-41
lines changed

8 files changed

+151
-41
lines changed

Runtime/Scripts/AnimationRigging/BoneMappingsExtension.cs

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Meta Platforms, Inc. and affiliates.
2-
3-
using System.Collections.Generic;
4-
using UnityEngine;
2+
3+
using System.Collections.Generic;
4+
using UnityEngine;
55

66
namespace Oculus.Movement.AnimationRigging
77
{
@@ -84,6 +84,68 @@ public static readonly Dictionary<HumanBodyBones, AvatarMaskBodyPart>
8484
{ HumanBodyBones.RightLittleDistal, AvatarMaskBodyPart.RightArm }
8585
};
8686

87+
/// <summary>
88+
/// Maps HumanBodyBones to avatar mask body part. Includes legs as well.
89+
/// </summary>
90+
public static readonly AvatarMaskBodyPart[] HumanBoneToAvatarBodyPartArray = new AvatarMaskBodyPart[]
91+
{
92+
AvatarMaskBodyPart.Body, // Hips
93+
AvatarMaskBodyPart.LeftLeg, // LeftUpperLeg
94+
AvatarMaskBodyPart.RightLeg, // RightUpperLeg
95+
AvatarMaskBodyPart.LeftLeg, // LeftLowerLeg
96+
AvatarMaskBodyPart.RightLeg, // RightLowerLeg
97+
AvatarMaskBodyPart.LeftLeg, // LeftFoot
98+
AvatarMaskBodyPart.RightLeg, // RightFoot
99+
AvatarMaskBodyPart.Body, // Spine
100+
AvatarMaskBodyPart.Body, // Chest
101+
AvatarMaskBodyPart.Head, // Neck
102+
AvatarMaskBodyPart.Head, // Head
103+
AvatarMaskBodyPart.LeftArm, // LeftShoulder
104+
AvatarMaskBodyPart.RightArm, // RightShoulder
105+
AvatarMaskBodyPart.LeftArm, // LeftUpperArm
106+
AvatarMaskBodyPart.RightArm, // RightUpperArm
107+
AvatarMaskBodyPart.LeftArm, // LeftLowerArm
108+
AvatarMaskBodyPart.RightArm, // RightLowerArm
109+
AvatarMaskBodyPart.LeftArm, // LeftHand
110+
AvatarMaskBodyPart.RightArm, // RightHand
111+
AvatarMaskBodyPart.LeftLeg, // LeftToes
112+
AvatarMaskBodyPart.RightLeg, // RightToes
113+
AvatarMaskBodyPart.Head, // LeftEye
114+
AvatarMaskBodyPart.Head, // RightEye
115+
AvatarMaskBodyPart.Head, // Jaw
116+
AvatarMaskBodyPart.LeftArm, // Left Hand Fingers
117+
AvatarMaskBodyPart.LeftArm,
118+
AvatarMaskBodyPart.LeftArm,
119+
AvatarMaskBodyPart.LeftArm,
120+
AvatarMaskBodyPart.LeftArm,
121+
AvatarMaskBodyPart.LeftArm,
122+
AvatarMaskBodyPart.LeftArm,
123+
AvatarMaskBodyPart.LeftArm,
124+
AvatarMaskBodyPart.LeftArm,
125+
AvatarMaskBodyPart.LeftArm,
126+
AvatarMaskBodyPart.LeftArm,
127+
AvatarMaskBodyPart.LeftArm,
128+
AvatarMaskBodyPart.LeftArm,
129+
AvatarMaskBodyPart.LeftArm,
130+
AvatarMaskBodyPart.LeftArm,
131+
AvatarMaskBodyPart.RightArm, // Right Hand Fingers
132+
AvatarMaskBodyPart.RightArm,
133+
AvatarMaskBodyPart.RightArm,
134+
AvatarMaskBodyPart.RightArm,
135+
AvatarMaskBodyPart.RightArm,
136+
AvatarMaskBodyPart.RightArm,
137+
AvatarMaskBodyPart.RightArm,
138+
AvatarMaskBodyPart.RightArm,
139+
AvatarMaskBodyPart.RightArm,
140+
AvatarMaskBodyPart.RightArm,
141+
AvatarMaskBodyPart.RightArm,
142+
AvatarMaskBodyPart.RightArm,
143+
AvatarMaskBodyPart.RightArm,
144+
AvatarMaskBodyPart.RightArm,
145+
AvatarMaskBodyPart.RightArm,
146+
AvatarMaskBodyPart.Body, // UpperChest
147+
};
148+
87149
/// <summary>
88150
/// Maps OVRSkeletonBoneId to avatar mask body part.
89151
/// </summary>
@@ -265,4 +327,4 @@ public static readonly Dictionary<HumanBodyBones, AvatarMaskBodyPart>
265327
{ OVRSkeleton.BoneId.FullBody_RightFootBall, AvatarMaskBodyPart.RightLeg },
266328
};
267329
}
268-
}
330+
}

Runtime/Scripts/AnimationRigging/ExternalBoneTargets.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ private void Initialize()
9797
{
9898
retargetedBoneTarget.BoneId = humanBodyBoneToOVRBoneId[retargetedBoneTarget.HumanBodyBone];
9999
}
100+
101+
// Sort by bone id.
102+
_boneTargets = _boneTargets.OrderBy(x => x.BoneId).ToArray();
100103
_initialized = true;
101104
}
102105

@@ -110,22 +113,23 @@ public void ProcessSkeleton(OVRSkeleton skeleton)
110113
{
111114
return;
112115
}
116+
113117
Initialize();
114-
IList<OVRBone> bones = skeleton.Bones;
118+
var retargetedBoneTargetIndex = 0;
119+
var bones = skeleton.Bones;
115120
for (var i = 0; i < bones.Count; i++)
116121
{
117-
foreach (var retargetedBoneTarget in _boneTargets)
122+
var retargetedBoneTarget = _boneTargets[retargetedBoneTargetIndex];
123+
if (bones[i].Id == retargetedBoneTarget.BoneId)
118124
{
119-
if (bones[i].Id == retargetedBoneTarget.BoneId)
125+
retargetedBoneTargetIndex++;
126+
var targetBone = bones[i].Transform;
127+
if (targetBone == null)
120128
{
121-
var targetBone = bones[i].Transform;
122-
if (targetBone == null)
123-
{
124-
continue;
125-
}
126-
retargetedBoneTarget.Target.SetPositionAndRotation(
127-
targetBone.position, targetBone.rotation);
129+
continue;
128130
}
131+
retargetedBoneTarget.Target.SetPositionAndRotation(
132+
targetBone.position, targetBone.rotation);
129133
}
130134
}
131135
}

Runtime/Scripts/AnimationRigging/PlaybackAnimationJob.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ public override void Update(PlaybackAnimationJob job, ref T data)
176176

177177
if (playbackType == PlaybackAnimationData.AnimationPlaybackType.None ||
178178
(data.AnimationMask != null &&
179-
!data.AnimationMask.GetHumanoidBodyPartActive(BoneMappingsExtension.HumanBoneToAvatarBodyPart[i])))
179+
!data.AnimationMask.GetHumanoidBodyPartActive(BoneMappingsExtension.HumanBoneToAvatarBodyPartArray[(int)i])))
180180
{
181181
job.BonePositionDeltas[index] = Vector3.zero;
182182
job.BoneRotationDeltas[index] = Quaternion.identity;

Runtime/Scripts/AnimationRigging/ProxyTransformLogic.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ private void CleanUpOldProxyTransforms()
171171
GameObject.Destroy(proxyParent.gameObject);
172172
}
173173

174-
// <summary>
174+
/// <summary>
175175
/// Sometimes source transforms change even though the IDs are the same,
176176
/// and proxies are only recreated if the bone IDs of the sources change.
177177
/// Make sure they are set properly.

Runtime/Scripts/AnimationRigging/RetargetingLayer.cs

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,6 @@ public class JointPositionAdjustment
5353
public Vector3 GetPositionOffset()
5454
{
5555
var targetPositionOffset = FinalPosition - OriginalPosition;
56-
// The recorded positions will not be finite when we regenerate data for the rig.
57-
if (!RiggingUtilities.IsFiniteVector3(FinalPosition) ||
58-
!RiggingUtilities.IsFiniteVector3(OriginalPosition))
59-
{
60-
return Vector3.zero;
61-
}
6256
return targetPositionOffset;
6357
}
6458
}
@@ -214,6 +208,11 @@ public RetargetedBoneMappings RetargetedBoneMappingsInst
214208
private ProxyTransformLogic _proxyTransformLogic = new ProxyTransformLogic();
215209
private bool _isFocusedWhileInBuild = true;
216210

211+
// Cached array versions of dictionaries used in OVRUnityHumanoidSkeletonRetargeter
212+
private HumanBodyBones[] _customBoneIdToHumanBodyBoneArray;
213+
private OVRSkeletonMetadata.BoneData[] _targetSkeletonDataBodyToBoneDataArray;
214+
private OVRHumanBodyBonesMappings.BodySection[] _boneToBodySectionArray;
215+
217216
/// <summary>
218217
/// Check for required components.
219218
/// </summary>
@@ -263,6 +262,7 @@ protected override void Start()
263262
ConstructDefaultPoseInformation();
264263
ConstructBoneAdjustmentInformation();
265264
CacheJointConstraints();
265+
CacheBoneMapping();
266266
ValidateHumanoid();
267267

268268
_retargetingAnimationRig.ValidateRig(this);
@@ -325,6 +325,26 @@ private void CacheJointConstraints()
325325
_jointConstraints = jointConstraints.ToArray();
326326
}
327327

328+
private void CacheBoneMapping()
329+
{
330+
_targetSkeletonDataBodyToBoneDataArray = new OVRSkeletonMetadata.BoneData[(int)HumanBodyBones.LastBone];
331+
_customBoneIdToHumanBodyBoneArray = new HumanBodyBones[(int)BoneId.Max];
332+
for (int i = 0; i < _customBoneIdToHumanBodyBoneArray.Length; i++)
333+
{
334+
_customBoneIdToHumanBodyBoneArray[i] = BodyBoneMappingsInterface.GetFullBodyBoneIdToHumanBodyBone.
335+
GetValueOrDefault((BoneId)i, HumanBodyBones.LastBone);
336+
}
337+
338+
_boneToBodySectionArray =
339+
new OVRHumanBodyBonesMappings.BodySection[OVRHumanBodyBonesMappings.BoneToBodySection.Count];
340+
for (int i = 0; i < _boneToBodySectionArray.Length; i++)
341+
{
342+
_boneToBodySectionArray[i] =
343+
OVRHumanBodyBonesMappings.BoneToBodySection.GetValueOrDefault((HumanBodyBones)i,
344+
OVRHumanBodyBonesMappings.BodySection.Head);
345+
}
346+
}
347+
328348
private void ValidateHumanoid()
329349
{
330350
bool validHumanoid = true;
@@ -386,6 +406,13 @@ protected override void Update()
386406
_retargetingAnimationRig.UpdateRig(this);
387407
}
388408

409+
/// <summary>
410+
/// Empty fixed update to avoid updating OVRSkeleton during fixed update.
411+
/// </summary>
412+
private void FixedUpdate()
413+
{
414+
}
415+
389416
/// <summary>
390417
/// Allows fixing joints via the retargeting processors. The avatar does not allow
391418
/// precise finger positions even with translate DoF checked.
@@ -397,6 +424,7 @@ protected virtual void LateUpdate()
397424
return;
398425
}
399426

427+
UpdateBoneDataToArray();
400428
foreach (var retargetingProcessor in _retargetingProcessors)
401429
{
402430
retargetingProcessor.PrepareRetargetingProcessor(this, Bones);
@@ -419,10 +447,18 @@ protected virtual void OnDrawGizmos()
419447
}
420448
}
421449

450+
protected virtual void UpdateBoneDataToArray()
451+
{
452+
for (int i = 0; i < TargetSkeletonData.BodyToBoneData.Count; i++)
453+
{
454+
_targetSkeletonDataBodyToBoneDataArray[i] =
455+
TargetSkeletonData.BodyToBoneData.GetValueOrDefault((HumanBodyBones)i, null);
456+
}
457+
}
458+
422459
protected virtual bool ShouldUpdatePositionOfBone(HumanBodyBones humanBodyBone)
423460
{
424-
var bodySectionOfJoint =
425-
OVRHumanBodyBonesMappings.BoneToBodySection[humanBodyBone];
461+
var bodySectionOfJoint =_boneToBodySectionArray[(int)humanBodyBone];
426462
return IsBodySectionInArray(bodySectionOfJoint,
427463
_skeletonType == SkeletonType.FullBody ? FullBodySectionToPosition : BodySectionToPosition);
428464
}
@@ -547,7 +583,7 @@ public void UpdateAdjustments(Quaternion[] rotationOffsets,
547583
if (avatarMask != null)
548584
{
549585
jointFailsMask = !avatarMask.GetHumanoidBodyPartActive(
550-
BoneMappingsExtension.HumanBoneToAvatarBodyPart[targetHumanBodyBone]);
586+
BoneMappingsExtension.HumanBoneToAvatarBodyPartArray[(int)targetHumanBodyBone]);
551587
}
552588

553589
if (adjustment == null)
@@ -672,25 +708,33 @@ public int GetNumberOfTransformsRetargeted()
672708
/// <returns>The human body bone for a custom bone id. Returns null if it doesn't exist.</returns>
673709
public HumanBodyBones? GetCustomBoneIdToHumanBodyBone(BoneId boneId)
674710
{
675-
if (CustomBoneIdToHumanBodyBone == null)
676-
{
677-
return null;
678-
}
679-
if (!CustomBoneIdToHumanBodyBone.TryGetValue(boneId, out var humanBodyBone))
711+
var humanBodyBone = _customBoneIdToHumanBodyBoneArray[(int)boneId];
712+
if (humanBodyBone == HumanBodyBones.LastBone)
680713
{
681714
return null;
682715
}
683716
return humanBodyBone;
684717
}
685718

719+
/// <summary>
720+
/// Returns the human body bone to body section pairing.
721+
/// </summary>
722+
/// <param name="humanBodyBone">The human body bone to check for.</param>
723+
/// <returns>The body section for a human body bone.</returns>
724+
public OVRHumanBodyBonesMappings.BodySection GetHumanBodyBoneToBodySection(HumanBodyBones humanBodyBone)
725+
{
726+
return _boneToBodySectionArray[(int)humanBodyBone];
727+
}
728+
686729
/// <summary>
687730
/// Returns the correction quaternion for a human body bone, if it exists.
688731
/// </summary>
689732
/// <param name="humanBodyBone">The human body bone to check for.</param>
690733
/// <returns>The correction quaternion for a human body bone. Returns null if it doesn't exist.</returns>
691734
public Quaternion? GetCorrectionQuaternion(HumanBodyBones humanBodyBone)
692735
{
693-
if (!TargetSkeletonData.BodyToBoneData.TryGetValue(humanBodyBone, out var targetData))
736+
var targetData = _targetSkeletonDataBodyToBoneDataArray[(int)humanBodyBone];
737+
if (targetData == null)
694738
{
695739
return null;
696740
}
@@ -708,7 +752,8 @@ public int GetNumberOfTransformsRetargeted()
708752
/// <returns>The original joint for a human body bone.</returns>
709753
public Transform GetOriginalJoint(HumanBodyBones humanBodyBone)
710754
{
711-
if (!TargetSkeletonData.BodyToBoneData.TryGetValue(humanBodyBone, out var targetData))
755+
var targetData = _targetSkeletonDataBodyToBoneDataArray[(int)humanBodyBone];
756+
if (targetData == null)
712757
{
713758
return null;
714759
}

Runtime/Scripts/RetargetingProcessing/RetargetingProcessorCorrectBones.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public override void ProcessRetargetingLayer(RetargetingLayer retargetingLayer,
110110
var targetCorrectionQuaternion = (Quaternion)nullableTargetCorrectionQuaternion;
111111

112112
// Make sure body part passes mask, and bone's position should be updated.
113-
var bodyPart = BoneMappingsExtension.HumanBoneToAvatarBodyPart[humanBodyBone];
113+
var bodyPart = BoneMappingsExtension.HumanBoneToAvatarBodyPartArray[(int)humanBodyBone];
114114
var targetJoint = retargetingLayer.GetOriginalJoint(humanBodyBone);
115115
if (retargetingLayer.CustomPositionsToCorrectLateUpdateMask != null &&
116116
!retargetingLayer.CustomPositionsToCorrectLateUpdateMask.GetHumanoidBodyPartActive(bodyPart))
@@ -123,16 +123,16 @@ public override void ProcessRetargetingLayer(RetargetingLayer retargetingLayer,
123123
continue;
124124
}
125125

126-
// Make sure the joint position is valid before fixing it.
126+
// If this is the first target position, check its validity.
127+
// If it's valid, assume that the remaining positions are valid as well.
127128
var currentTargetPosition = targetJoint.position;
128-
if (!RiggingUtilities.IsFiniteVector3(currentTargetPosition))
129+
if (i == 0 && !RiggingUtilities.IsFiniteVector3(currentTargetPosition))
129130
{
130-
continue;
131+
return;
131132
}
132133

133134
var rtWeight = Weight * retargetingLayer.RetargetingConstraint.weight;
134-
var bodySectionOfJoint =
135-
OVRUnityHumanoidSkeletonRetargeter.OVRHumanBodyBonesMappings.BoneToBodySection[humanBodyBone];
135+
var bodySectionOfJoint = retargetingLayer.GetHumanBodyBoneToBodySection(humanBodyBone);
136136
bool isLeftHandFingersOrWrist =
137137
bodySectionOfJoint == OVRUnityHumanoidSkeletonRetargeter.OVRHumanBodyBonesMappings.BodySection.LeftHand ||
138138
humanBodyBone == HumanBodyBones.LeftHand;

Runtime/Scripts/RetargetingProcessing/RetargetingProcessorCorrectHand.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ public override void SetupRetargetingProcessor(RetargetingLayer retargetingLayer
179179
}
180180

181181
if ((Handedness == Handedness.Left &&
182-
BoneMappingsExtension.HumanBoneToAvatarBodyPart[i] == AvatarMaskBodyPart.LeftArm) ||
182+
BoneMappingsExtension.HumanBoneToAvatarBodyPartArray[(int)i] == AvatarMaskBodyPart.LeftArm) ||
183183
(Handedness == Handedness.Right &&
184-
BoneMappingsExtension.HumanBoneToAvatarBodyPart[i] == AvatarMaskBodyPart.RightArm))
184+
BoneMappingsExtension.HumanBoneToAvatarBodyPartArray[(int)i] == AvatarMaskBodyPart.RightArm))
185185
{
186186
armBones.Add(boneTransform);
187187
}

Samples/Prefabs/Retargeting/ArmatureSkinningUpdateRetarget.prefab

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1562,7 +1562,6 @@ MonoBehaviour:
15621562
- {fileID: 11400000, guid: 15440560904a85846a7a4b75e1f7b96e, type: 2}
15631563
- {fileID: 11400000, guid: 8033477507feea54a9c44eb17a69be20, type: 2}
15641564
- {fileID: 11400000, guid: b47ca2dcc0aa6e34484b90e7122d3db4, type: 2}
1565-
- {fileID: 11400000, guid: 8eb3b8157e16d26409685b880d73b84e, type: 2}
15661565
_retargetingAnimationRig:
15671566
_rebindAnimator: 1
15681567
_reEnableRig: 1

0 commit comments

Comments
 (0)