Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
22
Help us understand the problem. What is going on with this article?
@decchi

UniVRMのVRMBlendShapeProxyで表情アニメーション処理を共通化する

More than 3 years have passed since last update.

はじめに

2018/4/16にドワンゴさんからVRM及びUniVRMが公開されました。
詳細は公式のgithubを参照してください(とても丁寧にまとめられているので基本的なことはここを読めば大丈夫だと思います。)
VRMはVRアプリケーション向けの人型3Dアバター(3Dモデル)データを扱うためのファイルフォーマットであり、UniVRMはUnity向けのVRMファイルの読み書きを行うC#による標準実装とあります。
さて、UniVRMはUnity向けのVRMファイルの読み書きを行うC#による標準実装とあるように以下のコンポーネントが提供されています。

  • モデル情報
  • BlendShape
  • 一人称視点
  • 視線制御
  • 揺れモノ

つまり、VRMのセットアップ済モデルであれば上記の情報が共通の処理で取得できるということになります。便利です。
本記事ではUniVRMにおけるBlendShapeの操作方法について解説したいと思います。

環境

  • Unity2017.4.0f1
  • UniVRM-0.30

UniVRMからBlendShapeが取得できなかったら

そもそもUniVRMでBlendShapeを取得することの何が便利なのでしょうか。
下の画像はリップシンクによく使うOVRLipSyncのOVRLipSyncContextMorphTargetスクリプトのインスペクタです。
image.png

Visime To Blend Targetsの10~14にあ~おのShape Keyを設定するのですが、モデル毎にSkinned Mesh Rendererの名前も場所もバラバラ、またShape Keyの順番もバラバラなので、これを設定するときはモデルの構造を熟知しないと設定できません。色々なモデルを扱おうとすると辛い。。。(設定法については凹みさんの記事)参照
そこでUniVRMのVRMBlendShapeProxyを通してShape Keyを取得し、操作するというのが本記事のテーマです。

UniVRMからBlendShapeを操作する

今回はToggleで表情(「あいうえお」、「喜」、「哀」)を操作する簡単なスクリプトを作成しました。

FaceAnimation.cs
using UnityEngine;
using UnityEngine.UI;
using VRM;

public class FaceAnimation : MonoBehaviour
{

    private VRMBlendShapeProxy proxy;
    public GameObject model; // VRMモデルのオブジェクトを設定
    public Toggle a;
    public Toggle i;
    public Toggle u;
    public Toggle e;
    public Toggle o;
    public Toggle egao;
    public Toggle komari;


    // Use this for initialization
    void Start()
    {

    }

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

        // VRMBlendShapeProxyはUpdateが始まってからでないと取得できない
        if (proxy == null)
        {
            proxy = model.GetComponent<VRMBlendShapeProxy>();
        }
        else
        {

            // あ
            if (a.isOn)
            {
                proxy.SetValue(BlendShapePreset.A, 1f);
            }
            else
            {
                proxy.SetValue(BlendShapePreset.A, 0f);
            }

            // い
            if (i.isOn)
            {
                proxy.SetValue(BlendShapePreset.I, 1f);
            }
            else
            {
                proxy.SetValue(BlendShapePreset.I, 0f);
            }

            // う
            if (u.isOn)
            {
                proxy.SetValue(BlendShapePreset.U, 1f);
            }
            else
            {
                proxy.SetValue(BlendShapePreset.U, 0f);
            }

            // え
            if (e.isOn)
            {
                proxy.SetValue(BlendShapePreset.E, 1f);
            }
            else
            {
                proxy.SetValue(BlendShapePreset.E, 0f);
            }

            // お
            if (o.isOn)
            {
                proxy.SetValue(BlendShapePreset.O, 1f);
            }
            else
            {
                proxy.SetValue(BlendShapePreset.O, 0f);
            }

            // 笑顔
            if (egao.isOn)
            {
                proxy.SetValue(BlendShapePreset.Joy, 1f);
            }
            else
            {
                proxy.SetValue(BlendShapePreset.Joy, 0f);
            }

            // 困り顔
            if (komari.isOn)
            {
                proxy.SetValue(BlendShapePreset.Sorrow, 1f);
            }
            else
            {
                proxy.SetValue(BlendShapePreset.Sorrow, 0f);
            }
        }
    }
}

ここでのポイントはUpdate関数内でproxyを設定しているところです。現在の仕組みだとUpdateが走ってからでないとproxy.SetValue()で操作できません。(さらに正確にいうとVRMBlendShapeProxy内部のBlendShapeMergerのインスタンスが設定されないと操作できない)

    void Update()
    {

        // VRMBlendShapeProxyはUpdateが始まってからでないと取得できない
        if (proxy == null)
        {
            proxy = model.GetComponent<VRMBlendShapeProxy>();
        }

VRMBlendShapeProxyの取得さえできてしまえばあとはSetValue()でBlendShapeの値を変更できます。(値の範囲は0f~1fです)

proxy.SetValue(BlendShapePreset.A, 1f);

動かしてみる

今回はUnityちゃんをVRMにセットアップして試してみます。(© Unity Technologies Japan/UCL)
公式を参考に「あいうえお」と「喜」に笑顔、「哀」に困り顔をセットアップしました。(マテリアル周りの設定は割愛しています)
あとはシーンをセットアップして実行してみます。
image.png

実行結果

しっかり動いてくれました!
ダウンロード (1).gif

モデル変更

さらに応用(というかこれがやりたかった)としてモデルの変更をやってみます。
変更するモデルはニコニ立体ちゃんをお借りしました。
http://3d.nicovideo.jp/works/td32797

VRMファイルをインポートしてできたプレハブをシーンに配置してFaceAnimation.csのmodelにインスペクタに設定するだけで・・・
ダウンロード2.gif

ちゃんと動いてくれました。モデル変更も数ステップで行けますね!

終わりに

まだ公開されたばかりでVRMに対応したモデルは少ないですが、今後VRMが普及していくと簡単にモデルを入れ替えて共通の動作をさせることができます。モデルのセットアップは簡単なので、自作モデルがある方は是非作ってみてください!あとプログラマの方はVRMのAPIに対応した処理を作っておくと幸せになれるかもですね。

22
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
decchi
なんだかんだで大規模開発ばかりやってきたが、縁あってVR/AR界に足を踏み入れる。 Java,Oracle,Javascript,SVF,JP1とか触ってきました。 このアカウントで発信する内容は個人検証に基づくものであり、現在所属する会社の公式見解を示すものではありません。
tis
創業50年超のSIerです。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
22
Help us understand the problem. What is going on with this article?