148 lines
3.9 KiB
C#
148 lines
3.9 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
public class Audio2LipScript : MonoBehaviour
|
||
{
|
||
[Tooltip("Which lip sync provider to use for viseme computation.")]
|
||
public OVRLipSync.ContextProviders provider = OVRLipSync.ContextProviders.Enhanced;
|
||
[Tooltip("Enable DSP offload on supported Android devices.")]
|
||
public bool enableAcceleration = true;
|
||
[SerializeField] private uint Context = 0;
|
||
[SerializeField] public float gain = 1.0f;
|
||
/// <summary>
|
||
/// 音频
|
||
/// </summary>
|
||
[SerializeField] private AudioSource m_AudioSource;
|
||
/// <summary>
|
||
/// 模型的SkinnedMeshRenderer组件
|
||
/// </summary>
|
||
[Header("设置带有口型的MeshRender")]
|
||
public SkinnedMeshRenderer meshRenderer;
|
||
/// <summary>
|
||
/// blendshape权重倍数
|
||
/// </summary>
|
||
public float blendWeightMultiplier = 100f;
|
||
/// <summary>
|
||
/// 设置每个口型对应的blendershape的索引
|
||
/// </summary>
|
||
[Header("设置元音对应的blendershape的索引值")]
|
||
public VisemeBlenderShapeIndexMap m_VisemeIndex;
|
||
|
||
/// <summary>
|
||
/// 音素分析结果
|
||
/// </summary>
|
||
private OVRLipSync.Frame frame = new OVRLipSync.Frame();
|
||
protected OVRLipSync.Frame Frame
|
||
{
|
||
get
|
||
{
|
||
return frame;
|
||
}
|
||
}
|
||
|
||
private void Awake()
|
||
{
|
||
m_AudioSource=this.GetComponent<AudioSource>();
|
||
if (Context == 0)
|
||
{
|
||
if (OVRLipSync.CreateContext(ref Context, provider, 0, enableAcceleration)
|
||
!= OVRLipSync.Result.Success)
|
||
{
|
||
Debug.LogError("OVRLipSyncContextBase.Start ERROR: Could not create" +
|
||
" Phoneme context.");
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
void OnAudioFilterRead(float[] data, int channels)
|
||
{
|
||
ProcessAudioSamplesRaw(data, channels);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Pass F32 PCM audio buffer to the lip sync module
|
||
/// </summary>
|
||
/// <param name="data">Data.</param>
|
||
/// <param name="channels">Channels.</param>
|
||
public void ProcessAudioSamplesRaw(float[] data, int channels)
|
||
{
|
||
// Send data into Phoneme context for processing (if context is not 0)
|
||
lock (this)
|
||
{
|
||
if (OVRLipSync.IsInitialized() != OVRLipSync.Result.Success)
|
||
{
|
||
return;
|
||
}
|
||
var frame = this.Frame;
|
||
OVRLipSync.ProcessFrame(Context, data, frame, channels == 2);
|
||
}
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (this.Frame != null)
|
||
{
|
||
SetBlenderShapes();
|
||
}
|
||
}
|
||
|
||
|
||
private void SetBlenderShapes()
|
||
{
|
||
for (int i = 0; i < this.Frame.Visemes.Length; i++)
|
||
{
|
||
string _name = ((OVRLipSync.Viseme)i).ToString();
|
||
int blendShapeIndex = GetBlenderShapeIndexByName(_name);
|
||
int blendWeight = (int)(blendWeightMultiplier * this.Frame.Visemes[i]);
|
||
if (blendShapeIndex == 999)
|
||
continue;
|
||
|
||
meshRenderer.SetBlendShapeWeight(blendShapeIndex, blendWeight);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 简单判断下,返回a i u e o 的索引
|
||
/// </summary>
|
||
/// <param name="_name"></param>
|
||
/// <returns></returns>
|
||
private int GetBlenderShapeIndexByName(string _name)
|
||
{
|
||
if (_name == "sil")
|
||
{
|
||
return 999;
|
||
}
|
||
if (_name == "aa")
|
||
{
|
||
return m_VisemeIndex.A;
|
||
}
|
||
if (_name == "ih")
|
||
{
|
||
return m_VisemeIndex.I;
|
||
}
|
||
if (_name == "E")
|
||
{
|
||
return m_VisemeIndex.E;
|
||
}
|
||
if (_name == "oh")
|
||
{
|
||
return m_VisemeIndex.O;
|
||
}
|
||
|
||
return m_VisemeIndex.U;
|
||
}
|
||
|
||
[System.Serializable]
|
||
public class VisemeBlenderShapeIndexMap
|
||
{
|
||
public int A;
|
||
public int I;
|
||
public int U;
|
||
public int E;
|
||
public int O;
|
||
|
||
}
|
||
}
|