Unity插件OVRLipSync有什么用

这篇文章给大家分享的是有关Unity插件OVRLipSync有什么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

项目需要接入对话口型动作,所以将OVRLipSync集成到项目中。

1、下载OVRLipSync.unitypackage

2、导入完成后可以参看demo,我这边主要是导入了模型动作的功能。我们主要关注的是OVRLipSync.cs,OVRLipSyncContext.cs,OVRLipSyncContextMorphTarget.cs类

3、OVRLipSync.cs 主要是导入Dll接口函数。需要预先初始化这个。可以在Scence创建一个GameObject绑上这个脚本。

4、我将OVRLipSyncContext.cs,OVRLipSyncContextMorphTarget.cs 合并为一个.cs 脚本。

[RequireComponent(typeof(AudioSource))]

public class OVRLipSyncContextEx: MonoBehaviour
{

    public AudioSource audioSource = null;
    public float gain = 1.0f;

    public OVRLipSync.ovrLipSyncContextProvider provider = OVRLipSync.ovrLipSyncContextProvider.Main;
    public bool delayCompensate = false;

    private OVRLipSync.ovrLipSyncFrame frame = new OVRLipSync.ovrLipSyncFrame(0);
    private uint context = 0; // 0 is no context

    public SkinnedMeshRenderer skinnedMeshRenderer = null;

   // 目标的模型动作名称,这个美术给定
    public int [] VisemeToBlendTargets = new int[(int)OVRLipSync.ovrLipSyncViseme.Count];

    void Awake()
    {
        // Cache the audio source we are going to be using to pump data to the SR
        if (!audioSource) audioSource = GetComponent<AudioSource>();
        if (!audioSource) return;
    }

    void Start()
    {
        lock (this) //不存在异步同时,可以去掉lock
        {
            if (context == 0)
            {
                if (OVRLipSync.CreateContext(ref context, provider) != OVRLipSync.ovrLipSyncSuccess)
                {
                    Debug.Log("OVRPhonemeContext.Start ERROR: Could not create Phoneme context.");
                    return;
                }
            }

        //通过AudioSourceListener 去获取Audio的数据。这个是Unity大概没20ms会出发一次。

gameObject.GetComponent<AudioSourceListener>().OnEventAudioFilterRead += AudioFilterRead;
        }

SendSignal(OVRLipSync.ovrLipSyncSignals.VisemeSmoothing, SmoothAmount, 0);

            //测试动作名称
            VisemeToBlendTargets[0] = "doubt";
            VisemeToBlendTargets[1] = "smile";
            VisemeToBlendTargets[2] = "anger";
            VisemeToBlendTargets[3] = "surprise";
            VisemeToBlendTargets[4] = "scare";
            VisemeToBlendTargets[5] = "nervous";
            VisemeToBlendTargets[6] = "upset";
            VisemeToBlendTargets[7] = "tiresome";
            VisemeToBlendTargets[8] = "bashful";
            VisemeToBlendTargets[9] = "greedy";
            VisemeToBlendTargets[10] = "doubt";
            VisemeToBlendTargets[11] = "doubt";
            VisemeToBlendTargets[12] = "doubt";
            VisemeToBlendTargets[13] = "doubt";
            VisemeToBlendTargets[14] = "doubt";

    }

    void Update()
    {
if(skinnedMeshRenderer != null)
{
if(GetCurrentPhonemeFrame(ref frame) == OVRLipSync.ovrLipSyncSuccess)
{
SetVisemeToMorphTarget();
}
}
    }

    void OnDestroy()
    {
        // Create the context that we will feed into the audio buffer
        lock (this) //不存在异步同时,可以去掉lock
        {
            if (context != 0)
            {
                if (OVRLipSync.DestroyContext(context) != OVRLipSync.ovrLipSyncSuccess)
                {
                    Debug.Log("OVRPhonemeContext.OnDestroy ERROR: Could not delete Phoneme context.");
                }
            }
        }
    }

    void AudioFilterRead(float[] data, int channels)
    {
        // Do not spatialize if we are not initialized, or if there is no
        // audio source attached to game object
        if ((OVRLipSync.IsInitialized() != OVRLipSync.ovrLipSyncSuccess) || audioSource == null)
            return;


        // increase the gain of the input to get a better signal input
        for (int i = 0; i < data.Length; ++i)
            data[i] = data[i] * gain;


        // Send data into Phoneme context for processing (if context is not 0)
        lock (this) //不存在异步同时,可以去掉lock
        {
            if (context != 0)
            {
                OVRLipSync.ovrLipSyncFlag flags = 0;


                // Set flags to feed into process
                if (delayCompensate == true)
                    flags |= OVRLipSync.ovrLipSyncFlag.DelayCompensateAudio;


                OVRLipSync.ProcessFrameInterleaved(context, data, flags, ref frame);
            }
        }
    }

    public int GetCurrentPhonemeFrame(ref OVRLipSync.ovrLipSyncFrame inFrame)
    {
        if (OVRLipSync.IsInitialized() != OVRLipSync.ovrLipSyncSuccess)
            return (int)OVRLipSync.ovrLipSyncError.Unknown;


        lock (this) //不存在异步同时,可以去掉lock
        {
            inFrame.frameNumber = frame.frameNumber;
            inFrame.frameDelay = frame.frameDelay;
            for (int i = 0; i < inFrame.Visemes.Length; i++)
            {
                inFrame.Visemes[i] = frame.Visemes[i];
            }
        }


        return OVRLipSync.ovrLipSyncSuccess;
    }

    public int ResetContext()
    {
        if (OVRLipSync.IsInitialized() != OVRLipSync.ovrLipSyncSuccess)
            return (int)OVRLipSync.ovrLipSyncError.Unknown;


        return OVRLipSync.ResetContext(context);
    }

