VRM(VRoid)モデルをMayaのHumanIKに対応し、モーキャプしたモーションを流す

# はじめに
VRMとは、人型3Dアバター（3Dモデル）データを扱うためのファイルフォーマットです。
VRoidStudioとは、VRMモデルを簡単に制作するためのツールです。

HumanIKとは、Mayaに標準搭載されている人型リグです。
この形式に対応させることで、様々な便利機能が使用できるようになります。
(UnityのHumanoidの概念に近いかもしれません。)

この記事は、モーションキャプチャで収録したモーションを、MayaでVRoidキャラクターに転写(リターゲット)し、Unityで実行するまでの流れを説明します。

# モデル準備
## VRoidで制作
VRoidStudio(v1.14.0)を用いて、キャラモデルを制作します。
今回はサンプルをそのままお借りします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/f8c08b2c-09cd-9280-c28b-1e9038eb84f2.png", width=256/>

## Blenderで変換
このモデルをMayaにインポート...と言いたいところですが、私の知る限りMayaにはVRMImporterが存在しません。
そこで、Blenderを使用してVRMモデルをFBXに変換します。
まずモデルの拡張子を.vrmから.gltfに変更します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/fb0151fb-1ecc-d143-c013-4b841ee59637.png", width=256/>

Blender(3.3.0)でgltfモデルとして、読み込みます。
テクスチャ表示状態とし、シーンファイルを保存しておきましょう。
その後Armatureを選択し、FBXとしてエクスポートします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/11aaf27b-717d-c675-7790-830d05a786c7.png", width=256/><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/4176de3e-40f1-3d9d-e601-ea72b8043b42.png", width=256/>

同梱されているテクスチャも分離しておきます。
File → ExternalData → UnpackResources → Use file in current...を実行します。
シーンファイルと同階層にtextureフォルダが生成され、その中にテクスチャが出力されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/0230e5dd-d89c-ce13-bda5-8f64f113ffd2.png", width=256/><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/04689935-6cb8-302b-7c31-b0da399c0e35.png", width=256/>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/ddf33f2a-414d-ded8-248e-62b72ece38db.png", width=256/>

## Mayaに読み込み
出力したFBXを読み込みます。
何やら見づらい状態ですので修正します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/f82984c5-75fd-dbf8-a3aa-d413dcb9690e.png", width=256/>

ジョイント表示をオフにします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/a5f2dd29-b9ff-a333-5c53-e9f2d03e66bb.png", width=256/>

テクスチャが剥がれているので、マテリアルにセットします。
(マテリアルは新規で作成したほうが望ましいと思いますが、今回は時短で再利用します。)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/58763acf-d09e-1ec4-037b-412d31deaa4a.png", width=256/>

描画順がおかしかったので レンダラ → Viewport2.0 → 透過度のアルゴリズム を 深度ピーリングにします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/d75be493-2ff8-00a7-6fb9-236c11164d2c.png", width=256/>

これで最低限見れるようになりました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/d17f40f9-6d47-e434-4e9e-ec08cade6669.png", width=256/>

# HumanIK対応
HumanIKのタブを出して
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/e46780f5-9ed7-9387-ca60-d319e48f0f80.png", width=256/>

キャラクタ定義を作成して
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/8d57ef56-c829-8356-4433-a9e9a3fc629f.png", width=256/>

キャラジョイントをHumanIKジョイントの定義にセットします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/9a21a935-f721-c9e7-ea13-7c4ef8ad7890.png", width=256/>

...手動で定義するのが大変なので、スクリプト化しました。
よかったら使ってください。(マッピングが間違っていたら指摘いただけるとありがたいです。)

