MayaでBlend Poseらしき仕組みを自作してみた話

はじめに

こちらの記事は KLab Creative Advent Calendar 2019 の 21日目の記事になります。

こんにちは。KLab株式会社クリエイティブR&Dグループ所属、kotuと申します。
R&Dグループではリギング&モーション周りのR&Dを担当しています。

KLab歴が浅くまだまだ新参者ですが、社内社外問わず、業界での交流をどんどん広めていきたいと、思い切ってAdvent Calendarの執筆に挑戦させて頂きました!

普段リギングに関する業務は主にAutodesk Mayaで行っているので、今回はMayaでのフェイシャルリグのキャプチャ対応に関する知見を掲載させて頂きたいと思います。

フェイシャルリグ伝統芸 Blend Shape (Morph)

image1

3Dソフトウェア(DCCツール、ゲームエンジンなど)で、キャラクターの顔の動きを作る手法の一つとして、「BlendShape」がよく用いられます。
頂点数などの構造は同じで、形が違うモデルを複数用意しておき、それぞれの形をブレンドして新しい形を作り出す機能になります。
この手法は、変形精度の高いアニメーションを作り出せるメリットを持つ反面、用意されたモデルパターンへの変形にしか対応出来ない、モデルの形状修正コストが高いことや、形状変化の過程はリニア補完でしか作れないなどのデメリットも挙げられます。

Blend Pose とは?

Blend Poseとは名前から伺えるように、コントローラーを操作して作った様々なポーズをブレンドし、最終的な動きを作り出す手法です。BlendShapeはバーテックス移動のブレンドに対し、Blend Poseはコントローラーの移動値や回転値、そしてスケール値、言わばTransformのブレンドです。
同じDCCツールの「Houdini」では、「Blend Pose」という名のノードが存在していますが、Autodesk Mayaでは機能として存在しないため、色々と試行錯誤を重ねた結果、類似性を持つノードを使って自力で構築することに挑戦しました。

今回のR&Dのプロジェクトではより豊かな表情を表現するために、自由度が高い、且つフェイシャルキャプチャに対応できるリグに挑戦するという目標がありました。BlendShape の持つデメリットを回避すると同時に自由度を向上させるため、ジョイント+コントローラーの構造でベースリグを制作しました。
フェイシャルキャプチャ対応では、Blend Poseに近い仕組みの実装に挑戦しました。

作ってみた

ここから、実際にBlend Poseらしき仕組みをMayaで実装する流れをフランクな感じでお伝えしていきたいと思います。

状況は?

今回のプロジェクトで採用したのは、Apple社のARKitを使ったFaceID搭載iOSデバイスによるFace Trackingソリューションです。顔の表情を52個のBlendShapeに細分化し、捕捉した変化量で相応のBlendShapeを駆動する仕組みです。

リグ側では自由度重視で、コントロールポイントはARKitのBlendShapeより更に細分化されているため、事前にコントローラーを使って各BlendShapeの変形を再現し、Transformの値をキャッシュとして保存しました。

その後、キャプチャで記録した各BlendShapeのウェイト値を元に、該当コントローラーのTransform値をブレンドすることになります。

発見!blendWeighted ノード

目標達成のために、MayaのノードエディターでひたすらTabキーで使えるノードをさがしていました。そこで目に留まったのは「blendWeighted」ノードでした。

image2

一見使えるプラグは割と少ない印象でしたが、アトリビュートを全表示させると

image3

色々と出てきました!
InputにWeight!しかも動的に増減可能なリスト型!これはもしや!?と試しに値を投げ込んてみたところ

image16

という内部処理を確認出来ました。

コイツは使えるぞ!

詳しく見ていきましょう~

実はこのblendWeightedノード、Mayaで1つのアトリビュートに対して複数ドライバーを持つドリブンキーを作成する時に自動で生成されるUtilityノードです。下図のように、複数入力を加算するだけだったため、Inputプラグしか使われていません。

