技術ブログ

【Unity】ハンドトラッキングに物理ベースなインタラクションを追加する【ArticulationBody】

はじめに

ArticulationBodyを使用してMeta Questのハンドトラッキングに物理ベースのインタラクションを追加してみました.まだあんまり安定していないけど,一旦記事にしてみようかなということで ...

ソースコードはこちら


TL;DR

ArticulationBodyを使用してハンドトラッキングに物理ベースのインタラクションを追加したよ.だけどまだあんまり安定してない.


ArticulationBody ... ?

ArticulationBodyはUnityで使用できるJointコンポーネントの1つです.ドキュメントやその他ネットの情報を参考にすると,ロボットアームの実装などで使われることが多く,実際そういう用途を想定したコンポーネントのようですね.

    Articulation Bodies enable you to build physics articulations such as robotic arms or kinematic chains with GameObjects
    that are hierarchically organized. They help you get realistic physics behaviors in the context of simulation for industrial applications.  

    (Articulation Body (連結ボディ) を使うことによって、ゲームオブジェクトを使ったロボットアームやキネマティックチェーンのような 物理連結 を構築することができます。
    これらは、産業用アプリケーションのシミュレーションのコンテキストでリアルな物理動作を得るのに役立ちます。)

ついでなので,ArticulationBodyの実装の元であるPhysXArticulationのドキュメントをみるとこんなことがかいてありました.
    Articulations provide an alternative, and often superior approach to creating mechanisms versus adding joints to rigid bodies. Typically, 
    you achieve higher simulation fidelity with articulations as they have zero joint error by design, and can handle larger mass ratios 
    between the jointed bodies. PhysX simulates articulations in reduced-coordinates, where the configuration of the articulation is determined 
    by its root body and the joint angles instead of the world pose of each body involved.

    (関節は、剛体にジョイントを追加するのとは対照的に、メカニズムを作成するための代替の、そして多くの場合より優れたアプローチを提供します。通常、関節は設計上
    ジョイント エラーがゼロであり、ジョイントされたボディ間のより大きな質量比を処理できるため、関節を使用するとシミュレーションの忠実度が高くなります。PhysX 
    は、関節を縮小座標でシミュレートします。この場合、関節の構成は、関係する各ボディのワールド ポーズではなく、ルート ボディと関節角度によって決定されます。)

この"剛体にジョイントを追加する"っていうのはUnityでいうところのConfigurableJointなどのことでしょうか? PhysXにおける各コンポーネントの実装を全く知らないので適当な感想になってしまいますが,揺れもの以外で物理コンポーネントの連結オブジェクト実装する際には基本的にArticulationBodyを使うのがよさそうな感じななんですかね ...


(本題) 物理インタラクション可能な手の実装に使えるかも ... ?

話は変わりますが,こんな動画を見つけたんです.


すごい ... これはUltraLerpが開発しているUnityPluginのデモの1部ですが,どうやらArticulationBodyを使用して指関節とRigidbodyのインタラクションを実装しているみたいです. ぜひ使ってみたいけど,あいにく自分はUltraLerpを持っていません😢 (VRデバイスはOculus Quest 2しか持っていない !!) ということで今回はOVRで似たもの(廉価版)を実装してみました.


簡単な説明だけ ...

OVRHandPrefabのコピーを作成して,コピーしたほうの手のモデルの各関節にArticulationBodyとCapsuleColliderを追加しています. ArticulationBodyに角度制限を与えて,オリジナルの手のモデルから各関節のローカル空間における回転を毎フレームコピーするっていうシンプルな実装です. 手首 (Wirst) については,フレーム間の位置と回転の差分からvelocityとangulerVelocityを算出してそれを使用する方法をとっています.


パラメータの調整に苦戦した

今回はOVRHandPrefabで使用されている手のモデルとそのボーンを使用したのですが,なんだか自分の環境ではArticulationBodyのStiffnessとForceLimmitを大きめに設定しないと 軽い物体(500gくらい)ですら掴むのに苦戦してしまいました.

最初,CapsuleColliderはデフォルトのPhysicsMaterialをそのまま使用していたのですが,ArticulationBodyの強さ以外にも コライダーの摩擦を強くするなどの設定が必要そう.実際,UltraLerpのUnityPluginでは手のコライダーに動摩擦係数1のPhysicsMaterialをランタイム生成してArticulationBodyに 使用する処理が存在していたので,最終的にそれを真似しました.


まだまだ不安定

まだまだ不安定です.ArticulationBodyで,フレーム間バグなどでコライダーを貫通してしまった時(それとも異常に強い力が加わったとき ?)などに角度制限に訂正できないおかしなオフセットが追加される問題が発生したりしていました. ただこれについては,どんな状況で発生するものなのかすら正確には把握できていないようなものなので「なんか不安定なところがあるのか~」くらいに受け取ってほしいです.

そうえいばUltraLerpのUnityPluginではポジションエラーとローテーションエラーの合計を使用して値が大きくなるほどArticulationBodyで発生させる力を減衰させる処理などもありましたが,あれはこの問題に対処するためだったのでしょうか ...

あとはOVRプラグイン側にハンドトラッキングの認識状態の遷移(ハンドトラッキングがロストしたかなど ...)とその状態遷移のイベントコールバックを扱う機能があるかを知らないので,ハンドトラッキングの認識が復活したときに,直前でロストした 位置から現在位置へのArticulationBodyの力の発生となってしまい,ここもうまく制御できていないっていう問題があります(ハンドトラッキング: ロスト ➡ アクティブにフレーム間で遷移したとき,ArticulationBodyを現在位置に移動させるが そこでは力の作用効果をオフにしたい).もう面倒くさくなってきてその辺の実装をしなかったのですが,簡単なやり方だと,そのフレームでの移動量が一定値を超えたらTeleportRootで力の作用効果無しで移動してしまうっていう方法でも十分だったのかな ...


さいごに

なんだか悪い部分の説明ばっかりが長くなってしまった.以前も一度物理インタラクション可能なハンドトラッキングの実装にチャレンジしたことがあって,その時はConfigurableJointを使ったのですが,満足な結果を得られずに頓挫してしまいました. 今回ArticulationBodyを使用して改めて挑戦し,一応それっぽく動くものは完成したので少し満足している部分もありますが,まだまだ改善点は多いですね ...