卓上解説室

筆者TellerGがyoutube等に投稿した動画の解説用として試験的に運用中。

X-001 音量制御口パク 補足説明

動画本編

www.youtube.com

・・・超急いで作ったとはいえ我ながら不出来ですね(汗
動画を見ずに先にこちらのページへ来た方、正直動画のほうは今回は見なくていいです。全てこちらで解説させていただきます。

以下折り畳み内にて解説していきます。
(注意)素人解説です。詳しい方からのご指摘、ご指南等はいつでもお待ちしております。

目次

はじめに

正直動画は適当すぎてなんだかわからないので何ができるのかをまず明らかにします。
以下で解説するのは、Unity上でwave音源の音量データに基づいて口のモーフを制御する方法です。
本当は母音ごとにモーフ分けてちゃんとした「リップシンク」をやりたかったのですが難しかったためとりあえずで作った機能です。

  • 引用文献について

動画内にて、音量を計算する計算式の部分で「他のサイトから~」と書いていますが、今回のスクリプトは以下のページを参考にさせていただいています。
tips.hecomi.com
Unityでの「音」の取り扱いについて色々と書いて下さっているので、まずこちらのサイトの内容に目を通していただく事を推奨します。これを読めばある程度Unityに慣れた人ならこの先は読まなくてもできると思います。

まず音量を取得するスクリプトです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

[RequireComponent(typeof(AudioSource))]
[DisallowMultipleComponent]

public class loudget : MonoBehaviour {
    public static float volume;
    private new AudioSource audio;
    private float[] waveData_ = new float[1024];

    void Start()
    {
        audio = GetComponent<AudioSource>();
    }
    
    void Update () {
        audio.GetOutputData(waveData_, 1);
        volume = waveData_.Select(x => x * x).Sum() / waveData_.Length;
    }

//他スクリプトで音量の値を呼び出すための関数
    public static float getvolume()
    {
        return volume;
    }

}

AudioSourceで流れているオーディオを直接取得して音量値を関数で呼び出せるようにしたスクリプトです。
詳しい解説については引用したページの解説が分かりやすいのでそちらでどうぞ。


続いてモーフ制御スクリプトです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class rip : MonoBehaviour {
    //int blendShapeCount;
    public float mo = 0; 
    SkinnedMeshRenderer SkinnedMeshRenderer;
    //Mesh skinnedMesh;

    private void Awake()
    {
        SkinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
       // skinnedMesh = GetComponent<SkinnedMeshRenderer>().sharedMesh;      
    }

/*
   void Start () {
      blendShapeCount = skinnedMesh.blendShapeCount; 
    }
*/ 

    void Update () {
        mo = loudget.getvolume() * 5000;
        SkinnedMeshRenderer.SetBlendShapeWeight(8, mo);
    }
}

コメントアウト部分、動画で要らないかもなどと言った部分を含めて大部分ですが確認したところやはり不要でした。申し訳ありません。
音量を取得するプログラムから音量データを取得し、それをもとにモーフを操作するスクリプトです。
void Update 内、5000と記述した部分ですがここで取得した音量に倍率をかけています。
取得した音量は(私の環境では)非常に小さい値(0.001付近)になっています。これに対してunityのモーフ制御値は0~100なので大きく倍率をかける必要があります。使用する際は各自で調整してください。
その下、SetBlendShape後の( )内ですが、前の8がモーフ番号を、後ろは代入するモーフの値を示します。
f:id:TellerG:20180303192402p:plain
モーフ番号について、1からではなく0から数えます。注意してください。

コンポーネントをアタッチする場所

音量取得

f:id:TellerG:20180303192602p:plain
取得したい音声を流すAudioSourceのインスペクタにアタッチします。

顔モーフ制御

f:id:TellerG:20180303192601p:plain
モーフの登録されたパーツにアタッチします。

以上でなんちゃって口パクが完成する…ハズです。

オマケ

今回はモーフ操作を例に挙げましたが要は音量の数字を入力する先次第で何でもできます。
例えば顎の開度をボーンで制御している場合は

this.transform.localEulerAngles = new Vector3( vol*x,0,0 )

などのような方法が考えられます。
またスピーカーなどのスケールを

this.transform.localScale = new Vector3(vol *x+1, vol *x+1,vol *x+1);

のようにして変化させればスピーカーの振動、倍率を大げさにすればアニメっぽいスピーカー表現(伝われ)が考えられます。

私が動画で使用しているものとしては、私のエンブレムの明滅にも利用しています。

    public float ch=0, cs=1, cv=0.5F;

    private Renderer _renderer;

    void Start()
    {
        _renderer = GetComponent<Renderer>();
    }
    void Update () {
        cv=loudget.getvolume()*5+0.4F;
        _renderer.material.SetColor
            ("_EmissionColor", UnityEngine.Color.HSVToRGB (ch, cs, cv));

以上、拙いながらも私の考えが皆様のお役に立てれば光栄でございます。