  //暂时没用到
    public int SendSignal(OVRLipSync.ovrLipSyncSignals signal, int arg1, int arg2)
    {
        if (OVRLipSync.IsInitialized() != OVRLipSync.ovrLipSyncSuccess)
            return (int)OVRLipSync.ovrLipSyncError.Unknown;


        return OVRLipSync.SendSignal(context, signal, arg1, arg2);
    }


void SetVisemeToMorphTarget()
{
for (int i = 0; i < VisemeToBlendTargets.Length; i++)
{
if(VisemeToBlendTargets[i] != -1)
{
// 播放对应模型的动作权重。
skinnedMeshRenderer.SetBlendShapeWeight(VisemeToBlendTargets[i], frame.Visemes[i] * 100.0f);
}
}
}
 }

//以上是声音绑定在模型上播放。由于很多声音播放相对独立。可以实现以下函数。

float m_detaTime = 0;

  void Update()
        {
                if (m_bSpeak)
                {
                    // trap inputs and send signals to phoneme engine for testing purposes
                    AudioItem item = AudioController.GetAudioItem(speakKey);
                    if (item != null)
                    {
                        if (m_obj)  // 播放声音的GameObject  外部传入
                        {
                            AudioSource ads = m_obj.GetComponent<AudioSource>();
                            if (ads)
                            {

                              //unity3d OnAudioFilterRead 大概23毫秒回调一次。只新数据来,才在Update内去更新

     // demo里不加的话,会出现嘴唇抖动的问题。
                               if (m_detaTime < 0.023f)  // 48000/2048;
                                {
                                    m_detaTime += Time.deltaTime;
                                }
                                else
                                {
                                    // get the current viseme frame
                                    if (GetCurrentPhonemeFrame(ref frame) == OVRLipSync.ovrLipSyncSuccess)
                                    {
                                        SetVisemeToMorphTarget();
                                    }
                                    m_detaTime = 0;
                                }
                            }


                        }
                    }
                }
        }

增加一个deglet 回调类 放在AduioSource下

public class AudioSourceListener : MonoBehaviour
{


    public delegate void DgtEventAudioFilterRead(float[] data, int channels,AudioObject obj);
    public  DgtEventAudioFilterRead OnEventAudioFilterRead;


    private AudioObject m_audio_obj;
    // Use this for initialization
    public void Start()
    {
        m_audio_obj = this.gameObject.GetComponent<AudioObject>();
    }


    // Update is called once per frame
    void Update()
    {


    }


    void OnAudioFilterRead(float[] data, int channels)
    {
        if (OnEventAudioFilterRead != null)
        {
            OnEventAudioFilterRead(data,channels, m_audio_obj);
        }
    }
 }

Unity语音口型学习(Oculus发布的OVRLipSync示例)

了解该部分可以参考Oculus发布的OVRLipSync示例。
https://developer3.oculus.com/downloads/

Unity插件OVRLipSync有什么用

将下载下来的package导入Unity,可以运行官方Demo。

Unity插件OVRLipSync有什么用

该Demo中模型的口型动作,可以通过
Maya
Cinema4D
3D Studio Max
Blender
Cheetah 3D
XSI
Any tool that supports the FBX format
这几个工具进行设计和制作。详情

如果我们通过这些工具制作相关口型动作并导入,在Unity中选中模型,在Inspector中会显示在SkinMeshRenderer中。

Unity插件OVRLipSync有什么用

该Demo中通过Oculus官方提供的语音识别DLL进行实时语音识别并通过(位置..\Assets\Plugins\x86_64中的OVRLipSync.dll)

skinnedMeshRenderer = GetComponent<SkinnedMeshRenderer> ();
skinnedMeshRenderer.SetBlendShapeWeight (0, blendOne);

代码进行控制。

感谢各位的阅读!关于“Unity插件OVRLipSync有什么用”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍了Unity游戏开发中外观模式是什么意思,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章主要介绍Unity中地面检测方案的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1.普通射线在角色坐标(一般是脚底)...
这篇文章主要介绍了Unity游戏开发中如何消除不想要的黄色警告,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带...
这篇文章主要介绍了Unity中有多少种渲染队列,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解
这篇文章主要介绍Unity中如何实现Texture,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!了解Texture2D 如上图,Texture2D是一张
小编给大家分享一下Unity中DOTS要实现的特点有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让...
这篇文章给大家分享的是有关unity中如何实现UGUI遮罩流光特效的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。下面是核心shader:Sh...
这篇文章主要为大家展示了“Unity中如何实现3D坐标转换UGUI坐标”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下...
这篇文章主要介绍了Unity游戏开发中设计模式的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章主要介绍了Unity中如何实现仿真丝袜渲染,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了...
这篇文章给大家分享的是有关Unity插件OVRLipSync有什么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。项目需要接入对话口型动...
这篇文章主要介绍了Unity性能优化之DrawCall的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家...
这篇文章给大家分享的是有关Unity给力插件之Final IK怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。这插件有什么用:一般游...
这篇文章给大家分享的是有关Unity中如何内嵌网页插件UniWebView的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、常见Unity中内...
小编给大家分享一下Unity如何做流体物理的几个轮子,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让...
小编给大家分享一下Unity中Lod和Occlusion Culling的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收...
这篇文章将为大家详细讲解有关Unity中LineRenderer与TrailRenderer有什么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获...
这篇文章主要介绍了Unity中coroutine问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起...
这篇文章将为大家详细讲解有关unity中spine怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。骨骼动画首先我们来看到...
这篇文章主要为大家展示了“Unity Shader后处理中如何实现简单均值模糊”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学...