/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * Licensed under the Oculus SDK License Agreement (the "License"); * you may not use the Oculus SDK except in compliance with the License, * which is provided at the time of installation or download, or which * otherwise accompanies this software in either electronic or hard copy form. * * You may obtain a copy of the License at * * https://developer.oculus.com/licenses/oculussdk/ * * Unless required by applicable law or agreed to in writing, the Oculus SDK * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.ComponentModel; using UnityEngine; using UnityEngine.Assertions; /// /// OVR Component to drive blend shapes on a SkinnedMeshRenderer based on Face Tracking provided by OVRFaceExpressions. /// /// /// See for more information. /// This specialization of provides mapping based on an array, configurable from the editor /// This component comes with a custom editor that supports attempting to auto populate the mapping array based on string matching /// See for more information. /// [RequireComponent(typeof(SkinnedMeshRenderer))] [HelpURL("https://developer.oculus.com/reference/unity/latest/class_o_v_r_custom_face")] public class OVRCustomFace : OVRFace { public OVRFaceExpressions.FaceExpression[] Mappings { get => _mappings; set => _mappings = value; } [SerializeField] [Tooltip("The mapping between Face Expressions to the blendshapes available " + "on the shared mesh of the skinned mesh renderer")] internal OVRFaceExpressions.FaceExpression[] _mappings; [SerializeField, HideInInspector] internal RetargetingType retargetingType; protected RetargetingType RetargetingValue { get => retargetingType; set => retargetingType = value; } [SerializeField] [Tooltip("Allow duplicates when mapping blendshapes to Face Expressions")] internal bool _allowDuplicateMapping = true; protected bool AllowDuplicateMapping { get => _allowDuplicateMapping; set => _allowDuplicateMapping = value; } /// protected override void Start() { base.Start(); Assert.IsNotNull(_mappings); Assert.AreEqual(_mappings.Length, RetrieveSkinnedMeshRenderer().sharedMesh.blendShapeCount, "Mapping out of sync with shared mesh."); } /// protected internal override OVRFaceExpressions.FaceExpression GetFaceExpression(int blendShapeIndex) { Assert.IsTrue(blendShapeIndex < _mappings.Length && blendShapeIndex >= 0); return _mappings[blendShapeIndex]; } /// /// Allows the user to define their own blend shape name and face expression pair mappings. /// By default it will just return the Oculus version. /// /// Two arrays, each relating a blend shape name with a face expression pair. protected internal virtual (string[], OVRFaceExpressions.FaceExpression[]) GetCustomBlendShapeNameAndExpressionPairs() { string[] oculusBlendShapeNames = Enum.GetNames(typeof(OVRFaceExpressions.FaceExpression)); OVRFaceExpressions.FaceExpression[] oculusFaceExpressions = (OVRFaceExpressions.FaceExpression[])Enum.GetValues(typeof(OVRFaceExpressions.FaceExpression)); return (oculusBlendShapeNames, oculusFaceExpressions); } public enum RetargetingType { OculusFace = 0, Custom = 1, } }