すぎしーのXRと3DCG

主にXR, Unity, 3DCG系の記事を投稿していきます。

【Unity】指のポーズをブレンドしてハンドジェスチャーを作ろう

f:id:tsgcpp:20200810193210p:plain

概要

今回は手の指を曲げるアニメーションを組み合わせてハンドジェスチャーの作ってみたいと思います。

UnityにはBlendTreeというアニメーションをブレンドする機能があります。
今回はそのBlendTreeと指のアニメーションを組み合わせることでハンドジェスチャーを実現したいと思います。

動作環境

動作確認可能なプロジェクトを記事の最後に記載します。

使用アセット

ポーズの用意

Blenderでモデルを読み込んで、以下のポーズ(BlenderではActions)を作成。

1ポーズに左右の手両方のキーフレーム登録をオススメします。
後述するAvatar Maskで左右の手のアニメーションを分離できます。

※ポーズの作り方については後述

ポーズの条件

  • 0フレーム目は デフォルトの状態
    • 0フレーム目は必ずデフォルト(曲げる前)の状態のキーフレームを登録すること
  • 1フレーム目は 対象の指を曲げた状態
    • 例えば "IndexFingerClosed" であれば、人差し指のみ曲げた状態

用意するポーズ

  • HandOpened (いわゆるパーのポーズ、デフォルトのポーズ)
  • ThumbClosed (親指のみ閉じたポーズ)
  • IndexFingerClosed (人差し指のみ閉じたポーズ)
  • MiddleFingerClosed (中指のみ閉じたポーズ)
  • RingFingerClosed (薬指のみ閉じたポーズ)
  • PinkyFingerClosed (子指のみ閉じたポーズ)

HandOpened

手がパーのポーズ、いわゆるデフォルトポーズ

f:id:tsgcpp:20200810155530p:plain

ThumbClosed, FingerClosed

5本の指それぞれを個別に閉じている状態のポーズを用意。

f:id:tsgcpp:20200810155651p:plain

※親指、中指、薬指、小指は省略

ポーズの簡単な作り方

Blenderをある程度触ったことがある人向けです。

以下の流れで、それぞれの指のポーズを作成できます。

  • 初めにグーのポーズを作る
  • グーのポーズから対象の指以外をデフォルトに戻す

グーから作ることによって、すべての指のポーズをブレンドした時にきれいなグーになると思います。

パーからグーを作る方法

Blender グーから一部の指をデフォルトに戻す

アニメーションをExport

以下の手順でBlenderからFbxを算出

  • Export対象のモデルを選択
  • File -> Export -> FBX(.fbx)
  • "Selected Objects"を有効にし、"Object Types"を"Armature"のみする
    • 今回はスケルトンポーズ(アニメーション)のみを出力したいため、メッシュは除外
  • Export FBX

f:id:tsgcpp:20200810135627j:plain

UnityでFBXをImport

HumanoidとしてImportして、AnimationをHumanoid向けに変換しましょう。

  • "Animation Type" を "Humanoid"に変更
  • "Apply"

f:id:tsgcpp:20200810143446j:plain

非ループ化

Loop Timeなどは無効のままにしてください。
ブレンド中におかしくなってしまいます。

Animation Clipから不要なキーフレームを削除

必須ではありませんが、HumanoidでImportするとすべてのMuscleのキーフレームが登録されてしまいます。
Animation Clipのサイズが削減できるので不要なキーフレームは削除しておきましょう。

  • HandOpened は指以外のキーフレームを削除
  • 各FingerClosedは対象の指以外のキーフレームを削除

f:id:tsgcpp:20200810174348j:plain
HandOpened のキーフレーム(修正後)

f:id:tsgcpp:20200810174438j:plain
IndexFingerClosed のキーフレーム(修正後)

Avatar Mask の作成

UnityではAvatar Maskを使ってアニメーションの適用範囲をマスクで制限することができます。

  • "Project"上で右クリック -> "Create" -> "Avatar Mask"
  • アニメーションはループさせない(Loop Time チェックボックスを オフ)
    • プレイ中に大変なことになります
  • 左右の手それぞれの Avatar Mask を作成

f:id:tsgcpp:20200810144122j:plain
左手用 Avatar Mask
f:id:tsgcpp:20200810144148j:plain
右手用 Avatar Mask

AnimatorControllerを作成

前置きが長かったですがいよいよ本題です。
これまで用意したAnimation(ポーズ)をブレンドするAnimationControllerを用意して、ハンドジェスチャーを作っていきます。

ブレンドの方針

  • AnimatorControllerのレイヤーを使用
  • "Blending" を "Additive" にし、ベースポーズからの加算によってポーズの組み合わせを実現

f:id:tsgcpp:20200810150053j:plain

簡単に言えば"パー" から"指を曲げるポーズ"を加算することで、ジェスチャーを実現する方針になります。