image4

少し残念だったのは扱えるInputとOutputのデータタイプは単一なFloat型(浮動小数点数)で、TranslateXYZ、RotateXYZ、ScaleXYZのようなFloat3型(3つの浮動小数点数の配列)ではないため、組み込みに少し工夫が必要になります。

つないでみた!

説明のために簡単なシーンで動作確認をしていきます。

image5

シーン内のオブジェクト(すべてworld空間):
locator_og(コントロールされるロケーター)
locator_A(目標キャッシュA)
locator_B(目標キャッシュB)
locator_C(目標キャッシュC)
ctl(アトリビュートコントローラー)
ctl
にExtra Attribute として、各目標キャッシュへlocator_ogのTransformをブレンドさせる度合い(weight)をコントロールするアトリビュートを追加。

image6

ここからblendWeightedノードを使って構築していきます。

  • locator_ogのtranslateの3軸にblendWeightedノードを3つ用意し、それぞれのOutputとつなぎます。

  • locator_A、B、C、それぞれのtranslateを軸相応なblendWeightedノードのInputとつなぎます。

  • 最後に仕上げとして、各blendWeightedノードのウェイトリストに、ctlにある事前用意したweight調整用アトリビュートをInputリスト順につなげて完成!

image7

ctlのパラメータを調整してくと、想定通りの動きを確認できました!

image8

expression使ってsphrand()を送ってみると~

image9

動く動く~!
これでテスト完了です!

本番はどうだった?

本番リグのニーズ上、各コントローラーのTranslateX、Y、Z、RotateX、Y、Z、6つのアトリビュートをブレンドする必要があるため、下図のように各アトリビュートにblendWeightedノード1個を使って構築しました。

image10

コントローラーの多さにより、ノード数やコネクション数が膨大なため、Pythonスクリプトでバッチ処理を行い、上図の内容を各コントローラーに施し、そして各blendWeightedノードに52のWeight入力(下図)を構築しました。。。。この場においてはスクリプトの内容は割愛させて頂きます。

image11

最後に修正や加味用の手付コントローラーも加わりますと

image12

複雑なグラフになりました。。。汗

Blend Shapeのデメリットとして挙げた、変形過程のリニア補完は、下図のように、コントローラーの目標キャッシュの代わりに、アニメーションカーブをblendWeightedに入力することでリニア補完を解消出来ました。

image13

この作りにひと工夫加わえると、骨格に沿った変形など、細かいニュアンスもこれでできちゃいます!

image15

そんなにノードを使って性能面は大丈夫?

今回の運用ではコントローラー1個にアトリビュート6つ、そしてコントローラー総数69個で、合計414個のblendWeightedノードを使いました。
更に52のWeight入力を合算するとコネクション数40000超えになりましたが、社内のクリエイターPCではアニメーション再生時100fps以上と十分な動きをみせました。(アニメーションキャッシュOFF、再生設定は:Play Every Frame,Free)

オプティマイズとして顔各部分の可動域を絞った後、BlendShapeを掛け持ちしないコントローラーに対するコネクションを削ることができました。

ノードの自作も視野に

ニーズに応えるために、試行錯誤しながらの実装でしたが、この先もっと洗練された形として、Houdini の Blend Poseノードのようなわかりやすい、そして使いやすいノードを自作していきたいと思いました。

終わりに

ここまで Maya でのフェイシャルリグのキャプチャ対応に関する知見を紹介させて頂きました。

仕組みの肝となったblendWeightedノードに限らず、Mayaには様々なUtilityノードが用意されています。使い方の工夫次第で色んなことが出来ますので、興味のある方はぜひ試してみて下さい!

最後までご覧いただきありがとうございました!

このブログについて

KLabのクリエイターがゲームを制作・運営で培った技術やノウハウを発信します。

おすすめ

合わせて読みたい

このブログについて

KLabのクリエイターがゲームを制作・運営で培った技術やノウハウを発信します。