MRが楽しい

MRやVRについて学習したことを書き残す

MRTK v2のドキュメントを少しずつ読み解く ポインター その3

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

MRTKv2のGuidesドキュメント

以下のドキュメントを読み進めていきます。
microsoft.github.io

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200315111951j:plain

Mixed Realityプラットフォームのポインターサポート

次の表に、MRTKの一般的なプラットフォームで通常使用されるポインタータイプの詳細を示します。

これらのプラットフォームに異なるポインタータイプを追加することは可能です。
例えば VR に PokePointer または SpherePointer を追加することもできます。
さらに、ゲームパッド付きのVRバイスは GGVPoiinter を使用できます。

OpenVRWindows Mixed
Reality
HoloLens 1HoloLens 2
ShellHandRayPointer有効有効有効
TeleportPointer有効有効
ShellHandRayPointer有効
ShellHandRayPointer有効

コードを介したポインター相互作用

ポインターイベントインターフェイス

次のインターフェイスの1つ以上を実装し Collider で GameObject に割り当てられた MonoBehaviours は関連付けられたインターフェイスで定義されたポインターインタラクションイベントを受け取ります。

イベント説明ハンドラクラス
フォーカス変更前/
フォーカス変更後
ゲームオブジェクトがフォーカスを失ったか、ポインターがフォーカスを変更することの両方で発生します。 IMixedRealityFocusChangedHandler
フォーカス入力/終了 最初のポインターが当たったときのフォーカスを取得したゲームオブジェクトか
最後のポインターが離れたときのフォーカスを失ったゲームオブジェクトで発生します
IMixedRealityFocusHandler
ポインターの上下/ドラッグ/クリック ポインターの押下、ドラッグ、リリースを報告するために発生します。 IMixedRealityPointerHandler
タッチ開始/更新/完了 タッチアクティビティを報告するために、PokePointer などのタッチ対応ポインターによって発生します。 IMixedRealityTouchHandler


IMixedRealityFocusChangedHandler および IMixedRealityFocusHandler はそれらが発生するオブジェクトで処理する必要があります。
フォーカスイベントをグローバルに受信することは可能ですが、他の入力イベントとは異なり、グローバルイベントハンドラーはフォーカスに基づくイベントの受信をブロックしません。
イベントは、グローバルハンドラーと対応するフォーカスのあるオブジェクトの両方によって受信されます。

アクションのポインター入力イベント

ポインタ入力イベントは通常の入力イベントと同様の方法でMRTK入力システムによって認識および処理されます。
通常の入力イベントとの違いは、ポインター入力イベントは入力イベントを発生させたポインターとグローバル入力ハンドラーによってフォーカスされている GameObject によってのみ処理されることです。
通常の入力イベントは全てのアクティブなポインターに対してフォーカスされている GameObjects によって処理されます。

1.MRTK入力システムは、入力イベントが発生したことを認識します。

2.MRTK入力システムは、登録されているすべてのグローバル入力ハンドラーへの入力イベントに関連するインターフェイス関数を起動します。

3.入力システムはイベントを発生させたポインターに対してフォーカスしている GameObject を決定します。

3-1.入力システムは Unity のイベントシステムを利用して、フォーカスされた GameObject 上の全ての一致するコンポーネントに関連するインターフェイス関数を起動します。

3-2.いずれかの時点で入力イベントが使用済みとしてマークされている場合、プロセスは終了し、それ以上の GameObject はコールバックを受け取りません。
例:IMixedRealityFocusHandler を実装するコンポーネントが検索され、GameObject がフォーカスを取得または失ったとき。
注意:現在の GameObject で目的のインターフェースに一致するコンポーネントが見つからない場合、Unity Event System はバブルアップして親 GameObject を検索します。

4.グローバル入力ハンドラーが登録されておらず、一致するコンポーネント/インターフェースを持つ GameObject が見つからない場合、入力システムは各フォールバック登録済み入力ハンドラーを呼び出します。