ベースポーズ用レイヤーを作成

  • レイヤーを追加
  • Weightを1, Maskに左手用Avatar Mask, BlendingをOverrideに設定
  • DefaultStateのアニメーションに "HandOpened" を指定

これでBase Layerの左手のアニメーションが常にパーに上書きされる形になります。

f:id:tsgcpp:20200810150734j:plain

加算用レイヤーを作成

レイヤーの作成

  • レイヤーを追加
  • Weightを1, Maskに左手用Avatar Mask, BlendingをAdditiveに設定
  • DefaultStateにBlendTreeを指定

f:id:tsgcpp:20200810151509j:plain

BlendTreeの設定

  • ParametersにCloseThumb_L, CloseIndex_L... の様に左手の指ごとのパラメータをfloatで用意
    • 右手の指の場合はCloseThumb_R, CloseIndex_R...
  • "BlendType" に "Direct" を指定
  • Motionを5つ追加し、各指のアニメーションとパラメータを指定

f:id:tsgcpp:20200810152457j:plain

動作確認

それでは作ったAnimatorControllerをユニティちゃんのAnimatorに入れて動作確認してみましょう!

www.youtube.com

うまくいきました!

Additive Reference Pose について

Blenderでアニメーションを作る際、「0フレーム目は デフォルトの状態」という条件を加えました。 実はこれ、"Additive Reference Pose"というものが関係しています。

Additive Reference Pose とは

平たく言えば「Additive(レイヤー)で使用する際にベースとなるポーズ」のことです。

残念ながら"Additive Reference Pose"の明確なドキュメントは見つかりませんでした。。。(知っている方いらっしゃいましたら教えてください!!!)

デフォルトのAdditive Reference Pose

AnimationUtility.SetAdditiveReferencePoseのページにこんな説明があります。

By default any animation clip used in an additive layer use the pose at time 0 to define the reference pose

つまり、"Additive Reference Pose"はデフォルトではそのAnimation Clipの0フレーム目のポーズになるということです。

これが 「0フレーム目は デフォルトの状態」という条件にした最大の理由になります。

余談:Additive Reference Pose を明示的に指定する方法

一応、Additive Reference Pose は明示的に指定する方法があります。

ただ、どれも扱いやすいとは言えないと個人的には思います。。。
ブレンド前提のAnimation Clip は素直にベースのポーズを0フレーム目に指定したほうが良いと思います。

FBXのImport時に指定

以下の方法を使用すると、同一Animation Clip内で0フレーム目以外を"Additive Reference Pose"として指定できます。

  • FBXをInspectorで確認し、"Animation"タブを開く
  • 下部に"Additive Reference Pose" のチェックボックスをオンにする
  • Pose Frameを指定

f:id:tsgcpp:20200810165228j:plain

Debug Inspectorで指定

実はDebug Inspectorにすると、Animation ClipのInspectorに"Additive Reference Pose"を指定する欄が表示されます。

  • InspectorをDebug化
  • "Additive Reference Pose Clip" と "Additive Reference Pose Time" を指定
  • "Has Additive Reference Pose"のチェックボックスをオン
    • オンにしていないと"Additive Reference Pose"が有効になりません

f:id:tsgcpp:20200810170930j:plain

AnimationUtility.SetAdditiveReferencePoseを使って指定

※個人的には非推奨

AnimationUtility.SetAdditiveReferencePose を使うことで指定できます。
別のAnimation Clipも指定可能です。

AnimationUtility.SetAdditiveReferencePose(targetClip, referenceClip, poseTime);

メソッド呼び出しの結果を確認したい場合は、前述したDebug Inspectorで確認して下さい。

また、以下のようなツールも作ってみました(プロジェクトにいれています)。
複数のAnimationClipでまとめて"Additive Reference Pose"を指定できます。

f:id:tsgcpp:20200810165859j:plain

ツールの注意点

Set/Reset を繰り返すと以下のようなエラーを吐くことがあります。
こうなるとUnityを再起動しないとうまく動作しません。。。

f:id:tsgcpp:20200810170254j:plain

原因不明なので何か知っている人は良かったら教えてください。

サンプルプロジェクト

github.com

雑感

今回はBlender, Animator, Animation Clip, Additive Reference Poseと詰め込みすぎ感がありますねw。
有料アセット使えばUnity内で完結できたと思うんですが、無料でできるようにしたかったのでBlenderも入れてみました。

今回の記事の経緯は手のアニメーション作ってるときに「あれ、これアニメーションの組み合わせでできんじゃね?」と思ったことですね。

Animationの用意やAnimatorの調整など、面倒な部分もありますがモデルに適したAnimation Clipを使えることがメリットでしょうか。
AnimatorControllerOverrideを使えばモデルごとにAnimationClipを設定することも可能です。

"Additive Reference Pose"についてはいいドキュメントが見つからなかったので調べるのがちょっと大変でした。

今のところ手のジェスチャー以外にいい組み合わせは思いつかないですが、 何かよさげな応用例があれば教えてください!

それでは~。