using System; using System.Collections.Generic; using System.Text.RegularExpressions; using Service; using UnityEngine; namespace Convai.Scripts.Utils.LipSync { /// /// This Class will serve as a base for any method of Lipsync that Convai will develop or use /// public abstract class ConvaiLipSyncApplicationBase : MonoBehaviour { /// /// This stores a dictionary of blendshape name and index of the Blendweight it will affect /// protected Dictionary _headMapping; /// /// Reference to the Head Skin Mesh Renderer used for lipsync /// protected SkinnedMeshRenderer _headSkinMeshRenderer; /// /// Reference to the Teeth Skin Mesh Renderer used for lipsync /// protected SkinnedMeshRenderer _teethSkinMeshRenderer; /// /// Reference to the Jaw bone gameobject used for lipsync /// private GameObject _jawBone; /// /// Reference to the Tongue bone gameobject used for lipsync /// private GameObject _tongueBone; /// /// Reference to the NPC on which lipsync will be applied /// protected ConvaiNPC _convaiNPC; protected float _weightMultiplier { get; private set; } #region Null States of References protected bool HasHeadSkinnedMeshRenderer { get; private set; } protected bool HasTeethSkinnedMeshRenderer { get; private set; } protected bool HasJawBone { get; private set; } protected bool HasTongueBone { get; private set; } #endregion /// /// Initializes and setup up of the things necessary for lipsync to work /// /// /// public virtual void Initialize(ConvaiLipSync convaiLipSync, ConvaiNPC convaiNPC) { _headSkinMeshRenderer = convaiLipSync.HeadSkinnedMeshRenderer; HasHeadSkinnedMeshRenderer = _headSkinMeshRenderer != null; _teethSkinMeshRenderer = convaiLipSync.TeethSkinnedMeshRenderer; HasTeethSkinnedMeshRenderer = _teethSkinMeshRenderer != null; _jawBone = convaiLipSync.jawBone; HasJawBone = _jawBone != null; _tongueBone = convaiLipSync.tongueBone; HasTongueBone = _tongueBone != null; _convaiNPC = convaiNPC; _weightMultiplier = convaiLipSync != null ? convaiLipSync.WeightMultiplier : 1; if (HasHeadSkinnedMeshRenderer) _headMapping = SetupMapping(GetHeadRegexMapping, _headSkinMeshRenderer); } /// /// Creates the mapping of blendshape and index it affects during lipsync /// protected Dictionary SetupMapping(Func> finder, SkinnedMeshRenderer skinnedMeshRenderer) { Dictionary mapping = new Dictionary(); Dictionary regexMapping = finder(); foreach (KeyValuePair pair in regexMapping) { for (int i = 0; i < skinnedMeshRenderer.sharedMesh.blendShapeCount; i++) { string blendShapeName = skinnedMeshRenderer.sharedMesh.GetBlendShapeName(i); Regex regex = new(pair.Value); if (regex.IsMatch(blendShapeName)) { mapping.TryAdd(pair.Key, i); } } } return mapping; } /// /// Returns a dictionary of blendshape name and regex string used to find the index /// TODO Modify the override to fit your version of the mapping /// /// protected virtual Dictionary GetHeadRegexMapping() { return new Dictionary(); } /// /// Updates the tongue bone rotation to the new rotation /// /// protected void UpdateTongueBoneRotation(Vector3 newRotation) { if (!HasTongueBone) return; _tongueBone.transform.localEulerAngles = newRotation; } /// /// Updates the jaw bone rotation to the new rotation /// /// protected void UpdateJawBoneRotation(Vector3 newRotation) { if (!HasJawBone) return; _jawBone.transform.localEulerAngles = newRotation; } /// /// Updates the current blendshape or visemes frame /// protected abstract void UpdateBlendShape(); /// /// This removes the excess frames in the queue /// public abstract void PurgeExcessBlendShapeFrames(); /// /// This resets the whole queue of the frames /// protected bool CanPurge(Queue queue) { // ? Should I hardcode the limiter for this check return queue.Count < 10; } public abstract void ClearQueue(); /// /// Adds blendshape frames in the queue /// /// public virtual void EnqueueQueue(Queue blendshapeFrames) { } /// /// Adds Visemes frames in the list /// /// public virtual void EnqueueQueue(Queue visemesFrames) { } /// /// Adds a blendshape frame in the last queue /// /// public virtual void EnqueueFrame(BlendshapeFrame blendshapeFrame) { } /// /// Adds a viseme frame to the last element of the list /// /// public virtual void EnqueueFrame(VisemesData viseme) { } } }