LoginSignup
17
15

More than 3 years have passed since last update.

UnityでVtuber用の表情制御リグを作る

Last updated at Posted at 2019-04-30

自己紹介

こんにちはゆずです。@Yuzu_Unity

はじめに

Vtuberの表情制御の仕方はいくつかあると思いますが
自分なりの一番いいシステムを考えてみました。
リアルタイム&あとから修正にも対応

まず欲しい機能としては
OVRリップシンク
手付(コントローラーでキャプチャも含む)
iPhone等でのフェイシャルトラッキング(キャプチャー含む)

また、それらのブレンド具合の調整・レコード機能・Timelineでプレイモード外での表示

ここまであれば他に望むものは無いかなーと思います。

設計

基本的には3DCGのブレンドシェイプ式によるフェイシャルリグを参考に作成してます。

FacialRigのパラメータのブレンド具合をFacialWeightで管理します。
配列が使えないため(レコードシステム参照)かなり面倒ではある
Untitled Diagram (2).png

レコードシステム

いくつかの記事を見ているとなぜか、jsonで保存していたりなど
自作していることが多いのですが、処理も重かったりとなかなか使いづらいです。

※Unityには標準でアニメーションクリップへのレコード機能があるんです!!(Editor専用)
GameObjectRecorder (※UnityのバージョンによりAPIが異なるため公式リファレンス参照)
https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Animations.GameObjectRecorder.html
これを知るとみんな乗り換えそ~(棒)
もちろん処理の負荷もなく、フレームでの差分がないとキーフレームも打たれません。

しかし…ちょっと使いづらいんですよね
コンポーネントをキャプチャーするとその差分全部をキャプチャーしてしまい、
いらないところの排除ができない…(やり方あったら教えてほしい…)
なので別でキャプチャー専用コンポーネント(C#クラスを作成します)
Unityのアニメーションでスクリプトの変数を動かしたことがある人はわかると思うのですが
キーフレームが打たれる条件は次のとおりです。

・シリアライズされていること(publicもしくは[SerializeField])
・配列やリストではないこと…。 配列使えないのがとてもめんどくさい…
(エディタ拡張を使ってもいい解決ができない…キーフレームが普通に打てなくなったりします)

BlendShapeの全パラメータ等キーフレームを打ちたい数分、変数を置きます。
また別の配列に入れ直します。

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

//プレイモード外でも実行
[ExecuteInEditMode]
public class FacialRig : MonoBehaviour
{
    [Range(0, 100)]
    public int a, i, u, e, o, blink;

    [HideInInspector]
    public int[] facilValue=new int[6];


    void Update()
    {
        facilValue[0] = a;
        facilValue[1] = i;
        facilValue[2] = u;
        facilValue[3] = e;
        facilValue[4] = o;
        facilValue[5] = blink;
    }
}

あとはレコード用のスクリプトを用意して完成です。
プレイ時レコードスタート

RecordFacialRig.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//忘れずに
using UnityEditor.Animations;
public class RecordFacialRig : MonoBehaviour
{
    public AnimationClip clip;
    private GameObjectRecorder gameObjectrecorder;

    void Start()
    {
        // Animatorコンポーネントをつけるオブジェクト
        gameObjectrecorder = new GameObjectRecorder(gameObject);

        /* ここにバインドしたいコンポーネント記述(今回はFacialRig
        このスクリプトがアタッチしているオブジェクトからGetComponentを行う)*/
        gameObjectrecorder.BindComponentsOfType<FacialRig>(gameObject, true);
    }

    void LateUpdate()
    {
        if (clip == null)
            return;

        // フレームごとにキーフレームを打つ
        gameObjectrecorder.TakeSnapshot(Time.deltaTime);
    }

    void OnDisable()
    {
        if (clip == null)
            return;

        if (gameObjectrecorder.isRecording)
        {
            // アニメーションクリップに保存
            gameObjectrecorder.SaveToClip(clip);
        }
    }
}

以下はOVRLipSyncを編集しFacialRigにパラメータを流しそれをキャプチャーしたもの
image.png

設計をもとにFacialManagerスクリプトを作成

最後にFacialManagerでパラメータのブレンドを行い、メッシュへ適用します。
FacialRig.csのfacilValueを用い、FacialWeightのweightValueを乗算したものを
加算しClampを行うだけの簡単な作業なのでコードは省略
※[ExecuteInEditMode]は忘れないようにします。

FacialRigコンポーネントをTimelineに設置しキャプチャーした各種AnimationTrackを配置した図
キャプチャ.PNG

iPhoneX系による表情取得方法は後日記述

17
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
15