トマシープが学ぶ

Unity/VR/AR/デザイン好きのミーハー 記事内容は自分用のメモです

モーフアニメーションを再生する方式のリップシンク【Unity/VRM】

アニメーション再生方式のリップシンク

NEOKETでのリップシンクは音声を検出したら口のモーフと体のアニメーションが再生されるという方式でした(VRではどうだったんだろう?)

あとアバターの上にしゃべっているマークも出てて分かりやすくて良かったですね。

f:id:bibinbaleo:20210210134421p:plain

こういう方式は初めて見ました。正確なリップシンクにしないという方法もあるのか~

 

でもそれって、モーフ名が同じじゃないと用意したアニメーションはできないのかな?

VRM共通のやつでできるのかな?

なんかVroidStudioと同じシェイプキーじゃないと動かない情報も

やってみる!

こちらの記事を参考に、VRMで共通で設定されているBlendShapeのパラメーターの数字を変えて簡易的なアニメーションを作れました。

qiita.com

スクリプトからBlendeShape変更

また変わってた。SetValueの中にCreateFromPresetというのが推奨だって。

proxy.SetValues(new Dictionary<BlendShapeKey, float>
{
    {BlendShapeKey.CreateFromPreset(BlendShapePreset.A), 1f}, // [0, 1] の範囲で Weight を指定
    {BlendShapeKey.CreateFromPreset(BlendShapePreset.Joy), 1f}, // システム定義の表情は enum で指定
    {BlendShapeKey.CreateUnknown("USER_DEFINED_FACIAL"), 1f}, // ユーザ定義の表情は string で指定
});

vrm.dev

昔はImmediatelySetValueが推奨。さらに昔はSetValueだった。

blendShapeProxy.(BlendShapePreset.A, 0~1の数値);

bibinbaleo.hatenablog.com

Updateでやるなとか突っ込みどころはあるけど一旦動く。

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

public class PresetLipSync : MonoBehaviour
{
    private VRMBlendShapeProxy _proxy;

    [Range(0, 1)] public float _A_Value;
    void Update()
    {
        DoLipSync();
    }
    private void DoLipSync()
    {
        if (_proxy == null)
        {
            _proxy = GetComponent<VRMBlendShapeProxy>();
        }
        else
        {
            _proxy.SetValues(new Dictionary<BlendShapeKey, float>
                {
                    {BlendShapeKey.CreateFromPreset(BlendShapePreset.A), _A_Value}, // [0, 1] の範囲で Weight を指定
                });
        }
    }
}

_A_Valueの値を0~1の範囲でアニメーションなどで変えたら口パクする

 

これをVRMに貼る

f:id:bibinbaleo:20210212100316p:plain

アニメーション作る

Animationウィンドウを開く

VRMを選択した状態でCreate。名前を付けて保存

f:id:bibinbaleo:20210212100609p:plain

AddPropertyからさっき作ったスクリプトのValueを+

f:id:bibinbaleo:20210212100544p:plain

0,1,0,1って値変えていく。キーを選択して値を変えるだけじゃなく、線もその時間のところに移動させないと値が変わらない気がする

f:id:bibinbaleo:20210212101120p:plain

遷移Animator作る

VRM選んだ状態でAnimationClip作ったら勝手にモデル名と同じAnimatorが作成されてた。でも使いにくいから新しく作った

f:id:bibinbaleo:20210212101721p:plain

これをVRMに付けて再生すると、例の沈んだ体になった状態でパクパクする

f:id:bibinbaleo:20210212101724p:plain

これになるのってアニメーションがHumanoidじゃないからだと思うけど、パラメーターだけのアニメーションをHumanoidにするのってどうするんだ??

レイヤー設定

AvatarMaskというのを使えばできた!と思ったら別にAvatarMaskはいらなかった。

レイヤーを分ければいいだけだった。

でもメモしておく

gametukurikata.com

Create>AvatarMask作成。顔だけ緑にする

f:id:bibinbaleo:20210212103230p:plain

Animatorで新しいレイヤー作ってさっきのマスクを設定Weightを1にする

f:id:bibinbaleo:20210212103155p:plain

新しいレイヤーのほうにリップシンクのアニメーション。

f:id:bibinbaleo:20210212112032p:plain

BaseのほうはWalkとかIdelとかデフォルト用のアニメーションを設定しておく。

f:id:bibinbaleo:20210212103604p:plain

これで歩きながら口パクできた!!

f:id:bibinbaleo:20210212103539p:plain

トリガー設定

今のままだとずっとパクパクするので、トリガーをOnにした時だけ口パクするようにする

まずParameterを作って置く

f:id:bibinbaleo:20210212105416p:plain

LipSyncレイヤーのほうに空のStateを作り、そこからリップシンクへ遷移させる

f:id:bibinbaleo:20210212105335p:plain

遷移の入るほうはHasExitTimeのチェックを外し、即遷移するようにする。あとConditionsでトリガー設定

f:id:bibinbaleo:20210212105527p:plain

出ていくほうはHasExitTimeにチェックを入れる。口パクアニメーションが終わったら自動で出ていく。

f:id:bibinbaleo:20210212105555p:plain

detail.chiebukuro.yahoo.co.jp

 

これでTriggerをスクリプトやボタンなどからオンにしたら、口パクアニメーションが再生される~~~やったー!!

f:id:bibinbaleo:20210212105208p:plain

f:id:bibinbaleo:20210212110442g:plain

Trigger

Triggerのオンはスクリプトだと

AnimatoeController.SetTrigger("トリガー名");

Animator-SetTrigger - Unity スクリプトリファレンス

ーーー

とりあえずボタンから簡易的にやる方法だとこの設定でノンスクリプトでできる

f:id:bibinbaleo:20210212105858p:plain

口パク回数

作ったアニメーション自体は2回口パクするやつだけど、Animatorの出ていくときのTransition設定で、ExitTimeを増やして再生回数を増やせば増える。

f:id:bibinbaleo:20210212110240p:plain

最後に

アニメーション分からない・・・でも新しいこと知れた。アバターマスクは今回は必要なかった。