表情モーションについて

最終更新: 2023年1月26日

表情モーションとは

表情モーションは通常のモーションとは別に、表情用の値を現在の状態に対して相対的に設定するSDKの機能です。
モーションマネージャーのフェード機能を利用して、現在の表情から再生された新しい表情の設定へと時間をかけて変化させることができます。
また、モーションにはない機能として計算方法を指定できるという点があります。

ACubismMotionクラスを継承しているので、通常のモーションと同様にCubismMotionManagerクラスで管理できます。
表情データ(.exp3.jsonファイル)の作成は、.motion3.jsonファイルをCubism Viewer (for OW)に表情用モーションとして読み込ませ、変換して出力する必要があります。
.motion3.jsonファイルを読み込ませたときはモーションの初期値が表情の目標値として設定されます。
「アニメーションビューで表情を作成 」
「表情の設定と書き出し」

表情は、モーションと比較すると以下の違いがあります。

  • 時間経過に基づく値の変化がありません。
  • パーツに対して影響することができません。
  • 計算方法(加算、乗算、上書き)の指定ができます。

インスタンスの作成(.exp3.jsonの読み込み)

表情はACubismMotionクラスから派生したCubismExpressionMotionクラスを使用して再生させます。
CubismExpressionMotionインスタンスを生成するには、Native(C++)のCubismExpressionMotion::Create関数、Web(TypeScript)、JavaのCubismExpressionMotion.create関数を使用します。

// C++
	csmInt32 len = _modelSetting->GetExpressionCount();
    for (csmInt32 i = 0; i < len; ++i)
    {
        csmString name = _modelSetting->GetExpressionName(i);
        csmString path = _modelSetting->GetExpressionFileName(i);
        path = _modelHomeDir + path;

        buffer = CreateBuffer(path.GetRawString(), &size);
        ACubismMotion* motion = CubismExpressionMotion::Create(buffer, size);

        if (_expressions[name] != NULL)
        {
            ACubismMotion::Delete(_expressions[name]);
            _expressions[name] = NULL;
        }
        _expressions[name] = motion;

        DeleteBuffer(buffer, path.GetRawString());
    }
// TypeScript
	let len: number = _modelSetting.getExpressionCount();

    for(let i: number = 0; i < len; ++i)
    {
        let name: string = this._modelSetting.getExpressionName(i);
        let path: string = this._modelSetting.getExpressionFileName(i);
        path = this._modelHomeDir + path;

        fetch(path).then(
            (response) => 
            {
                return response.arrayBuffer();
            }
        ).then(
            (arrayBuffer) =>
            {
                let buffer: ArrayBuffer = arrayBuffer;
                let size: number = buffer.byteLength;

                let motion: ACubismMotion = CubismExpressionMotion.create(buffer, size);

                if(this._expressions.getValue(name) != null)
                {
                    ACubismMotion.delete(this._expressions.getValue(name));
                    this._expressions.setValue(name, null);
                }

                this._expressions.setValue(name, motion);

                deleteBuffer(buffer, path);
            }
        );
    }
// Java
    final int count = modelSetting.getExpressionCount();

    for (int i = 0; i < count; i++) {
        String name = modelSetting.getExpressionName(i);
        String path = modelSetting.getExpressionFileName(i);
        path = modelHomeDirectory + path;
      
        byte[] buffer = createBuffer(path);
        CubismExpressionMotion motion = loadExpression(buffer);
      
        if (expression.get(name) != null) {
            expressions.remove(name);
        }
        expressions.put(name, motion);
    }

表情管理用のインスタンスの作成

表情の適用は、CubismMotionManagerクラスを使用します。
しかし、通常のモーションと効果を併用させるため、別のインスタンスとして作成する必要があります。

// C++
    CubismMotionManager* motionManager = CSM_NEW CubismMotionManager();

    CubismMotionManager* expressionManager = CSM_NEW CubismMotionManager();
// TypeScript
    let motionManager: CubismMotionmanager = new CubismMotionManager();

    let expressionManager: CubismMotionManager = new CubismMotionManager();
// Java
    CubismMotionManager motionManager = new CubismMotionManager();

    CubismMotionManager expressionManager = new CubismMotionManager();

表情の再生とその仕組み

モーションの再生と同様に、表情の再生には管理クラスに対して再生命令をだします。

// C++
    ACubismMotion* motion = _expressions[expressionID];//loaded CubismExpression
    if (motion != NULL)
    {
        expressionManager->StartMotionPriority(motion, false, PriorityForce);
    }
// TypeScript
    let motion: ACubismMotion = _expressions[expressionID];//loaded CubismExpressionMotion
    if(motion != null)
    {
        expressionManager.startMotionPriority(motion, false, PriorityForce);
    }
// Java
    ACubismMotion motion = expressions.get(expressionID); // loaded CubismExpression
    if (motion != null){
        expressionManager.startMotionPriority(motion, LAppDefine.Priority.FORCE.getPriority());
    }

表情の各パラメータの指定には計算方法の指定が可能です。
加算、乗算、上書きの三つの計算方法があります。

加算

計算方法の指定が”Add”と示されたとき、または計算方法の指定がない場合この方法が選ばれます。
適用時のパラメータの値にそのまま.exp3.jsonファイルに示された値が加算されます。
モーションではあまり操作されないパラメータに対してや、
そのままスライドさせて影響させたいときに使用します。
Cubism Viewer (for OW)で値を書き出すときにはパラメータの初期値から設定値への差分が設定されます。

乗算

計算方法が”Multiply”と示されたときに選ばれます。
適用時のパラメータの値にそのまま.exp3.jsonファイルに示された値が乗算されます。
適用後の加算、上書きにはこの乗算が影響しないことに注意してください。
モーションの動きをそのまま増幅したり、縮小させたりするときに便利です。
Cubism Viewer (for OW)で値を書き出すときには設定値がそのまま設定されます。
-30~30のモーションに30を掛けると-900~900のモーションになってしまうので、
モーションと表情の値の組み合わせには注意して設定をおこなってください。

上書き

Cubism Viewer (for OW)では設定できませんが、計算方法を”Overwrite”と指定することで利用が可能となります。
適用時のパラメータの値を無視し、そのまま値が上書きされます。
モーションなどの動きを無視したい場合に有効です。

演算方式の違いによる表現の違い

両目の開閉を設定値は0.4にして、それぞれAdd、Multiply、Overwriteの表情を適用した例です。
Addでは毎描画ごとに-0.6されるため、すぐに開閉の下限に達して下限の値へと上書きされるので、しばらく目が閉じたままになります。
Multiplyでは波形全体に値が乗算されるため、まばたきがきれいに動作しています。
Overwriteではまばたきが無視されまばたきしていません。

モーションなどと組み合わせたとき、表情の計算一つでニュアンスを変えることができます。

表情の適用

モデルへの適用は管理クラスのNative(C++)のCubismMotionManager::UpdateMotion関数、Web(TypeScript)、JavaのCubismMotionManager.updateMotion関数やNative(C++)のMotionQueueManager::DoUpdateMotion関数、Web(TypeScript)、JavaのCubismMotionQueueManager.doUpdateMotion関数で行います。

// C++
	expressionManager->UpdateMotion(_model, deltaTimeSeconds);
// TypeScript
	expressionManager.updateMotion(_model, deltaTimeSeconds);
// Java
    expressionManager.updateMotion(model, deltaTimeSeconds);

モーションや表情、他のパラメータ操作要素の計算順は表現に大きく影響します。

「パラメータについて:パラメータの計算順序の重要性」

適用の順番には十分注意してください。

この記事に関するご意見・
ご要望をお聞かせください。