0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Three-VRMで組み合わせて表情を登録する(Custom Expression)

Last updated at Posted at 2024-10-05

概要

Three-VRMでプリセットの表情ではなく、パーツごとに組み合わせた表情(眉毛、目、口などでそれぞれ異なった表情にする)を反映させてみます。プリセットの表情は特に設定なしに使うことができますが、パーツごとに変える場合はCustom Expressionとしての登録が必要となります。

Unityなどでブレンドシェイプを作成することで実現する方法もあるみたいですが(試してませんが)、ここでは、JavaScriptの実行時にプログラム的に設定し使用します。

動作確認

  • VRoidStudio 1.29. 1 -- VRMファイルのエクスポート
  • Three-VRM 3.1.2
  • Firefox 131

実装

プリセットの使用

Three-VRMでブラウザ上でVRMを非常に簡単に扱うことができますが、expressionManager経由で表情を反映させることができます。以降のコードでは、変数vrmVRMオブジェクトとします。VRMファイルの読み込みはThree-VRMのサンプルスクリプト等を参照してください。ここで扱うコードはVRMオブジェクトがある前提です。

Three-VRM 2.0.0より前はblendShapeProxyでしたが、2.0.0以降はexpressionManager経由で表情を操作するようです。

// プリセット名の確認
vrm.expressionManager.expressionMap
// Object { happy: {…}, angry: {…}, sad: {…}, relaxed: {…}, surprised: {…}, aa: {…}, ih: {…}, ou: {…}, ee: {…}, oh: {…}, … }

// プリセットの使用
vrm.expressionManager.setValue("relaxed", 0.8);

vrm.expressionManager.setValue()はプリセットだけではなく、今回登録するCustom Expressionにも使うのですが、登録する前はプリセットしかありません。

カスタム表情の追加

上記のようにプリセットの表情(happy, angry, sad, relaxed, surprisedおよび口の形)はそのまま使えるのですが、VRoidStudioのようにそれぞれのパーツの表情を組み合わせたいことは多いと思います。その場合、VRMExpressionオブジェクトを作成し、expressionManager.registerExpression()を使って追加登録します。

なお、この部分はThree-VRM 3.1.2のpackages/three-vrm-core/src/expressions/VRMExpressionLoaderPlugin.tsの143行目付近のコードを参考にしています。そこで表情の登録をしているので、一連の流れを追えばさらに詳細が理解できると思います。

// カスタム表情の追加登録
const expressionName = "smile";        // 表情の登録名
const targetName     = "Fcl_MTH_Fun";  // 反映させるターゲット
const targetWeight   = 0.8;            // ウェイト

const expression = new VRMExpression(expressionName);
vrm.scene.add(expression);

// MorphTargetBind.primitivesに登録するのはFaceグループのSkinnedMesh
const primitives = [...vrm.scene.getObjectByName("Face").children];

// FaceグループのSkinnedMesh#morphTagetDictionaryから、目的のmorphTargetIndexを得る
// FaceグループにはFace_(merged)などのSkinnedMeshが登録されている
const morphTargetDictionary = vrm.scene.getObjectByName("Face").children[0].morphTargetDictionary;

// バインドする
// 他のパーツも足していくことができる
expression.addBind(
    new VRMExpressionMorphTargetBind({
        primitives,
        index: morphTargetDictionary[targetName],
        weight: targetWeight,
    })
);

// Expressionを登録する(customExpressionMapに追加される)
vrm.expressionManager.registerExpression(expression);

このコード片では、Fcl_MTH_Funすなわち、口の「楽しい」にウェイトをかけています。VRMExpressionを初期化する際に渡す名前でexpressionManager.customExpressionMapに登録されます(ここではsmile)。ここではFcl_MTH_FunのみをaddBind()していますが、addBind()は複数できるので、例えばFcl_BRW_FunFcl_EYE_Spreadなどを組み合わせることができます。使用できるターゲット名は、このコード中のvrm.scene.getObjectByName("Face").children[0].morphTargetDictionaryで得ることができます。

登録した表情を使うのはプリセットと同様です。

vrm.expressionManager.setValue("smile", 1.0);

このようにすることで、様々な表情を簡単に作ることができます。

参考

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?