凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

Unity でリアルタイムにリップシンクする MMD4Mecanim LipSync Plugin を作ってみた

はじめに

前回(Oculus Rift をかぶって VR の世界でおしゃべりしてきた - 凹みTips)、MMD4Mecanim を適用したモデル上でリップシンクを行うプラグインの紹介をしました。本エントリでは、前回省略してしまった利用方法や仕組みの解説をしていきたいと思います。

デモ

歌をリップシンクさせたデモになります。曲は、しましまPさんの「LIFE -きみそらいのち-」を利用させて頂いています。

前回の会話をしてみたデモは以下になります。

できること

主に出来ることは以下の 3 種類になります。

マイク入力に関しては現状余りうまくいっていないので、調整中です。。

動作環境

  • Mac OS X 10.9 / Windows 8
  • Unity 4.3.1f1
    • 4.2 ではオーディオ周りのバグで Mac 環境下でうまく動きません。

セットアップ

  1. 上記 github のリンクから「Download ZIP」をクリックして一連のファイルをダウンロードします。
  2. MMD4Mecanim-LipSync-Plugin.unitypackage」を開いて、現在の Unity のプロジェクトへインポートします。
    • この際、音声合成による発話を行わない場合は「LipSync/*」以外のものはインポートしなくても構いません。
  3. MMD4Mecanim によって作成したモデルに「LipSync > MMD4M_LipSync」をアタッチします。
  4. 音声合成による発話を使う際は、「Edit > Project Settings > Player」の「Other Settings > Optimization > Api Compatibility Level」を「.NET 2.0 Subset」から「.NET 2.0」へと変更して下さい。


これで準備完了になります。次の項で説明するようにエディタから操作することが出来ます。

オーディオファイルに合わせてリップシンク

ユースケース

冒頭のデモ相当の内容になります。以下の様なユースケースを想定しています。

  • 歌をリップシンクさせて歌わせる
  • 事前に生成しておいた文章を読み上げる Wave ファイルを再生する
エディタからの再生方法

再生のさせ方は 3 種類あります。

  1. Play Voice Sound > Audio File > Select」からファイラを開き、Wave ファイルを指定して「Play」を押下
    • 内部的には、WWWfile:// プロトコル経由で読み込んでいます。
  2. Play Voice Sound > Audio File」内に Resources 以下のファイルを指定して「Play」を押下
    • Resouces/MeiVowel/a.wav であれば「MeiVowel/a」と入力します。
    • 内部的には、Resources.Load で読み込んでいます。
  3. Play Voice Sound > Audio Clip」に再生したい Audio Clip を指定して「Play」を押下

キャリブレーション

母音に合致した口の形になるように、それぞれの声に対してキャリブレーションを行う必要があります。Resources/MeiVowel/a〜o.wav に同梱したように、「あ」〜「お」の母音を発音するモノラルのファイルを用意して下さい。歌の場合はボーカルのみの素材から audacity などを利用して切り取ると良いと思います。

そしてこれらを「Callibration > Each Vowel Data」に指定して「Callibration」を押下します。この際、「LPC Parameters > Typical Formant Frequencies for Each Vowel」がいい感じにばらついていることを確認して下さい。ばらついていない際は、「LPC Parameters > LPC Order」および「LPC Parameters > Sample Num」の数値を調整します。前者は 24 〜 48 くらい、後者は 256 〜 1024 の範囲くらいだと思います。冒頭のデモでは 24 / 256 にしています。

おまけ解説:フォルマントについて

声は色々な周波数の波が重なって出来ています。この波を複雑に組み合わせたものが、あ〜おの母音になっています。そしてそれぞれの母音は周波数の組み合わせ具合に特徴を持っており、大体この付近の周波数の成分が多いみたいな形になっています。

この山の 1 番目と 2 番目の周波数を第 1 フォルマント、第 2 フォルマントと呼び、例えば「あ」なら第 1 フォルマントは他の母音よりも高い 1000 kHz 付近で、第 2 フォルマントは他と比べると平均的な 1500 〜 2500 kHz くらいに位置する、といった形になっています。現在解析している音声が、この山のどのパターンに近いかを見てあげれば、何の母音をしゃべっているか判別できるという仕組みなわけです。

キャリブレーションでは、入力された音ファイルから平均のフォルマントを割り出して、それぞれのパターンとしてセットしています。この値は(本当は変わってほしくないのですが)今回の手法ではパラメタに大きく依存するので、現状良い感じに判別できるように微調整が必要になってしまっています。

スクリプトからの利用
var lipSync = GetComponent<MMD4M_LipSync>();
lipSync.Play("file://path/to/your/sound.wav"); // WAVE ファイルを再生
lipSync.Play("MeiVowel/a");                    // Resource 内のファイルを再生
lipSync.Play(audioClip);                       // AudioClip を再生
再生位置

Play Voice Sound > Playing Position」を指定すると、指定した場所から 3D サウンドを発する形になります。モデルをたどって舌を見つけてそれをドラッグ&ドロップして指定すると口からしゃべっている形になります。指定しない場合は (0, 0, 0) から音を発します。

文字列を発話しながらリップシンク

ユースケース
  • いちいち喋る言葉に対応した Wave ファイルを作るのは面倒なのでいい感じに喋って欲しい
  • 自由な文章を動的に喋らせたい(前回の記事参のような形)
利用しているソフト
エディタからの再生方法

Play Voice Sound > Word」に文字列を入力し、「Talk」を押下します。
※ 現状、開始時にプチフリーズします。原因は調査中です。。

スクリプトからの利用
var lipSync = GetComponent<MMD4M_LipSync>();
lipSync.Talk("ほげほげほげほげ"); // 喋らせたい言葉を指定
その他

その他の設定に関しては、「オーディオファイルに合わせてリップシンク」と同じです。

マイク入力に合わせてリップシンク(調整中)

エディタからの利用方法

少し込み入っているので動画にしました。

Callibration > Record / Stop」をそれぞれの母音に対して行って「Callibration」を押下します。その後、「use mic」にチェックを入れると声に合わせて喋ります(現状精度はかなり悪いです)。なお、ゲーム実行時しかキャリブレが出来ないのですが、ゲームが終わると値がリセットされてしまうので、一番上の「MMD4M_Lip Sync (Script)」上を右クリックして「Copy Component」をしておいてから、終了後に「Paste Component Value」してください。

その他

その他の設定に関しては、「オーディオファイルに合わせてリップシンク」と同じです。

その他の設定


Morph Speed

MMD4MecanimMorphHelper のモーフィングのスピードを指定します。数値が小さいほどすぐ切り替わるため、子音による無音が取りやすくなる一方、パカパカして人間っぽくない感じになります。数値を大きくするとフィルタが掛かった動きになり、子音が見えにくくなりますが、自然な形になります。

Max Morph Weight

1.0 が既定のモーフィングの最大値です。口をもっと大きく開けて欲しい場合には 1.0 以上の値を指定します。が、大きくし過ぎると大変残念なことになるので 1.0 〜 1.2 くらいが良いと思います。

Morph Names for Each Vowel

「あ」〜「お」以外の口の形(ヮとか△とか)にしたいときに名前を書き換えます。

Minimum Volume

無音と判断する音のしきい値を指定します。

Normalized Volume

口の大きさが Max Morph Weight となるしきい値を指定します。Minimum Volume と同じ値にすると、はっきりパクパクします。Minimum Volume と差をつけると、小声の時は口の開きが小さくなります。

Lip Sync Delay Time

リップシンクの遅延時間を指定します。通常、口の動きに遅れて声が出るので、ある程度遅らせた値を指定したほうが自然なリップシンクになります。0.15 くらいが丁度良いと思います。

Result Outputter

GUIText を指定すると、現在、どの母音と判定されているか画面に書き出します。

おわりに

Unity 上でしか出来ないような表現や、スクリプトを活用して手軽にカメラを動かしたりと、Unity を活用して他とは違う独特な PV とか出来そうですね。その際に、本プラグインが一役買ってくれれば幸いです。
解析の仕組み(オーディオ周りの取り扱い)や Streaming Assets を活用した外部 exe との連携、また冒頭の動画にあったについてはまた別途記事を書きます。