SteamVR スケルタルハンドトラッキングドライバーガイド
本ガイドは、VRChatが SteamVR Input 2.0 にアップデートされるにあたり、カスタムの SteamVR Skeletal Input Drivers の作成者が、自身のドライバーをVRChatで適切に動作させるためのものです。既存のドライバーが正しく動作することを確認したい場合や、SteamVR経由でVRChatで使用する全く新しいドライバーを作成する場合、Valveによる SteamVR スケルタルドライバー作成のドキュメントや、より全般的な ドライバーAPIドキュメント を確認することをお勧めします。
VRChatはいつ、どのようにSteamVRスケルタルデータを使用するか?
アバターのアニメーション
アバターの手をアニメーションさせる目的で、VRChatは SkeletonLeftHand または SkeletonRightHand アクションにバインドされ、かつ入力ソースにおいて利用可能なあらゆるスケルタルデータを使用します。いずれの場合も、VRSkeletalMotionRange_WithoutController のスケルトンアニメーションがアクションから取得され、中間データに格納されます。この中間データの内部表現にはボーンの位置と回転の両方が保持されますが、本ドキュメント執筆時点において、アバターに適用されるリターゲティングは回転情報のみを提供します。これは、アバターの3Dハンドメッシュが、指の長さが異なる多様な手に対して関節位置がうまく機能するように慎重かつ適切に設計されていない限り、歪んだり潰れたりして見える可能性があるためです。この仕様の欠点は、プロポーションが異なるアバターの手において、ピンチやグラブといったアクションに対する視覚的フィードバックとして正確に機能することが保証されない点にあります。
ゲームプレイ、メニューなどの入力として
VRChatは、スケルトンアクションの eSkeletalTrackingLevel の値が VRSkeletalTrackingLevel.VRSkeletalTracking_Full である場合にのみ、提供されたスケルトンアニメーションデータを手の入力として使用します。
まとめとして、 eSkeletalTrackingLevel には以下の値があります:
VRSkeletalTracking_Estimated- デバイスが身体部位の位置を直接特定できない場合です。デバイスによって提供されるスケルトンポーズは、ボタン、トリガー、ジョイスティック、またはその他の入力センサーをアクティブにするために必要な位置を想定して推定されます。Viveコントローラーが最もよく知られた例です。VRSkeletalTracking_Partial- 身体部位の位置を直接測定できますが、実際の身体部位よりも自由度が低い場合です。身体部位の特定の位置がデバイスによって測定されず、他の入力データから推定されることがあります。例:Indexコントローラー、Eteeコントローラー、指の屈曲のみを測定するグローブなどVRSkeletalTracking_Full- 体の部位の可動範囲全体にわたって、その位置を直接測定できる状態。例:Ultraleapトラッキング、Metaハンドトラッキング、MediaPipeハンドトラッキング、各指のセグメントの回転を測定するグローブなど
そのため、なぜこの値を使用するのかは明らかでしょう。これは、提供されたスケルトン内に、手のポーズに関する実際の情報がどれだけ利用可能かを直接示してくれるからです。APIの中でこの種の情報を提供しているのはここだけであるため、この目的のためにそれを使用する必要があります。
高精度なスケルタルハンドトラッキングのインタラクションモデルは、私たちがスケルトンデータに対してかなり複雑な処理を行うことを前提に構築されています。私たちは親指の先から各指の先までの距離をチェックすることで独自のpinch detectionを計算し、UIでの「クリック」や、親指と人差し指、中指、薬指、小指の先を合わせるピンチを基盤としたジェスチャー入力に使用しています。現在のジェスチャーアクションは以下の通りです:
左手:
- 親指と人差し指のピンチ:
- 手のひらがユーザーの顔を直接向いているとき: メニューを開く
- 手のひらが外側を向いており、レイキャストが有効なとき: UIクリック
- 親指と中指のピンチ: 移動
- 親指と薬指のピンチ&ホールド(概ねユーザーの顔を向いているとき): マイクミュート
- 親指と小指のピンチ&ホールド(概ねユーザーの顔を向いているとき): ジェスチャー入力を無効化
右手:
- 親指と人差し指のピンチ: なし
- 親指と中指のピンチ: 回転
- 親指と薬指のピンチ(概ねユーザーの顔を向いているとき): ジャンプ
- 親指と小指のピンチ(概ねユーザーの顔を向いているとき): キャンセル/ドロップ
つまり、スケルタルハンドトラッキングのソースとなる「デバイス」に関連する、スケルトンやポーズ以外の(ブール値、スカラー、ベクトル2などの)入力コンポーネントハンドルから、これらのアクションを提供する必要はありません。実際、それらを提供してしまうと、ダブルクリックが発生したり、意図しない操作が実行されたりする可能性があります。これについては、後ほど「Controller Emulation」のセクションで詳しく説明します。
また、これはジョイントのポーズを正しく計算することが極めて重要であることも意味します。ほとんどのトラッキングシステムでは、SteamVRの座標系と適切に一致させるために何らかの座標変換が必要となりますが、このプロセスでエラーが発生しやすくなります。この点については、次セクションのスケルトンデータを視覚的に確認する方法で解説します。
スケルトンデータの視覚的デバッグ
デバッグ目的でスケルトンデータを視覚化することができます。