以下は、ポインタがフォーカスを取得または終了したとき、または、ポインタがオブジェクトを選択したときにアタッチされたレンダラーの色を変更するスクリプトの例です。

public class ColorTap : MonoBehaviour, IMixedRealityFocusHandler, IMixedRealityPointerHandler
{
    private Color color_IdleState = Color.cyan;
    private Color color_OnHover = Color.white;
    private Color color_OnSelect = Color.blue;
    private Material material;

    private void Awake()
    {
        material = GetComponent<Renderer>().material;
    }

    void IMixedRealityFocusHandler.OnFocusEnter(FocusEventData eventData)
    {
        material.color = color_OnHover;
    }

    void IMixedRealityFocusHandler.OnFocusExit(FocusEventData eventData)
    {
        material.color = color_IdleState;
    }

    void IMixedRealityPointerHandler.OnPointerUp(
         MixedRealityPointerEventData eventData)
    { }

    void IMixedRealityPointerHandler.OnPointerDown(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerDragged(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
    {
        material.color = color_OnSelect;
    }
}

f:id:bluebirdofoz:20200315112530j:plain

MRTK v2のドキュメントを少しずつ読み解く ポインター その2

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

MRTKv2のGuidesドキュメント

以下のドキュメントを読み進めていきます。
microsoft.github.io

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200314215520j:plain

ポインター

デフォルトのポインタークラス

以下のクラスは、すぐに使用できるMRTKポインターです。
上記で概説したデフォルトのMRTKポインタープロファイルで利用可能で定義されています、
Assets/MixedRealityToolkit.SDK/Features/UX/Prefabs/Pointers で提供される各ポインタープレハブには添付されたポインターコンポーネントの1つが含まれています。
f:id:bluebirdofoz:20200314215536j:plain

Far pointers

LinePointer

ベースポインタークラスである LinePointer は入力のソース(つまりコントローラー)からポインター方向に線を引きます。
この方向に単一の Raycast をサポートします。
主に一般的な機能を提供するこのクラスの代わりに、ShellHandRayPointer やテレポートポインターなどの子クラスがインスタンス化されて利用されます。
(テレポーテーションが終了する場所を示す線も描画します)

Oculus、Vive、Windows Mixed Reality などのモーションコントローラーの場合、回転はコントローラーの回転と一致します。
HoloLens 2 の関節付き手のような他のコントローラーの場合、回転はシステムが提供する手のポインティングポーズと一致します。
f:id:bluebirdofoz:20200314215606j:plain
microsoft.github.io

CurvePointer

CurvePointer は曲線に沿ったマルチステップレイキャストを可能にすることにより、LinePointer クラスを拡張します。
この基本ポインタークラスはラインが常に放物線に曲がる Teleport pointers などの曲線インスタンスに役立ちます。
microsoft.github.io

ShellHandRayPointer

LinePointer から拡張された ShellHandRayPointer の実装はMRTKポインタープロファイルのデフォルトとして使用されます。
DefaultControllerPointer プレハブは ShellHandRayPointer クラスを実装します。
microsoft.github.io

GGVPointer

GGVPointerは Gaze/Gesture/Voice(GGV)ポインターとも呼ばれます。
主に、視線とエアタップ、または、視線と音声認識インタラクションを介して、HoloLens 1 スタイルのルックアンドタップインタラクションを強化します。
GGVPointer の位置と方向は、頭の位置と回転によって決まります。
microsoft.github.io

TouchPointer

TouchPointer は Unity Touch 入力(つまり、タッチスクリーン)の操作を担当します。
これらは「遠くの相互作用」に分類されます。
スクリーンに触れる行為はカメラからシーン内の遠い場所に Raycast を投げかけるからです。
microsoft.github.io

MousePointer

MousePointer は遠隔操作のために画面をワールドレイキャストにパワーアップします。
ただしタッチの代わりにマウスを利用します。
f:id:bluebirdofoz:20200314215709j:plain

マウスサポートはMRTKではデフォルトでは使用できません。
MouseDeviceManager タイプの新しい Input Data Provider をMRTK入力プロファイルに追加し、MixedRealityMouseInputProfile を Data Provider に割り当てることで有効にできます。
microsoft.github.io

Near pointers

PokePointer

PokePointer は「タッチ可能な近接操作」をサポートするゲームオブジェクトとやり取りするために使用されます。
タッチ可能なゲームオブジェクトとは NearInteractionTouchableスクリプトが添付された GameObject です。
UnityUI の場合、このポインターは NearInteractionTouchableUnityUIs を探します。
PokePointer は SphereCast を使用して、最も近いタッチ可能な要素を決定し、押し可能なボタンなどを駆動するために使用されます。

NearInteractionTouchable コンポーネントを使用して GameObject を構成する場合 localForward パラメーターを設定して、ボタンまたはタッチ可能にする必要があるオブジェクトの前面を指すようにしてください。
また、タッチ可能の境界がタッチ可能オブジェクトのバウンドと一致することを確認してください。

PokePointer の便利なプロパティを以下に示します。

・TouchableDistance
タッチ可能な表面が相互作用できる最大距離。

・Visuals
指先を視覚的にレンダリングするために使用されるゲームオブジェクト(デフォルトでは指のリング)。

・Line
指先からアクティブな入力面に描画するオプションの線。

・Poke Layer Masks
ポインターが相互作用する可能性のある GameObject と、試行する相互作用の順序を決定する LayerMask の優先順位付き配列。
GameObject には PokePointer と対話するために NearInteractionTouchable コンポーネントも必要であることに注意してください。
f:id:bluebirdofoz:20200314215755j:plain
microsoft.github.io

SpherePointer

SpherePointer は UnityEngine.Physics.OverlapSphere を使用して、相互作用のための最も近い NearInteractionGrabbable オブジェクトを識別します。
これは ManipulationHandler のようなグラブ可能な入力に役立ちます。
PokePointer/NearInteractionTouchable 機能ペアと同様に SpherePointer と相互作用するにはゲームオブジェクトに NearInteractionGrabbable スクリプトであるコンポーネントが含まれている必要があります。
f:id:bluebirdofoz:20200314215906j:plain

SpherePointer の便利なプロパティを以下に示します。

Sphere Cast Radius
グラブ可能なオブジェクトの照会に使用される球の半径。

・Grab Layer Masks
ポインターが相互作用する可能性のある GameObject と、試行する相互作用の順序を決定する LayerMask の優先順位付き配列。
GameObject は SpherePointer と対話するために NearInteractionGrabbable も持っている必要があることに注意してください。

Spatial Awareness レイヤーは MRTK が提供するデフォルトの GrabPointer プレハブでは無効になっています。
これは空間メッシュで球面オーバーラップクエリを実行することによるパフォーマンスへの影響を軽減するために行われます。
これを有効にするには GrabPointer プレハブを変更します。

・Ignore Colliders Not in FOV
ポインタの近くにある可能性があるが、実際には視覚的な FOV にはないコライダーを無視するかどうか。
これにより、偶発的なグラブを防ぐことができます。
つかむことができるが近くに見えない場合に HandRay をオンにすることができます。

視覚 FOV はパフォーマンス上の理由から、一般的な錐台のコーンを介して定義されます。
この円錐は、カメラの錐台と同じ中心に配置され、半径はディスプレイの高さの半分(または垂直FOV)に等しくなります。
f:id:bluebirdofoz:20200314215849j:plain
microsoft.github.io

Teleport pointers

TeleportPointer

TeleportPointer はユーザーを移動するためにアクションが実行されるとテレポート要求を出します。
microsoft.github.io

ParabolicTeleportPointer

ParabolicTeleportPointer はユーザーを移動するために放物線のレイキャストでアクションが実行されるとテレポート要求を発生させます。
f:id:bluebirdofoz:20200314215935j:plain
microsoft.github.io

MRTK v2のドキュメントを少しずつ読み解く ポインター その1

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

MRTKv2のGuidesドキュメント

以下のドキュメントを読み進めていきます。
microsoft.github.io

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200313092002j:plain

ポインター

この記事ではポインター入力を構成して応答する方法をポインターアーキテクチャと比較して説明します

ポインターは、新しいコントローラーが検出されると、実行時に自動的にインスタンス化されます。
複数のポインターをコントローラーに接続できます。
例えば、デフォルトのポインタープロファイルを使用すると、Windows Mixed Realityコントローラーは通常の選択のための線と、テレポーテーションのための放物線の両方のポインターを取得します。

ポインター構成

ポインターは MixedRealityPointerProfile を介してMRTKの入力システムの一部として構成されます。
このタイプのプロファイルはMRTK構成インスペクターの MixedRealityInputSystemProfile に割り当てられます。
ポインタープロファイルは、カーソル、実行時に使用可能なポインターの種類、およびそれらがどのようにアクティブであるかを決定するかを決定します。

Pointing Extent

ポインターが GameObject と対話できる最大距離を定義します。

Pointing Raycast Layer Masks

これは指定されたポインターが相互作用する GameObject と作用の順序を決定するための、LayerMask の優先順位付き配列です。
これはポインターが他のシーンオブジェクトの前に、UI要素と対話することを保証するのに役立つ場合があります。
f:id:bluebirdofoz:20200313092016j:plain

ポインターオプションの構成

デフォルトのMRTKポインタープロファイル構成には次のポインタークラスと関連するプレハブがすぐに使用できます。
実行時にシステムで使用可能なポインターのリストはポインタープロファイルの[Pointer Options]で定義されます。
開発者はこのリストを使用して、既存のポインターを再構成したり、新しいポインターを追加したり、削除したりできます。
f:id:bluebirdofoz:20200313092114j:plain

ポインターエントリは、次のデータセットによって定義されます。

Controller Type

ポインターが有効なコントローラーのセットです。

例えば PokePointer は指でオブジェクトを「突く」役割を果たします。
これはデフォルトでは関節式ハンドコントローラータイプのみをサポートするものとしてマークされています。
ポインターは対称のコントローラータイプが使用可能になったときにのみ、インスタンス化されます。
Controller Type はこのポインタープレハブを作成できるコントローラーを定義します。

Handedness

特定の手(左/右)に対してのみインスタンス化されるポインターを許可します。
Pointer エントリの Handedness プロパティを None に設定すると、システムから実質的に無効になります。

Pointer Prefab

このプレハブアセットは指定されたコントローラータイプと利き手に一致するコントローラーが追跡され始めるとインスタンス化されます。

1つのコントローラーに複数のポインターを関連付けることができます。
例えば、デフォルトの HoloLens 2 プロファイルで多関節ハンドコントローラーは PokePointer、GrabPointer、DefaultControllerPointer(手の光線)に関連付けられています。

注意

MRTKは Assets/MixedRealityToolkit.SDK/Features/UX/Prefabs/Pointers 配下に一連のポインタープレハブを提供します。
Assets/MixedRealityToolkit.SDK/Features/UX/Scripts/Pointers のポインタースクリプトの1つか、IMixedRealityPointerを実装するスクリプトが含まれていれば、新しいカスタムプレハブを構築できます。

MRTK v2のドキュメントを少しずつ読み解く MRTKでNearInteractionを追加する方法 その3

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

MRTKv2のGuidesドキュメント

以下のドキュメントを読み進めていきます。
microsoft.github.io

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200312094520j:plain

MRTKでNearInteractionを追加する方法

NearInteractionスクリプトの例

タッチイベント

この例ではキューブを作成してタッチ可能にすることで、タッチで色を変更します。

public static void MakeChangeColorOnTouch(GameObject target)
{
    // Add and configure the touchable
    // タッチ可能を追加および構成
    var touchable = target.AddComponent<NearInteractionTouchableVolume>();
    touchable.EventsToReceive = TouchableEventType.Pointer;

    var material = target.GetComponent<Renderer>().material;
    // Change color on pointer down and up
    // ポインターの色を上下に変更します
    var pointerHandler = target.AddComponent<PointerHandler>();
    pointerHandler.OnPointerDown.AddListener((e) => material.color = Color.green);
    pointerHandler.OnPointerUp.AddListener((e) => material.color = Color.magenta);
}

f:id:bluebirdofoz:20200312094535j:plain

グラブイベント

以下の例は GameObject をドラッグ可能にする方法を示しています。
ゲームオブジェクトにコライダーが搭載されていると仮定します。

public static void MakeNearDraggable(GameObject target)
{
    // Instantiate and add grabbable
    // インスタンス化してグラブ可能を追加する
    target.AddComponent<NearInteractionGrabbable>();

    // Add ability to drag by re-parenting to pointer object on pointer down
    // ポインターオブジェクトの親を変更してドラッグする機能を追加します
    var pointerHandler = target.AddComponent<PointerHandler>();
    pointerHandler.OnPointerDown.AddListener((e) =>
    {
        if (e.Pointer is SpherePointer)
        {
            target.transform.parent = ((SpherePointer)(e.Pointer)).transform;
        }
    });
    pointerHandler.OnPointerUp.AddListener((e) =>
    {
        if (e.Pointer is SpherePointer)
        {
            target.transform.parent = null;
        }
    });
}

f:id:bluebirdofoz:20200312094545j:plain

MRTK v2のドキュメントを少しずつ読み解く MRTKでNearInteractionを追加する方法 その2

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

MRTKv2のGuidesドキュメント

以下のドキュメントを読み進めていきます。
microsoft.github.io

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200311095231j:plain

MRTKでNearInteractionを追加する方法

タッチ操作を追加する

UnityUI 要素にタッチインタラクションを追加するプロセスは標準的な 3D GameObjects とは異なります。
UnityUI コンポーネントを有効にするために、次の UnityUI のセクションにスキップできます。

ただし、両方のタイプのUX要素については PokePointer が Pointer プロファイルに登録されていることを確認してください。

デフォルトの MRTK プロファイルとデフォルトの HoloLens2 プロファイルには PokePointer が含まれています。
MRTK構成プロファイルを選択し、[Input] > [Pointers] > [Pointer Options] に移動して、PokePointer が作成されることを確認できます。
MRTK.SDK/Features/UX/Prefabs/Pointers/の配下の PokePointer プレハブが、[Controllered Type]を[Articulated Hand]に設定した状態で追加されていることを確認します。
または PokePointer クラスを実装しているカスタムプレハブを利用できます。
f:id:bluebirdofoz:20200311095246j:plain

3D GameObjects

タッチ可能にする必要がある GameObject で、コライダーと NearInteractionTouchable コンポーネントを追加します。

コンポーネントスクリプトで IMixedRealityTouchHandler インターフェイスを使用する場合は、[Event to Receive]を[Touch]に設定します。
その後、[Fix bounds]と[Fix Center]をクリックします。
f:id:bluebirdofoz:20200311095258j:plain

GameObject またはその親で IMixedRealityTouchHandler インターフェイスを実装するスクリプトコンポーネントを追加します。
NearInteractionTouchable を持つオブジェクトの親もポインターイベントを受け取ることができます。

注意

NearInteractionTouchable が設定された GameObject が選択されたエディターシーンビューで、白いアウトラインの正方形と矢印に注目してください。
矢印はタッチ可能オブジェクトの「前面」を指します。衝突可能オブジェクトはその方向からのみタッチ可能になります。
コライダーを全ての方向からタッチ可能にするには代わりに NearInteractionTouchableVolume を追加します。
f:id:bluebirdofoz:20200311095415j:plain

Unity UI

シーンにUnityUIキャンバスがあることを追加/確認します。

タッチ可能にしたい GameObject で NearInteractionTouchableUnityUI コンポーネントを追加します。

コンポーネントスクリプトで IMixedRealityTouchHandler インターフェイスを使用する場合は、[Event to Receive]を[Touch]に設定します。

GameObject またはその親で IMixedRealityTouchHandler インターフェイスを実装するスクリプトコンポーネントを追加します。
NearInteractionTouchableUnityUI を持つオブジェクトの親もポインターイベントを受け取ることができます。

重要

NearInteractionTouchable スクリプトコンポーネントの[Events to Receive]プロパティには2つのオプションがあります。
オプションは Pointer と Touch です。

入力イベントに応答/処理するコンポーネントスクリプトで IMixedRealityPointerHandler インターフェースを使用する場合は Pointer に設定します。
または IMixedRealityTouchHandler インターフェースを使用する場合は Touch に設定します。

タッチコードの例

以下のコードは NearInteractionTouchable バリアントコンポーネントを使用して GameObject にアタッチし、タッチ入力イベントに応答できる MonoBehaviour を示しています。

public class TouchEventsExample : MonoBehaviour, IMixedRealityTouchHandler
{
    public void OnTouchStarted(HandTrackingInputEventData eventData)
    {
        string ptrName = eventData.InputSource.SourceName;
        Debug.Log($"Touch started from {ptrName}");
    }
    public void OnTouchCompleted(HandTrackingInputEventData eventData) {}
    public void OnTouchUpdated(HandTrackingInputEventData eventData) { }
}

f:id:bluebirdofoz:20200311095651j:plain

MRTK v2のドキュメントを少しずつ読み解く MRTKでNearInteractionを追加する方法 その1

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

MRTKv2のGuidesドキュメント

以下のドキュメントを読み進めていきます。
microsoft.github.io

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200310035739j:plain

MRTKでNearInteractionを追加する方法

NearInteraction はタッチとグラブの形で提供されます。
タッチイベントとグラブイベントはそれぞれ PokePointer と SpherePointer によってポインターイベントとして発生します。

特定の GameObject でタッチイベントをリッスンしたり、入力イベントを取得するには3つの重要な手順が必要です。

1.関連するポインターがメインのMRTK構成プロファイルに登録されていることを確認してください。
2.目的の GameObject に適切なグラブまたはタッチスクリプトコンポーネントとコライダーがあることを確認します。
3.グラブまたはタッチイベントをリッスンするために、目的の GameObject に接続されたスクリプトに入力ハンドラーインターフェイスを実装します。

グラブインタラクションを追加する

1.プロファイルの設定

SpherePointer が Pointer プロファイルに登録されていることを確認してください。

デフォルトの MRTK プロファイルとデフォルトの HoloLens2 プロファイルには SpherePointer が含まれています。
SpherePointer が作成されていることを確認するにはMRTKの構成プロファイルを選択し、[Input] > [Pointers] > [Pointer Options]に移動します。
MRTK.SDK/Features/UX/Prefabs/Pointers/の配下の GrabPointer プレハブが、[Controllered Type]を[Articulated Hand]に設定した状態で追加されていることを確認します。
または SpherePointer クラスを実装しているカスタムプレハブを利用できます。
f:id:bluebirdofoz:20200310035755j:plain

2.NearInteractionGrabbableの設定

掴むべき GameObject に NearInteractionGrabbable とコライダーを追加します。
GameObject のレイヤーがグラブ可能なレイヤー上にあることを確認してください。
デフォルトでは Spatial Awareness および Ignore Raycasts を除くすべてのレイヤーはグラブ可能です。
GrabPointer プレハブのグラブレイヤーマスクを調べると、どのレイヤーがグラブ可能かを確認できます。
f:id:bluebirdofoz:20200310035805j:plain

3.IMixedRealityPointerHandlerの設定

GameObject またはその親で IMixedRealityPointerHandler インターフェイスを実装するスクリプトコンポーネントを追加します。
NearInteractionGrabbable を持つオブジェクトの親もポインターイベントを受け取ることができます。

グラブコードの例

以下はイベントがタッチまたはグラブの場合にログ出力するスクリプトです。
関連する IMixedRealityPointerHandler インターフェイス関数では MixedRealityPointerEventData を介してそのイベントをトリガーするポインターのタイプを見ることができます。
ポインターが SpherePointer の場合、相互作用はグラブです。

public class PrintPointerEvents : MonoBehaviour, IMixedRealityPointerHandler
{
    public void OnPointerDown(MixedRealityPointerEventData eventData)
    {
        if (eventData.Pointer is SpherePointer)
        {
            Debug.Log($"Grab start from {eventData.Pointer.PointerName}");
        }
        if (eventData.Pointer is PokePointer)
        {
            Debug.Log($"Touch start from {eventData.Pointer.PointerName}");
        }
    }

    public void OnPointerClicked(MixedRealityPointerEventData eventData) {}
    public void OnPointerDragged(MixedRealityPointerEventData eventData) {}
    public void OnPointerUp(MixedRealityPointerEventData eventData) {}
}

f:id:bluebirdofoz:20200310035824j:plain

MRTK v2のドキュメントを少しずつ読み解く ハンドトラッキング その2

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

MRTKv2のGuidesドキュメント

以下のドキュメントを読み進めていきます。
microsoft.github.io

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200309091911j:plain

ハンドトラッキング

スクリプティング

手の位置と回転は MixedRealityPose として、個々の手の関節の入力システムから要求できます。

あるいはジョイントに従う GameObject へのアクセスを許可します。
これは別の GameObject がジョイントを継続的に追跡する必要がある場合に役立ちます。

使用可能なジョイントは TrackedHandJoint 列挙型にリストされています。
microsoft.github.io

注意

ハンドトラッキングが失われると、ジョイントオブジェクトが破壊されます。
null エラーを回避するために、ジョイントオブジェクトを使用するスクリプトが適切に処理するようにしてください。

所定のハンドコントローラーへのアクセス

入力イベントを処理する場合などに、特定のハンドコントローラーが利用できることがあります。
この場合、IMixedRealityHand インタフェースを使うことで、デバイスからジョイントデータを直接要求できます。

コントローラからのジョイントポーズのポーリング

要求されたジョイントが何らかの理由で利用できない場合、TryGetJoint 関数は false を返します。
その場合、結果のポーズは MixedRealityPose.ZeroIdentity になります。

public void OnSourceDetected(SourceStateEventData eventData)
{
  var hand = eventData.Controller as IMixedRealityHand;
  if (hand != null)
  {
    if (hand.TryGetJoint(TrackedHandJoint.IndexTip, out MixedRealityPose jointPose))
    {
      // ...
    }
  }
}

f:id:bluebirdofoz:20200309091936j:plain

ハンドビジュアライザーからのジョイント変換

コントローラービジュアライザーからジョイントオブジェクトを要求できます。

public void OnSourceDetected(SourceStateEventData eventData)
{
  var handVisualizer = eventData.Controller.Visualizer as IMixedRealityHandVisualizer;
  if (handVisualizer != null)
  {
    if (handVisualizer.TryGetJointTransform(TrackedHandJoint.IndexTip, out Transform jointTransform))
    {
      // ...
    }
  }
}

f:id:bluebirdofoz:20200309091945j:plain

簡素化されたジョイントデータアクセス

特定のコントローラーが指定されていない場合、手関節データに簡単にアクセスできるユーティリティクラスが提供されます。
これらの関数は、現在追跡されている最初の利用可能なハンドデバイスからの共同データを要求します。

HandJointUtilsからのジョイントポーズのポーリング

HandJointUtils は最初のアクティブなハンドデバイスを照会する静的クラスです。

if (HandJointUtils.TryGetJointPose(TrackedHandJoint.IndexTip, Handedness.Right, out MixedRealityPose pose))
{
    // ...
}

f:id:bluebirdofoz:20200309091954j:plain

手関節サービスからの関節変換

IMixedRealityHandJointService はジョイントを追跡するための永続的な GameObjects のセットを保持します。

IMixedRealityHandJointService handJointService = null;
if (CoreServices.InputSystem != null)
{
    var dataProviderAccess = CoreServices.InputSystem as IMixedRealityDataProviderAccess;
    if (dataProviderAccess != null)
    {
        handJointService = dataProviderAccess.GetDataProvider<IMixedRealityHandJointService>();
    }
}

if (handJointService != null)
{
    Transform jointTransform = handJointService.RequestJointTransform(TrackedHandJoint.IndexTip, Handedness.Right);
    // ...
}

f:id:bluebirdofoz:20200309092004j:plain

ハンドトラッキングイベント

コントローラから直接データをポーリングすることが望ましくない場合、入力システムもイベントを提供します。

ジョイントイベント

IMixedRealityHandJointHandler はジョイント位置の更新を処理します。

public class MyHandJointEventHandler : IMixedRealityHandJointHandler
{
    public Handedness myHandedness;

    void IMixedRealityHandJointHandler.OnHandJointsUpdated(InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>> eventData)
    {
        if (eventData.Handedness == myHandedness)
        {
            if (eventData.InputData.TryGetValue(TrackedHandJoint.IndexTip, out MixedRealityPose pose))
            {
                // ...
            }
        }
    }
}

f:id:bluebirdofoz:20200309092015j:plain

メッシュイベント

IMixedRealityHandMeshHandler は関節式ハンドメッシュの変更を処理します。
ハンドメッシュはデフォルトでは有効になっていないことに注意してください。

public class MyHandMeshEventHandler : IMixedRealityHandMeshHandler
{
    public Handedness myHandedness;
    public Mesh myMesh;

    public void OnHandMeshUpdated(InputEventData<HandMeshInfo> eventData)
    {
        if (eventData.Handedness == myHandedness)
        {
            myMesh.vertices = eventData.InputData.vertices;
            myMesh.normals = eventData.InputData.normals;
            myMesh.triangles = eventData.InputData.triangles;

            if (eventData.InputData.uvs != null && eventData.InputData.uvs.Length > 0)
            {
                myMesh.uv = eventData.InputData.uvs;
            }

            // ...
        }
    }
}

f:id:bluebirdofoz:20200309092025j:plain

既知の問題点

.NETネイティブ

現在、.NETバックエンドを使用したマスタービルドには既知の問題があります。
.NET Nativeでは、Marshal.GetObjectForIUnknown を使用して IInspectable ポインターをネイティブコードからマネージコードにマーシャリングできません。
MRTKはこれを使用して SpatialCoordinateSystem を取得し、プラットフォームから手と目のデータを受信します。

この問題の回避策として、ネイティブの Mixed Reality Toolkit リポジトリでDLLソースを提供しました。
そこのREADMEの指示に従って、バイナリを Unity アセットの Plugins フォルダーにコピーしてください。
その後、MRTKで提供される WindowsMixedRealityUtilities スクリプトが解決します。

独自のDLLを作成するか、この回避策を既存のDLLに含めたい場合、回避策のコードは次のとおりです。

extern "C" __declspec(dllexport) void __stdcall MarshalIInspectable(IUnknown* nativePtr, IUnknown** inspectable)
{
    *inspectable = nativePtr;
}
[DllImport("DotNetNativeWorkaround.dll", EntryPoint = "MarshalIInspectable")]
private static extern void GetSpatialCoordinateSystem(IntPtr nativePtr, out SpatialCoordinateSystem coordinateSystem);

private static SpatialCoordinateSystem GetSpatialCoordinateSystem(IntPtr nativePtr)
{
    try
    {
        GetSpatialCoordinateSystem(nativePtr, out SpatialCoordinateSystem coordinateSystem);
        return coordinateSystem;
    }
    catch
    {
        UnityEngine.Debug.LogError("Call to the DotNetNativeWorkaround plug-in failed. The plug-in is required for correct behavior when using .NET Native compilation");
        return Marshal.GetObjectForIUnknown(nativePtr) as SpatialCoordinateSystem;
    }
}