XRHands synchronization
このモジュールは、XR Handsの手(フィンガートラッキングを含む)の状態を同期する方法を示します。
手は以下のどちらかの方法で表示できます。
- 掴んでいるコントローラーから受け取るデータ
- フィンガートラッキングのデータ
フィンガートラッキングのデータに関しては、帯域消費を削減するために手のボーンのデータを高圧縮する方法を示しています。
備考:
このアドオンは、OpenXR対応(Oculus QuestやApple Vision Proなど)を別にすれば、Meta OVR hands synchronizationに似ています。
ただ、このアドオンにいくつかの改良点と、ジェスチャー検知ツールも追加されています。
手のロジック概要
このアドオンは、コントローラーベースのハンドトラッキングとフィンガーベースのハンドトラッキングが共存できます。一方からもう一方へシームレスに移行できるようにすることが目的です。
- 他のVRサンプルのように、コントローラーを使用する場合、手のモデルはOculust Sample Frameworkで表示されます。
- フィンガートラッキングを使用する場合、ローカルユーザーでは、XRHandsの
XRHandSkeletonDriver
コンポーネントを継承したXRHandCollectableSkeletonDriver
が手と指のボーンデータを収集して、ローカルのスケルトンにそれらを適用します。スケルトンは、ローカルのみで表示するメッシュに使用されます(デフォルトのプレハブでは、リモートユーザーに同じネットワークバージョンの手を表示するかわりに、表示を隠しています)。 - リモートユーザーでは、
NetworkBonesStateSync
コンポーネント(後述)が手と指のボーンの回転データを復元して、手のスケルトンのtransform
を動かし、それ自体によってSkinnedMeshRenderer
で適切な手の描画を行います。 Render
毎に、NetworkBonesStateSync
はFusionの補間データを使用して、2つの受信した手の状態間で手のボーンの回転をスムーズに補間し、2ティック間でボーンの表示もスムーズに行われます。
ローカルのハードウェアリグの手コンポーネント
ローカルユーザーのハードウェアリグの手の階層にあるXRHandCollectableSkeletonDriver
コンポーネントは、手の状態を収集して同期を行います。手の状態(特に指のボーンの回転を含む)にアクセスするため、XRHandsの親クラスXRHandSkeletonDriver
コンポーネントに依存していて、兄弟のXRHandTrackingEvents
コンポーネントが必要です。
また、これには現在フィンガートラッキングが使用されているかを知るための補助プロパティも含まれています。
備考:
XRHandCollectableSkeletonDriver
には分析コードがあり、手の状態を同期するために必要なScriptableObject
のために、デフォルトのボーン位置を探し、ボーンの回転の圧縮表現を提案します。これは後述の「ネットワークリグの手コンポーネント」で説明します。
大抵のニーズに合ったデフォルトのScriptableObject
と分析コードはアドオンで提供されているため、手のボーンの変更が多くなければ、使用する必要はありません。
ネットワークリグの手コンポーネント
ローカルユーザーでは、ユーザーのネットワークリグのNetworkBonesStateSync
コンポーネントが、ローカルのハードウェアの手からIBonesCollecter
インターフェースを実装したコンポーネントを探し、ローカルの手の状態を見つけ、それらをFixedUpdateNetwork
内でネットワーク変数に保存します。
IBonesCollecter
インターフェースはXRHandCollectableSkeletonDriver
コンポーネントで実装されていて、以下を提供します。
- フィンガートラッキングの状態
- 手のボーンの回転
リモートユーザーでは、その同期データをパースしてRender
内でローカルの手の状態を再構築します。
ネットワークを介して同期される回転データに加えて、BonesStateScriptableObject
はボーンのローカルの位置(不変)を提供します。
アドオンは、XRHandの手のボーンのローカルの位置を定義するLeftXRHandsDefaultBonesState
とRightXRHandsDefaultBonesState
アセットを含みます。
いつでも各ボーンの回転をスムーズに見せるため、NetworkBonesStateSync
は2つの受信した状態間のボーンの回転を補間します。これは、TryGetSnapshotsBuffers(out var fromBuffer, out var toBuffer, out var alpha)
を使用して、補間したいボーンの回転の「from」と「to」を探しています。
手のポーズは、ネットワークの手にあるIBonesReader
を実装したコンポーネント(XRHandsのXRHandSkeletonDriver
を継承したXRHandRemoteSkeletonDriver
など)によって、ローカルのスケルトンに適用されます。
最後に、SkinnedMeshRenderer
がこのスケルトンを使用して、適切に手を表示します。
帯域幅の最適化
ボーン情報の転送は非常に高コストで、同期する手の状態には24個のQuaternion
が含まれます。
NetworkBonesStateSync
コンポーネントは、手のボーンと同じプロパティ(特定の回転軸、可動域の制限など)を使用して、必要な帯域幅を削減しています。各ボーンの精度は、専用のHandSynchronizationScriptable
で指定できます。
NetworkBonesStateSync
のhandSynchronizationScriptable
属性が与えられていなければ、デフォルトの圧縮が使用されるため、アドオンで提供されているLeftHandSynchronization
とRightHandSynchronization
アセットのものよりも効率が下がります。これらは、大抵のニーズに合うように作られています。
- 圧縮率が非常に高く、約20分の1のバイトを使用する(手のボーンの回転を、完全な
Quaternion
を386bytesで転送するかわりに19bytesで保存します) - 圧縮によって、リモートユーザーの手の表現に悪影響を与えない
手のモデルの切り替え
HandRepresentationManager
コンポーネントは、現在使用中のハンドトラッキングモードに基づいて、どの手のメッシュを表示するかを制御します。
- コントローラートラッキング使用時は、Oculus Sample Frameworkの手のメッシュ
- フィンガートラッキング使用時は、
XRHandSkeletonDriver
コンポーネントのロジックによってアニメーションするボーンのスケルトンに依存するメッシュ
このスクリプトには2つのバージョンが存在し、1つはローカルハードウェアの手(手のスケルトンのアニメーションでの使用、ローカルの当たり判定目的、またはオフラインの手が必要な場合)、1つはネットワークの手です。
ローカルのハードウェアリグの手
このバージョンは、ハードウェアの手にあるIBonesCollecter
(XRHandCollectableSkeletonDriver
など)に依存しています。
他の機能に加えて、2つのグラブのCollider
間の切り替えの確認も行います。1つはフィンガートラッキング使用時の掌のローカルの位置、1つはコントローラーベースのトラッキング使用時の掌のローカルの位置です。(2つのモード間で、手の「中心」は全く同じ位置ではありません)これは、2つの人差し指先のCollider
と同じです。
備考:現在の設定では、ネットワークの手の表示のみが選択されます。ハードウェアリグの手は、ボーンの位置を収集して、適切に人差し指のCollider
の位置をアニメーションするためだけにあります。したがって、ハードウェアの手に使用されるマテリアルは透過です(描画が無効になっている場合は、アニメーションでボーンは動きません)。ハードウェアの手のメッシュは、HardwareHandRepresentationManager
のMaterialOverrideMode
がOverride
に設定されていれば、overrideMaterialForRenderers
フィールドで与えられた透過マテリアルによって、自動的に透過に設定されます。
ネットワークリグの手
NetworkHandRepresentationManager
コンポーネントは、手のモードに基づいて、どのメッシュを表示するかを制御します。コントローラートラッキング使用時はOculus Sample Frameworkの手のメッシュ(フィンガートラッキングのステータスを同期しているNetworkBonesStateSync
のデータをチェックします)、またはNetworkBonesStateSync
ロジックに依存したメッシュです。
Avatarアドオン
このプロジェクトでAvatarアドオンを使用する場合は、アバターのスキンの色に基づいて手の色を適用することが可能であることを確認してください。
HandManagerAvatarRepresentationConnector
の2行目#define AVATAR_ADDON_AVAILABLE
のコメントを外す- 各
NetworkHandRepresentationManager
やHardwareHandRepresentationManager
にHandManagerAvatarRepresentationConnector
をつける
ジェスチャー認識
フィンガートラッキングデータを補助するため、手のポーズの解析に役立ついくつかのヘルパースクリプトが提供されています。
FingerDrivenGesture
はそれらのスクリプトのベースで、OpenXRの手のサブシステムの接続や、トラッキングロストのコールバックを制御します。
FingerDrivenHardwareRigPose
は、通常のコントローラーのボタン(ユーザーが掴んでいるか・指をさしているかなどを決定する)による手のコマンドを処理します。これは掴みや、中指と薬指のピンチや押下を検知します(両方のオプションを同時に有効にすることが可能で、その中の1つのみがHardwareHand
のisGrabbing
をトリガーします)。
FingerDriverBeamer
は、「銃」のポーズ(人差し指と親指を立てる)を検知して、RayBeamer
(テレポート用)をトリガーします。一度有効になると、親指を立てている間(人差し指はチェックされません)は、ビームが有効になり続けます。
FingerDrivenMenu
によって、ユーザーが短時間手を見た時にメニューがポップアップし、ヘッドセットが手の方を向いている間はメニューが更新され続けます。
Toucher
のサブクラスのPincher
はピンチ動作を検知し、IPinchable
インターフェースを実装しているオブジェクトに通知します。オブジェクトはTryConsumePinch
でピンチ動作を「消費」できて、1つのピンチ動作で1つのアクションのみがトリガーされることを確実にできます。
デモ
デモシーンはAssets\Photon\FusionAddons\XRHandsSynchronization\Demo\Scenes\
フォルダーにあります。
依存関係
- XRShared addon 2.0
ダウンロード
このアドオンの最新バージョンは、Industries アドオンのプロジェクトに含まれています。
また、無料のXR アドオンのプロジェクトにも含まれています。
対応するトポロジー
- 共有モード
更新履歴
- Version 2.0.6:
- NetworkHandrepresentationManager can now specify a material for the local user
- Fix to prefab's index tip position
- Version 2.0.5:
- Allow to work with a IBonesCollector not providing bones positions
- Allow to skip automatic hardware hand wrist translation (useful for XRIT rigs)
- Version 2.0.4: Allow to disable tip collider in finger tracking
- Version 2.0.3: Ensure compatibility with Unity 2021.x (box colliders, edited in 2022.x, in prefab had an improper size when opened in 2021.x)
- Version 2.0.2: Add define checks (to handle when Fusion not yet installed)
- Version 2.0.1: Change transparent material (unlit shader)
- Version 2.0.0: First release