/************************************************************************************ Filename : OVRLipSyncContextTextureFlip.cs Content : This bridges the phoneme/viseme output to texture flip targets Created : August 7th, 2015 Copyright : Copyright Facebook Technologies, LLC and its affiliates. All rights reserved. Licensed under the Oculus Audio SDK License Version 3.3 (the "License"); you may not use the Oculus Audio 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/audio-3.3/ Unless required by applicable law or agreed to in writing, the Oculus Audio 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 UnityEngine; public class OVRLipSyncContextTextureFlip : MonoBehaviour { // PUBLIC // Manually assign the material public Material material = null; // Set the textures for each viseme. We should follow the viseme order as specified // by the Phoneme list [Tooltip("The texture used for each viseme.")] [OVRNamedArray(new string[] { "sil", "PP", "FF", "TH", "DD", "kk", "CH", "SS", "nn", "RR", "aa", "E", "ih", "oh", "ou" })] public Texture[] Textures = new Texture[OVRLipSync.VisemeCount]; // smoothing amount [Range(1, 100)] [Tooltip("Smoothing of 1 will yield only the current predicted viseme," + "100 will yield an extremely smooth viseme response.")] public int smoothAmount = 70; // PRIVATE // Look for a Phoneme Context (should be set at the same level as this component) private OVRLipSyncContextBase lipsyncContext = null; // Capture the old viseme frame (we will write back into this one) private OVRLipSync.Frame oldFrame = new OVRLipSync.Frame(); /// /// Start this instance. /// void Start() { // make sure there is a phoneme context assigned to this object lipsyncContext = GetComponent(); if (lipsyncContext == null) { Debug.LogWarning("LipSyncContextTextureFlip.Start WARNING:" + " No lip sync context component set to object"); } else { // Send smoothing amount to context lipsyncContext.Smoothing = smoothAmount; } if (material == null) { Debug.LogWarning("LipSyncContextTextureFlip.Start WARNING:" + " Lip sync context texture flip has no material target to control!"); } } /// /// Update this instance. /// void Update () { if((lipsyncContext != null) && (material != null)) { // trap inputs and send signals to phoneme engine for testing purposes // get the current viseme frame OVRLipSync.Frame frame = lipsyncContext.GetCurrentPhonemeFrame(); if (frame != null) { // Perform smoothing here if on original provider if (lipsyncContext.provider == OVRLipSync.ContextProviders.Original) { // Go through the current and old for (int i = 0; i < frame.Visemes.Length; i++) { // Convert 1-100 to old * (0.00 - 0.99) float smoothing = ((smoothAmount - 1) / 100.0f); oldFrame.Visemes[i] = oldFrame.Visemes[i] * smoothing + frame.Visemes[i] * (1.0f - smoothing); } } else { oldFrame.Visemes = frame.Visemes; } SetVisemeToTexture(); } } // Update smoothing value in context if (smoothAmount != lipsyncContext.Smoothing) { lipsyncContext.Smoothing = smoothAmount; } } /// /// Sets the viseme to texture. /// void SetVisemeToTexture() { // This setting will run through all the Visemes, find the // one with the greatest amplitude and set it to max value. // all other visemes will be set to zero. int gV = -1; float gA = 0.0f; for (int i = 0; i < oldFrame.Visemes.Length; i++) { if(oldFrame.Visemes[i] > gA) { gV = i; gA = oldFrame.Visemes[i]; } } if ((gV != -1) && (gV < Textures.Length)) { Texture t = Textures[gV]; if(t != null) { material.SetTexture("_MainTex", t); } } } }