これらはメニュー内で「accurate hands(正確な手)」と呼ばれています。これらは常にメニュー画面やロードシーン、またはアバターがジェネリック(非ヒューマノイド)アバターである場合に表示されます。コントロールメニューからオプションとして有効にすることで、ローカル環境においてアバターの手を置換するように設定できます(ネットワーク越しには表示されません)。
上のキャプションで示されているように、VRChatにはAccurate Hands(正確な手)(Avatar Handsとは対照的なもの)と呼んでいる手の可視化機能があります。これは、3Dハンドメッシュとして見せつつ、基盤となるトラッキングデータを可能な限り忠実に表現したものです。これらは多くの場面で役立ちますが、本ドキュメントの目的としては、提供しているトラッキングデータが正確であり、可能な限り最高の入力体験を提供できるよう調整されているかを確認するための、デバッグおよび確認ツールとして使用することをお勧めします。ピンチジェスチャーを行う際には指先が触れる必要があり、使用しているトラッキングシステムが各関節の長さを測定している場合は、それも反映されるはずです。
このモードを有効にするには、Main Menuを開き、Settingsページに移動して、Controlsカテゴリを選択してください。

右側にある「Accurate」ボタンをクリックしてください。これで手が切り替わるはずです。
Controller Emulation
現在に至るまで、SteamVRで光学式フィンガートラッキング(あるいはグローブなど)を動作させる最も一般的な手法は、「コントローラーエミュレーション」と呼ばれるアプローチです。これは、カスタムSteamVRドライバーが入力プロファイル、既存の著名なデバイス(通常はTouchやIndexコントローラー)のプロパティとレンダリングモデルを備えた追跡デバイスオブジェクトを使用して、それらのデバイスになりすます手法です。次に、トラッキング元(Meta QuestやUltraleapなど)のスケルタルデータをスケルタルトラッキング入力ハンドル経由で送信し、アプリケーションのスケルタルトラッキングアクションへ反映させます。その際、忠実度レベルを「フル(Full)」として送信することもあります。この手法によりアプリケーションへフィンガートラッキングのデータを渡すことは可能ですが、理想的なアプローチとは言えません。
- アプリケーション側では、実際に使用されているハードウェアが何であるかを判別できません
- コントローラーのいくつかのプロパティ(fidelity level enumなど)は、スケルタル入力コンポーネントが初期化された後に変更することができません。そのため、実行時にコントローラーとハンドの間でマルチモーダルな切り替えを行うことは、アプリケーション側では対応不可能です。
- 仮想コントローラーのその他の入力(トリガー、ジョイスティック、ボタンなど)を埋めるための最も手軽な方法は、単純で見えないジェスチャーを配置することですが、これはユーザー体験の観点からは不満の残るものとなります。
- その他のアクション(前述のトリガー、ジョイスティック、ボタンなど)の仮想入力は、トラッキングデータから生成されるアプリケーション側の入力と競合する可能性があります。これは、メニュー操作時のダブルクリックや、ドライバーとアプリケーションのジェスチャー入力システムの両方から同時にグラブイベントがトリガーされるといった形で現れることがあります。その結果、ユーザーにとって予期せず混乱を招く事態につながる可能性があります。
- ユーザーは、フィンガートラッキングとコントローラー操作に対して個別のバインディングを設定することはできません。もしユーザーが(前述の問題を回避するためなどに)ハンド用の入力アクションマッピングを変更または無効にした場合、そのバインディングはコントローラーに戻した際にも維持されてしまいます。クリックや掴む操作の場合、コントローラーに戻ったときにクリックや掴む操作ができなくなる可能性があります。
こうした理由から、私たちはこの「コントローラーエミュレーション」アプローチを公式にはサポートしていません。私たちは、このような状況が発生したことを検知するコードをいくつか用意しており、その際に入力がサポートされていない旨をユーザーに通知する場合があり、意図しない副作用が生じる可能性があります。
何卒、SteamVR/VRChatに送信するハードウェアや入力の情報を偽ることは避けてください。Valveのドキュメントでは、VRChatが指のトラッキングを有効にする前に現在のコントローラーがKnucklesであるかどうかを確認しており、VRChatをターゲットにする際はValve標準の汎用コントローラーエミュレーションを使用すべきであると記載されていることに気づくかもしれません。現在、この情報は古くなっています。本ガイドが最新の公式情報となります。もし、このエミュレーションシステムを使用してすでにVRChat用のコントローラーエミュレーションバインディングを設定している場合は、それらを削除してください。
推奨されるアプローチ
ストリーミングアプリケーション
Meta QuestのようなスタンドアロンデバイスをSteamVRに接続するストリーミングアプリケーションを構築する場合、アプリケーション側でTouchのようなトラッキングコントローラーに加え、コントローラーを使用しないハンドトラッキングもサポートするのが望ましいでしょう。また、片手でコントローラーを持ち、もう片方の手でコントローラーを使用しないトラッキングを行う「マルチモーダル」な使用法に加えて、コントローラーからハンドトラッキングへ素早く切り替えられるようにサポートすることも考えられます。lighthouseのような既存のSteamVRドライバーが示している通り、複数の入力デバイスを単一のSteamVRドライバー内で共存させることが可能です。そのため、私たちは以下の手順を推奨します。
ストリーミングアプリケーションがサポートする既存の各物理コントローラータイプについて、仮想コントローラー(入力プロファイル、トラッキングデバイスIDとプロパティ、入力コンポーネントハンドルなど)を作成してください。
コントローラーを使用しないハンドトラッキング専用の、全く新しい仮想コントローラーを作成してください。
物理コントローラー
これらについては、パススルーしているコントローラーをそのまま複製してください。これらは通常持っているものと同じ入力プロファイルとコンポーネント(サムスティック、ボタンなど)、同じトラッキングデバイスプロパティ(モデル名、レンダーモデル、メーカー名など)、同じ入力ソース/役割(コントローラーなら左手/右手、HMDなら頭)を持ち、スケルタルトラッキングレベルをそのコントローラーが提供するもの(Touchの場合はEstimatedなど)に初期化する必要があります。
Hand Virtual Controller
これらについては、必要最小限の入力を提供する入力プロファイルとコンポーネントハンドルを用意する必要があります。具体的には以下の通りです。
Dashboard- System click(ダッシュボードとの対話用)
- Hand Pose
Skeleton
必要に応じて他の入力も提供できますが(特にジェスチャーが十分に設計されている場合や、それに対するフィードバックを提供するオーバーレイがある場合など)、VRChatに提供するデフォルトのバインディングには含めないことをお勧めします。
ここからは、仮想ハンドコントローラーに対して分かりやすいプロパティのセットを指定します。架空の例を使ってみましょう。ストリーミングアプリが「Bitriver」で、Meta Questから手のスケルタルトラッキングをストリーミングする場合、各プロパティに対して以下のように設定できます。
左手および右手両方:
| プロパティ | 値 |
|---|---|
Prop_ManufacturerName_String | Meta |
Prop_TrackingSystemName_String | Oculus Insight |
Prop_ModelNumber_String | Bitriver_Hand |
Prop_ControllerType_String | Bitriver_Hand |
TrackedDeviceClass | Controller |
Prop_InputProfilePath_String | 入力プロファイルのjsonファイルへのパス |
左手用:
| プロパティ | 値 |
|---|---|
Prop_SerialNumber_String | BitRiver_Left_Hand |
Prop_ControllerRoleHint_Int32 | 1 |
右手の場合:
| プロパティ | 値 |
|---|---|
Prop_SerialNumber_String | BitRiver_Right_Hand |
Prop_ControllerRoleHint_Int32 | 2 |
Skeletal Inputをサポートするすべてのコントローラーにはトラッキングデバイスがあり、このトラッキングデバイスの Pose コンポーネントはスケルトンの Base Pose と呼ばれます。スケルトンのトランスフォーム座標空間は、このベースポーズの子となります。
ユーザーのVRシステムがハンドトラッキングとコントローラートラッキングの間で切り替えを行っていることを示す場合、vr::VRserverDriverHost()-> TrackedDevicePoseUpdated() を呼び出す際に、各トラッキングデバイスの Base Pose コンポーネント内で送信するブール値を変更することで、この切り替えを通知する必要があります。DriverPose_t における関連フィールドは以下の通りです:
poseIsValiddeviceIsConnected
コントローラーがアクティブなときは、それらの poseIsValid を true に設定し(使用しているAPIが、ポーズの信頼性が低く拒否すべきであると示している場合などを除き)、deviceIsConnected を true に設定します。次に、仮想ハンドの poseIsValid を false に、そして仮想ハンドの deviceIsConnected を false に設定します。
ハンドトラッキングがアクティブなときは、これとは逆の値を設定する必要があります。コントローラーのトラッキングデバイスポーズコンポーネントの poseIsValid と deviceIsConnected を false に設定します。また、仮想ハンドの poseIsValid は手がトラッキングされているときは true に、トラッキングが外れているときは false に設定し、deviceIsConnected は true に設定します。
PCVR周辺機器
PCVR用の単一の周辺機器を構築する場合(独自のコンピュータビジョンによるハンドトラッキングシステムの作成や、グローブの製作など)、前述のセクションの後半部分、つまりハンドを表現するために適切な名前を付けた新しい仮想コントローラーを構築する手順のみを行う必要があります。コントローラーとハンドの切り替え(ハンドオフ)を行う必要はありません。
フィンガートラッキング専用モード(Finger Tracking Exclusive Mode)
VRChatは将来的にこの機能を削除する可能性があります。様々なアクションに対して独自の入力を提供する非準拠のドライバーは、ユーザー体験を低下させる原因となります。
VRChatは開発中にこの機能を使用していました。すべてのドライバーは、VRChatのカスタムトラッキングベースの入力システムが独自に推論できるSteamVRアクションに対して入力を行っていました。フィンガートラッキング専用モード(Finger Tracking Exclusive Mode)により、開発中にダブルクリックやダブルグラブなどが発生することなく、忠実度の高いハンドトラッキングが可能になりました。
ユーザーがフィンガートラッキング専用モードを有効にすると、VRChatはPose、SkeletonLeftHand、SkeletonRightHand以外のアクションにバインドされたSteamVR入力を無視します。
最終更新: