11// Copyright (c) Meta Platforms, Inc. and affiliates.
22
33using Oculus . Movement . AnimationRigging ;
4+ using Oculus . Movement . Tracking ;
45using System ;
56using UnityEditor ;
7+ using UnityEditor . SceneManagement ;
68using UnityEngine ;
79using UnityEngine . Animations . Rigging ;
810
@@ -15,18 +17,28 @@ namespace Oculus.Movement.Utils
1517 internal static class HelperMenus
1618 {
1719 private const string _MOVEMENT_SAMPLES_MENU =
20+
1821 "GameObject/Movement Samples/" ;
1922 private const string _MOVEMENT_SAMPLES_BT_MENU =
2023 "Body Tracking/" ;
2124 private const string _ANIM_RIGGING_RETARGETING_MENU =
2225 "Animation Rigging Retargeting" ;
2326
27+ private const string _MOVEMENT_SAMPLES_FT_MENU =
28+ "Face Tracking/" ;
29+ private const string _CORRECTIVES_FACE_MENU =
30+ "Correctives Face" ;
31+ private const string _CORRECTIVES_FACE_DUPLICATE_MENU =
32+ "Correctives Face (allow duplicate mapping)" ;
33+
2434 [ MenuItem ( _MOVEMENT_SAMPLES_MENU + _MOVEMENT_SAMPLES_BT_MENU + _ANIM_RIGGING_RETARGETING_MENU ) ]
2535 private static void SetupCharacterForAnimationRiggingRetargeting ( )
2636 {
37+ var activeGameObject = Selection . activeGameObject ;
38+
2739 try
2840 {
29- ValidGameObjectForAnimationRigging ( Selection . activeGameObject ) ;
41+ ValidGameObjectForAnimationRigging ( activeGameObject ) ;
3042 }
3143 catch ( InvalidOperationException e )
3244 {
@@ -36,25 +48,41 @@ private static void SetupCharacterForAnimationRiggingRetargeting()
3648
3749 Undo . IncrementCurrentGroup ( ) ;
3850
39- var mainParent = Selection . activeGameObject ;
40-
4151 // Add the retargeting and body tracking components at root first.
42- RetargetingLayer retargetingLayer = AddMainRetargetingComponents ( mainParent ) ;
52+ RetargetingLayer retargetingLayer = AddMainRetargetingComponents ( activeGameObject ) ;
4353
4454 GameObject rigObject ;
4555 RigBuilder rigBuilder ;
46- ( rigBuilder , rigObject ) = AddBasicAnimationRiggingComponents ( mainParent ) ;
56+ ( rigBuilder , rigObject ) = AddBasicAnimationRiggingComponents ( activeGameObject ) ;
4757
4858 RetargetingAnimationConstraint retargetConstraint =
4959 AddRetargetingConstraint ( rigObject , retargetingLayer ) ;
5060
5161 // Add final components to tie everything together.
52- AddAnimationRiggingLayer ( mainParent , retargetingLayer , rigBuilder ,
62+ AddAnimationRiggingLayer ( activeGameObject , retargetingLayer , rigBuilder ,
5363 retargetConstraint , retargetingLayer ) ;
5464
5565 Undo . SetCurrentGroupName ( "Setup Animation Rigging Retargeting" ) ;
5666 }
5767
68+ [ MenuItem ( _MOVEMENT_SAMPLES_MENU + _MOVEMENT_SAMPLES_FT_MENU + _CORRECTIVES_FACE_MENU ) ]
69+ private static void SetupCharacterForCorrectivesFace ( )
70+ {
71+ var activeGameObject = Selection . activeGameObject ;
72+
73+ try
74+ {
75+ ValidateGameObjectForFaceMapping ( activeGameObject ) ;
76+ }
77+ catch ( InvalidOperationException e )
78+ {
79+ EditorUtility . DisplayDialog ( "Face Tracking setup error." , e . Message , "Ok" ) ;
80+ return ;
81+ }
82+
83+ SetUpCharacterForCorrectivesFace ( activeGameObject ) ;
84+ }
85+
5886 private static RetargetingLayer AddMainRetargetingComponents ( GameObject mainParent )
5987 {
6088 RetargetingLayer retargetingLayer = mainParent . GetComponent < RetargetingLayer > ( ) ;
@@ -170,5 +198,48 @@ private static void ValidGameObjectForAnimationRigging(GameObject go)
170198 }
171199 }
172200
201+ public static void ValidateGameObjectForFaceMapping ( GameObject go )
202+ {
203+ var renderer = go . GetComponent < SkinnedMeshRenderer > ( ) ;
204+ if ( renderer == null || renderer . sharedMesh == null || renderer . sharedMesh . blendShapeCount == 0 )
205+ {
206+ throw new InvalidOperationException (
207+ $ "Adding a Face Tracking component requires a { nameof ( SkinnedMeshRenderer ) } " +
208+ $ "that contains blendshapes.") ;
209+ }
210+ }
211+
212+ private static void SetUpCharacterForCorrectivesFace ( GameObject gameObject )
213+ {
214+ Undo . IncrementCurrentGroup ( ) ;
215+
216+ var faceExpressions = gameObject . GetComponentInParent < OVRFaceExpressions > ( ) ;
217+ if ( ! faceExpressions )
218+ {
219+ faceExpressions = gameObject . AddComponent < OVRFaceExpressions > ( ) ;
220+ Undo . RegisterCreatedObjectUndo ( faceExpressions , "Create OVRFaceExpressions component" ) ;
221+ }
222+
223+ var face = gameObject . GetComponent < CorrectivesFace > ( ) ;
224+ if ( ! face )
225+ {
226+ face = gameObject . AddComponent < CorrectivesFace > ( ) ;
227+ face . FaceExpressions = faceExpressions ;
228+ Undo . RegisterCreatedObjectUndo ( face , "Create CorrectivesFace component" ) ;
229+ }
230+
231+ if ( face . BlendshapeModifier == null )
232+ {
233+ face . BlendshapeModifier = gameObject . GetComponentInParent < BlendshapeModifier > ( ) ;
234+ Undo . RecordObject ( face , "Assign to BlendshapeModifier field" ) ;
235+ }
236+
237+ Undo . RegisterFullObjectHierarchyUndo ( face , "Auto-map Correcives blendshapes" ) ;
238+ face . AutoMapBlendshapes ( ) ;
239+ EditorUtility . SetDirty ( face ) ;
240+ EditorSceneManager . MarkSceneDirty ( face . gameObject . scene ) ;
241+
242+ Undo . SetCurrentGroupName ( $ "Setup Character for CorrecivesFace Tracking") ;
243+ }
173244 }
174245}
0 commit comments