```
rig_name = "VRoid"

mel.eval('hikCreateCharacter("{0}")'.format(rig_name))
mel.eval('hikUpdateCharacterList()')
mel.eval(' hikSelectDefinitionTab()')

model_root = "|Armature|Root"
cmds.select(model_root)

joint_settings = [["J_Bip_C_Head", 15],
                  ["J_Bip_C_Hips", 1],
                  ["J_Bip_C_Neck", 20],
                  ["J_Bip_C_Spine", 8],
                  ["J_Bip_C_UpperChest", 23],
                  ["J_Bip_L_Foot", 4],
                  ["J_Bip_L_Hand", 11],
                  ["J_Bip_L_Index1", 54],
                  ["J_Bip_L_Index2", 55],
                  ["J_Bip_L_Index3", 56],
                  ["J_Bip_L_Little1", 66],
                  ["J_Bip_L_Little2", 67],
                  ["J_Bip_L_Little3", 68],
                  ["J_Bip_L_LowerArm", 10],
                  ["J_Bip_L_LowerLeg", 3],
                  ["J_Bip_L_Middle1", 58],
                  ["J_Bip_L_Middle2", 59],
                  ["J_Bip_L_Middle3", 60],
                  ["J_Bip_L_Ring1", 62],
                  ["J_Bip_L_Ring2", 63],
                  ["J_Bip_L_Ring3", 64],
                  ["J_Bip_L_Shoulder", 18],
                  ["J_Bip_L_Thumb1", 50],
                  ["J_Bip_L_Thumb2", 51],
                  ["J_Bip_L_Thumb3", 52],
                  ["J_Bip_L_ToeBase", 16],
                  ["J_Bip_L_UpperArm", 9],
                  ["J_Bip_L_UpperLeg", 2],
                  ["J_Bip_R_Foot", 7],
                  ["J_Bip_R_Hand", 14],
                  ["J_Bip_R_Index1", 78],
                  ["J_Bip_R_Index2", 79],
                  ["J_Bip_R_Index3", 80],
                  ["J_Bip_R_Little1", 90],
                  ["J_Bip_R_Little2", 91],
                  ["J_Bip_R_Little3", 92],
                  ["J_Bip_R_LowerArm", 13],
                  ["J_Bip_R_LowerLeg", 6],
                  ["J_Bip_R_Middle1", 82],
                  ["J_Bip_R_Middle2", 83],
                  ["J_Bip_R_Middle3", 84],
                  ["J_Bip_R_Ring1", 86],
                  ["J_Bip_R_Ring2", 87],
                  ["J_Bip_R_Ring3", 88],
                  ["J_Bip_R_Shoulder", 19],
                  ["J_Bip_R_Thumb1", 74],
                  ["J_Bip_R_Thumb2", 75],
                  ["J_Bip_R_Thumb3", 76],
                  ["J_Bip_R_ToeBase", 17],
                  ["J_Bip_R_UpperArm", 12],
                  ["J_Bip_R_UpperLeg", 5],
                  ["Root", 0]]

for joint_setting in joint_settings:
    mel_command = 'setCharacterObject("{0}","{1}", {2}, 0);'.format(
        joint_setting[0], rig_name, joint_setting[1])
    mel.eval(mel_command)
mel.eval("hikCreateControlRig;")
```

これでVroidモデルをHumanIKリグで動かすことができました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/5d3ff19c-52b0-858b-daab-f8f57c94155f.gif", width=256/>

# モーキャプ転写
今回はRokokoMotionLibraryというプラグインから、モーションを購入して使用しました。
(0円サンプルお借りしただけですが)
Mayaのバージョンに制約があるので、2022.1を使用しました。

キャラとモーションをシーンにロードし、キャラクタにVRoid、ソースにモーションを設定します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/75ded5bb-1bab-4aa4-30cc-ebb046a31109.png", width=256/>

アニメーションを再生するとキャラにモーションが転写されます。
ダンスモーションとアクロバティックなモーションも問題なく転写できてますね！！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/f8f539db-59df-4e49-f90a-97725b677968.gif", width=256/><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/f001c72a-cc02-4f1a-5b17-a18aa9953b33.gif", width=256/>

この記事ではアニメーション修正は行っていませんが、当然この後に手を入れることも可能です。
コンテンツならではの誇張表現などもここで入れてしまいしょう。

# Unityで流す
UnityプロジェクトにUniVRMを導入します。
詳細は省きますが、VRMのバージョンが一致しないため、【Migrate to VRM 1】にチェック入れて、対応します。
モーションをHumanoidにしてImportし、問題なく流れることを確認できました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/50369f14-9e7d-48c5-dbd6-7905bed1e492.gif", width=256/><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/057a5263-ea6e-c79a-3426-4e17bdc44332.gif", width=256/>

# まとめ
HumanIKを利用して、VRoidモデルにモーションをリターゲットしました。
VRMはアバター利用が主とはいえキャラを差し替えられるゲームも出てきているので、事前収録のモーションを流す需要も一定あると思います。

直接Unityでリターゲットとアニメーション修正する案もあるかと思いますが、MayaであればDCCツールらしい快適なサポートを標準で受けることができます。
特にダンスなどの長尺モーションや宙返りのようなアクロバットな動きの修正は、まだまだMayaのほうがやりやすいと思います。(主観です。)

VRMはUnityやBlenderでの活用事例は多く見られますが、Mayaの記事はあまり見られない印象です
さらにモデリング記事はあれど、アニメーションに関する記事も同様にあまり見られない印象です。
この記事が多様な制作方法の助けになれば幸いです。