アイトラとリップシンクを付けたまま首が取れるアバターを作る
ことの始まり
ハロウィンの季節、VRChatのアバターをハロウィン仕様にしたいなとふと思いました。現在主に使ってるアバターがウェイト塗りのミスで片目が抜け落ちていた時期があったのでそれをネタにしてアンデッド感のあるアバターに、見た目だけじゃなく腕とか頭とか取れる仕様にしちゃおう。と思い立ったのがきっかけです。そしてこんなのが出来上がりました。VRChatでデュラハンになりたい人にもいいのではないでしょうか。
頭が手に追従して取れてアイトラもリップシンクも死なないアバターができました。やり方は忘れないようにあとでまとめようと思います。せっかくだし今日明日使えるようペデスタルを用意したワールド作ろうかな。 pic.twitter.com/gfVN0zXh87
— キウィー (@okiuxio) October 30, 2018
先に言ってしまうと今回の記事の実装では時間経過や移動とともにボーンがズレてきていずれぐちゃぐちゃになります。また、クライアント毎の同期がうまく取れないようです。原因はFixed Jointの仕様らしいです。さらに常時Fixed Joint特有のガクツキが発生します。
いわゆるサブアームのような実装をしているのでそのへんに詳しくて解決方法を知っている方は情報提供してくださると助かります。
実装する機能
今回のネタで一番手こずるのが最後の項目についてです。この手のアバターからモノを取り出す・手に取る系の機能は予め手にオブジェクトを仕込みそれをアニメーションオーバーライドでOnOffして取り外しすることが多いと思います。アイトラや表情に関してはそれでも実装できますが、リップシンクだけは一つのオブジェクトにしか設定できないため、頭にくっついている方または手にくっついてる方のいずれか片方しかリップシンクを使えません。
そこで思いついた方法が2つ。まずは1つのオブジェクトに頭部につける頭のメッシュと右手に持つ頭のメッシュの両方を格納し、指定のUV座標をアルファで抜いてあたかも持ち替えてるように見せる方法。次にHumanoidのHeadボーンを複製した頭のボーンにFixed Jointで同期させて位置だけずらす方法。今回は後者を試しました。
実装方法
すでにアイトラッキングやリップシンクは実装できていて、アニメーションオーバーライドの設定方法がわかっているという前提で進めます。全体の流れとしては以下のようになります。
- 体と頭を別のfbxとして用意
- 体をHumanoid、頭をGenericとしてUnityにインポート
- 頭が体の動きと連動するようFixed Jointで紐づけ
- 空のオブジェクトを利用して頭を体、右手、Worldそれぞれの座標系を切り替えながら動けるように設定
- 操作用アニメーションオーバーライドの追加
要は「オブジェクトのワールド固定」と「Fixed Jointによるボーンの連動」を組み合わせたものになります。
今回例としているアバターでは左腕も取れるように設定しているため、途中の図に左腕が無いですが頭の設定には関係しないので気にしないでください。
1.体と頭を別のfbxとして用意
まずはBlender等のモデリングソフト上での作業です。VRChat内では特別なことをしない限りHumanoidのボーンの位置は基本の位置に矯正されます。そのため、Humanoidに割り当てる用の体のfbxとHumanoidに割り当てられない頭のfbxを別々に用意します。ただし、体側のfbxには頭部のボーンを残しておいてください。別オブジェクト化した頭部を正しい位置に追従させるために使います。表情やリップシンクのシェイプキーは頭側に設定しておいてください。
このモデルでは簡易なフェイシャルボーンが入っているため顔周りのボーンがごちゃごちゃしていますが気にしないでください。首、頭、さらにアイトラも含める場合は右目、左目のボーンが入っていれば最低限は大丈夫です。
2.体をHumanoid、頭をGenericとしてUnityにインポート
ここからUnity上での作業です。いつもどおりfbxをUnityのAssetsに入れます。Humanoidに設定するのは体のみです。頭はGenericのままにしてください(というよりHumanoidには設定できないと思います)。このとき、おそらくHeadのボーンが設定されていないと思うのでconfigureで下図のようにボーンを手動で割り当てて行きます。
VRC_Avatar DescriptorのFace Meshには頭オブジェクトのメッシュを設定してください。
3.頭が体の動きと連動するようFixed Jointで紐づけ
体をHierarchyにドラッグ&ドロップし、体の子になるよう頭をHierarchy上の体オブジェクトにドラッグ&ドロップします。次は頭と体が連動するように対応する各ボーンにFixed Jointコンポーネントでくっつけます。
上が体側のHeadボーンの設定、下側が頭部のHeadボーンの設定です。体側のボーンにはRigidbodyコンポーネントを追加、頭部のボーンにはRigidbodyとFixed Jointコンポーネントを追加します。Fixed JointのConnected Bodyは体側の対応するボーンを入れてください。その他の設定値は画像を参考にしてください。この設定を首、頭、アイトラありの場合は右目と左目、すべてのボーンに対して行ってください。
ここまで設定し終わったら一旦Playモード(上の再生マークを押した状態)で体側のボーンをいじってキチンと頭が追従してくるかチェックすることをおすすめします。PlayモードでないとFixed Jointが働かず追従しないので注意してください。Playモードであるにもかかわらず動かなかった場合はどこか設定が間違えている可能性があるので見直してみてください。
4.空のオブジェクトを利用して頭を体、右手、Worldそれぞれの座標系を切り替えながら動けるように設定
ここから頭を切り離せるよう設定をしていきます。今回は頭の追従を通常時は体に、アニメーションオーバーライド中は右手に追従またはWorldに固定されるようにします。3つの物体に追従するため、それぞれの追従をコントロールするための空のオブジェクトを作ります。
ただ、右手に追従させる機能は初期位置に戻す機能がないため自力で戻すことになります。また、Fixed Jointの仕様上それぞれのクライアントで同期ズレが発生するため、それぞれ違う場所に頭部が見えるようになります。そのため自分は正しい位置に戻したつもりでも他人からは全然違う位置に浮いているということがしょっちゅう起こります。メリットとしては右手で持ってるように動かせるだけなので実装しないほうが快適かもしれません。実装しない場合は以下の説明の橙色の文章を無視してください。
まず、下記のような構成で空のオブジェクトを3つ追加します。()内は実装時に命名したオブジェクト名です。オブジェクト名は何でも大丈夫ですが、以下説明では()内の名称を使うため合わせるとわかりやすいかもしれません。
体のオブジェクト
┗空のオブジェクト(Detach_Head)
┗空のオブジェクト(Relese_Head_to_world)
┗空のオブジェクト(Relese_Head_from_hand)
┗頭のオブジェクト
また、右手ボーンの子にも空のオブジェクトを追加してください。
右手のボーン
┗空のオブジェクト(right_hand_grab_point)
追加したそれぞれの空のオブジェクトのコンポーネントを以下のように設定します。
・Detach_Head
・Relese_Head_to_world
(2018/11/18 20時追記)ここのConnected BodyのHeadは体側のボーンです。
・Relese_Head_from_hand
・right_hand_grab_point
5.操作用アニメーションオーバーライドの追加
ここまででアバターの構成は完成しました。後は動的に切り離したりくっつけたりするためのアニメーションオーバーライドの設定です。
・頭をWorld固定する場合
Relese_Head_to_worldのis Kinematicにチェックを入れる。
・頭を右手に追従する場合
Relese_Head_from_handのis Kinematicのチェックを外す。
これらを設定したアニメーションを作成してカスタムアニメーションオーバーライドに設定すれば完成です。お疲れ様でした。
終わりに
途中でも述べましたが右手の追従は同期ズレが激しく、自分はお菓子をもらうときに頭を外して首に入れてもらったり人に手渡した頭がその人の手の上に残るという演出をしたいがために実装しましたがズレを実感し始めたころにアバターを読み込み直す必要があってあまり快適ではありませんでした。なので頭をWorldに固定する機能のみの実装をおすすめします。
今回は体を支点にして頭を取り外すという実装にしたため、視点は体側に追従しますが、頭と体のボーン構成などの設定を逆にすれば体を置いてきて頭だけで移動するということも実現できると思います。視点も頭に追従しているので自然な動きができると思います。ですが体全部をFixed Jointで制御するとなるとすぐ形が崩壊してしまう恐れがあります。体を置いていく場合は仕込んでおいた動かない体を置いていくのと同時に元の体をアルファマスクなどで透過するのが無難かもしれません。