16日目の記事になります。UnityでHumanoid関連スクリプトを使ってモデル制御を行う解説をします。MikuMikuAkushuの事例から発展させ、VRアバター実装へのヒントになるような内容になります。(筆者は現在MikuMikuAkushuのUnityプロジェクトを管理しており、最新の環境でも動作するよう定期的にメンテナンスを行っています。IKを使用するにはAnimationControllerの設定などスクリプト以外の手順も必要になりますが、今回の記事ではスクリプト制御以外については解説しません。使用し、リアル空間の手オブジェクトとVR空間のミクさんの手をリンクして、HMD内のミクさんと握手をしているかのような体験ができるコンテンツです。FalconでMOCAPる・Falconで腕のIKと連動。仕様としてはもうこのツイートでほぼ網羅されており、ここから完成ツイートまで約18時間。ここまでの実装速度はなかなか出せないにしても、Unityの基本機能であるHumanoidを活用すれば、同等の動きが実現できるということは理解して頂けるかと思います。DK1の2点トラッキングですが、機能的にはVRアバターはMikuMikuAkushuの延長線上にあると言っても決して言い過ぎではありません。IK関連の機能解説を行います。IKの関数(変数)は少し特殊でMonoBehaviour.OnAnimatorIK()コールバック内でしか機能しません。Update()内で呼び出しても無効化されますので注意してください。layerIndex)MonoBehaviourが持つコールバック。IK処理の直前に呼び出される。IKをスクリプトから使用するには、「IKを有効にする」⇒「IKゴールの位置/回転を指定する」という手順を実行します。シーン上にIKゴール用GameObjectを配置して、スクリプトから位置/回転をAnimatorの関数に渡せばOKです。MikuMikuAkushuではインスペクタからIKゴールのGameObject指定、IKを有効にする係数(Weight)を指定できるようにしてあります。手の動きに連動して腰の座標が少し遅れて追従する仕組みを実装し、握手すると身体も揺れる動きをプロシージャルに生成しています。value)Humanoidモデルの各IKゴール位置/回転のウェイトを設定する。valueの0~1はIK処理前~IKゴールに対応。IK主体の処理でも通常アニメーションを再生したいときは一時的に0にしたりします。goalRotation))Humanoidモデルの各IKゴール位置/回転を設定する。ウェイト設定と対になっている。clampWeight)視線制御は目だけではなく、首、胴体も視線方向に向けることができます。胴体も少しだけ視線方向に向くように調整してあげると自然な動きになります。MikuMikuAkushuでは以下のようなパラメータで関数を使用しています。追従を外す度合い(0~1)0だと真後ろでも追従しようとする。lookAtPosition)Humanoidモデルの視線点座標を指定する。上記、SetLookAtWeight()関数とワンセットで使用します。Humanoidモデルの腰の位置/回転を指定する処理としてはIKそのものの処理ではありませんが、Animatorクラスの変数で代入すると内部的にはHumanoidのHipボーンに位置/回転が適応されます。アニメーションや独自スクリプトでHipボーンにパラメータを与えている場合は上書きに注意する必要があります。Animator.bodyPositionボディの重心位置を示す。Animator.bodyRotationボディの重心回転を示す。Falconによる手の位置情報のみでした。バーチャルな存在が自分と同一空間を共有し、握手をしてもらえるという体験はプレイヤーに強烈な印象を与えることなりました。Falconも5台破損するという事態へ。バーチャルな存在をリアルに召喚することで、バーチャルキャラクターも負傷してしまう事実を垣間見ることに...。ViveTrackerを用いることで、従来のモーションキャプチャスタジオ利用に比べ、より多くの関節姿勢情報が安価に取得できるようになり、個人規模でも体験者を頭だけでなくその全身をVR空間に送り出すことが可能になってきました。(KINECTについてはCPU負荷や部屋の広さ的に日本住居での全身キャプチャの難しさなどから手軽とは言えず、ノイズも多いことから、当時、VRとの共存はあまり進みませんでした...)そしてVRアバターの実装も制御的にはMikuMikuAkushuの延長線上にあります。UnityのHumanoid機能も日々拡張されており、MikuMikuAkushu制作当時はスクリプトから制御できなかった部分も制御できるようになっています。Jobsで、IK処理自体のカスタマイズができるようになるようで、とても期待しています。Jobs開発TipsHumanoidの機能ではないのですが、VRアバターの開発にあたり、用意しておきたい機能を紹介しておきます。デバッグ情報のGameView描画HMDを被った状態だとUnityのSceneビューやInspectorビューなどが見えません。HMD内でも見えるように、GameView側に表示可能な線(箱や円、球)と文字表示を行うテキストウィンドウを実装しておくことをオススメします。コリジョンが関係するデバッグでは必須と言っていいでしょう。UnityEditorの持つGizmo表示ではSceneViewには表示されるのですが、GameViewに表示されないんですよね。リプレイデータの保存/再生ボタン入力とTrackingDeviceの姿勢情報のリプレイデータの保存/再生機能を作成することを強く推奨します。不具合の再現性も確保できますし、デバイスのバッテリー駆動時間制限も緩和されます。初期に作成しておけば、リプレイ機能実装に掛かったコストの回収に使える期間も伸びますので費用対効果的にも有利になります。モデルの揺れ物をセットアップする際のテストモーションとして利用するのも効果的です。HMDを被った状態だとUnityのSceneビューやInspectorビューなどが見えませんので動作確認がホントにしづらいんですよね...。不具合報告を受け取る際にもリプレイデータを送ってもらえるとデバッグめちゃくちゃ助かります。Humanoidとは何なのか?モデルのインポート直後はGeneric型になっており、Humanoid型を使用するには明示的にRigを変更する必要があります。その際に内部的にボーンの扱いが変わり、ボーンはHumanoid型に定義された名前に変換されます。変換後にできるようになること/できなくなることを把握することでHumanoid型とはなんなのかの理解に繋がります。骨格の違うモデルに同じモーションファイルが流し込めるモーションデータも、Generic型のボーン名⇒Humanoid定義ボーン名に変換されるため、Humanoid型に変換されたモーションは、モデルの骨格情報によらず再利用が可能になります。パラメータ名で各ボーンの位置や角度、スケールで記述されたデータで作成されています。Humanoid型に変換すると、GameObject名はHumanoid型に定義されたボーン名に書き換えられ、その情報もMuscle情報に変換されます。GameObject名によるマッチングができなくなるため、Humanoid型のモデルにはHumanoid型のAnimationClipしか動作しなくなりす(もちろん、Generic型のモデルにもHumanoid型のAnimationClipは名前マッチングに失敗するため動作しません)。その代わり、どのモデルで変換されたモーションでもHumanoid型であれば、適応可能なモーションとして利用可能な状態になります。(厳密に言うと多少のズレは発生しており、足の接地が甘くなったり、両手武器などの握り位置がズレたりします。その辺りがデメリットとなり、メリットと比較して使用を検討することになります)また、Humanoid変換されたモーションはMuscle表現により少ない情報でモーションが扱えるようになります。Settings]設定から確認できます。Humanoid型のモデルでは、ボーンは3軸の回転情報ではなく、関節を動かす筋肉の値(Muscle表現)として記述され、自由度の少ない(例えば指)関節などは1軸の0~1の数値1個で表現されるようになります。Muscleは95個定義されており、Generic型に比べて少ない情報で身体の姿勢を表現するとができるようになっています。IK機能が使用できるようになる所謂フルボディIKと呼ばれる機能はHumanoidにはありません。IKでも揃っているように思います。手足のIKゴール(4点)、肘膝はIKヒント(4点)、腰はbodyPosition/Rotation(1点)、頭はLookAt(1点)にて制御可能です。IK処理と混ざる形で独自にボーン制御を追加することができます。各種センサーでトラッキングされるデバイスは、ミリ以下の単位だったりもしますがノイズが発生し振動しています。IKに与えるゴール座標として利用する際には、あくまで人の動きであるということを前提に、位置/回転情報の丸め処理を行うことで(掴んでいるオブジェクトを含め)アバターの動きが自然に見えるようになります。ハンドデバイスの回転ノイズは長い棒状のものを持った時に先端が大きく振動し、非常に目立ちます。細かく振動すると持っている物の重さが軽く見えてしまいますので、VRアバターにおいてTrackingDeviceのノイズ対策は必須と言っていいでしょう。デメリットとしては、ノイズ対策の効果の強さに応じてIKゴールがワンテンポ遅れて付いてくるような動作になります。ダンスや楽器演奏などをキャプチャする場合は、パラメータの調整を行うことも必要になるかと思います。BuildHumanAvatarによるプレイヤー骨格モデルの動的生成アバターモデルと同じ体格であるなら特に問題ありませんが、プレイヤー本人と体格が一致しないアバターモデルを使用したい場合、何かしらの方法で骨格補正(リターゲット)が必要になります。プレイヤーの骨格に合わせてアバターモデルやワールドをスケールする方法等もあるのですが、ここではHumanoidの機能を利用するために、元データとしてプレイヤー本人骨格のHumanoid型モデルを動的に生成することを想定します。実行時に動的にHumanoid型の骨格(HumanAvatar)を生成するには以下の関数を使用します。AvatarBuilder.BuildHumanAvatarhttps://docs.unity3d.com/ja/2017.4/ScriptReference/AvatarBuilder.BuildHumanAvatar.htmlサンプルとしてousttrueさんのUniHumanoidライブラリのBuildHumanAvatarを呼び出している部分が参考になるかと思います。https://github.com/ousttrue/UniHumanoid/blob/master/Scripts/AvatarDescription.csヒエラルキーにGameObjectの階層として、Humanoidボーンに必要な骨格として正しく親子関係を付けたGameObjectのルートオブジェクトを引数として与える必要があります、GameObjectとボーン対応の配列などの情報(HumanDescription)を合わせて関数を呼び出すことで、Avatarクラスが生成されます。Settings]画面の下の方にあの数値です。Avatarクラスはモデルインポート時に自動生成され、Animatorインスペクタに自動セットされるあの部分です。HumanDescriptionhttps://docs.unity3d.com/ja/2017.4/ScriptReference/HumanDescription.htmlAvatarhttps://docs.unity3d.com/ja/2017.4/ScriptReference/Avatar.htmlBuildHumanAvatarを呼び出す際の注意点として、与えるGameObjectはシーンのルートに配置しておく必要があり、何かのGameObjectの子供として配置してあるものは、エラーになってしまいます。Muscle情報のコピーが行えるようになります。事前準備を除くと、2行でHumanoidの持つ骨格補正付きのポーズコピーが実装できてしまします。}}流石にSDユニティちゃんくらい等身の低いモデルのモーションを転送するとポーズの再現性が悪くなってしまいますが、HumanPoseのMuscle情報コピーが機能していることは分かると思います。構造上、どうしても足の接地感やポーズの再現は甘くなってしまいますが、カメラから少し離れたアバターモデルなどにはこちらで充分かと思われます。HumanPoseHandlerによる指ポーズ制御HumanPoseHandlerを使用して、指のMuscle情報を書き換えることで指ポーズを制御することができます。Muscle情報書き換えを使用しないで同様のスクリプト処理を実装しようとすると、モデル制作の際の3Dツールによって操作するボーン軸が変わったり、右手/左手でボーン軸が反転・回転したりしますので、そこそこ面倒くさい処理になったりします。Muscle情報ではモデル上のボーン軸を意識することなく指を曲げることができますので、簡潔な処理で指のポーズを制御することができるようになります。このgif画像ではインスペクタのスライダーを操作するとMuscle情報が自動生成されるスクリプトを自作し、指のMuscle情報をHumanPoseHandlerで書き換えています。画像右下のfloat配列が実際に書き込まれるMuscle情報になります。Muscle情報のコピーに比べ、より細やかな制御ができるようになります。アバターモデル側の制御もIK処理になるため、地面と足の接地が安定したり、Trackerを付けたリアル空間のオブジェクト(ゲームPADや楽器など)を持つなど、アバターモデルの腕の伸びきり対策をしつつリアル空間との整合性を維持する処理など、ポーズコピーの独自の仕組みを実装することが可能になります。SetBoneLocalRotation関数によるIK割込み処理MikuMikuAkushu制作当時は無かったのですが、今は「IK処理の直前にHumanoidボーン角度を変更する」専用の関数が用意されています。この関数のおかげで、IK処理と共存できるよう各ボーンの回転のみが入った大量のFBXアニメーションを別途用意してブレンドするという面倒くさい手順を踏まなくて済むようになりました。IKを使用した独自のアバター制御を実装することができます。rotation)処理順番は、Update()関数⇒Animation再生⇒BoneLocalRotation()関数⇒IK処理⇒LateUpdate()関数となっており、Animation再生とIK処理の間にこの関数で指定した回転が適応されるようになります。IK処理を共存させるためにはこのSetBoneLocalRotation関数が必要となります。肩上げアシスト人間の動作として、腕を上げたとき(よほど意識をしない限り)肩もつられて上がります。標準的なIK処理では肩は上がらず腕のみが上がる動作になってしまいます。SetBoneLocalRotation関数を使用して、プレイヤー骨格モデルの腕が上がったら、アバターモデルの肩を上げる処理を追加すると胴体から肩~腕へのシルエットが自然になものになります。右のミクさんはアシスト無し腕IKのgif動画です。手首のIKゴールは全て同じ高さになっています。腕が水平になったあたりから肩の高さに差が出るようにアシスト量を調整しています。最後に今回はHumanoidの機能を中心に解説しましたが、実際のキャラクター制御には不自然な動きをしないようにHumanoid以外の部分でも細かい実装を積み重ねていく必要があります。面白い分野ではあるのですが、唯一の正解があるわけではありませんので試行錯誤を重ねていくしかありません。最後にちょっとだけHumanoidの不満点をば。(2020/02/21)リンク切れ。疑問は残るものの、Humanoid型モデルを制作するための数少ない情報。MEBIUSTOSのブログ「スクリプトでアニメーションクリップファイルを作成する」http://mebiustos.hatenablog.com/entry/2015/09/16/230000Humanoid型AnimationClipをスクリプト作成する際のプロパティ名調査の参考にさせてもらいました。:ousttrue「UniHumanoid」https://github.com/ousttrue/UniHumanoidVRMに内包されているUniHumanoidライブラリ。BuildHumanAvatar関数の呼び出し方など、Humanoid関連の機能の使い方の参考に。http://piapro.jp/t/QcRy※この記事はピアプロ・キャラクター・ライセンスに基づいてクリプトン・フューチャー・メディア株式会社のキャラクター「初音ミク」を使用したものです。Segawa@mkt_本業はドッターだと主張するフリーランスのゲームプログラマ。家賃よりも書籍代の方が多い感じで。Blenderを覚えるためにMMDモデルを制作してみたり、UnityでMMD/OculusRiftを動かしてみたり。upLoginユーザーは見つかりませんでした。