ポインター — MRTK2

ポインター

この記事では、実際にポインター入力を構成して応答する方法について説明します。 複数のポインターを高レベルで制御する方法を理解するには、「 ポインター アーキテクチャ」を参照してください。

新しいコントローラーが検出されると、実行時にポインターが自動的にインスタンス化されます。 1 つのコントローラーに複数のポインターをアタッチできます。 たとえば、既定のポインター プロファイルを使用すると、Windows Mixed Reality コントローラーによって、通常の選択とテレポート用に、それぞれ直線と放物線の両方のポインターが取得されます。

ポインターの構成

ポインターは、MixedRealityPointerProfile を介して MRTK の入力システムの一部として構成されます。 この種類のプロファイルは、MRTK 構成インスペクターの MixedRealityInputSystemProfile に割り当てられます。 ポインター プロファイルでは、カーソルと、実行時に使用できるポインターの種類と、それらのポインターが相互に通信してアクティブなものを特定する方法とを決定します。

  • [ポイントの範囲] - ポインターが、GameObject と対話できる最大距離を定義します。

  • [ポイントのレイキャストのレイヤー マスク] - これは、指定されたポインターが対話できる可能性のある GameObject と、対話を試みる順序を決定するための、優先順位が付けられた LayerMask の配列です。 これは、ポインターが他のシーン オブジェクトの前に最初に UI 要素と対話するようにするのに役立つ場合があります。 ポインター プロファイルの例

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

既定の MRTK ポインター プロファイル構成には、次のポインター クラスと関連するプレハブが既定で含まれています。 実行時にシステムで使用できるポインターの一覧は、ポインター プロファイルの [ポインター オプション] に定義されています。 開発者は、この一覧を利用して、既存のポインターの再構成、新しいポインターの追加、または削除を行うことができます。

ポインター オプション プロファイルの例

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

  • [コントローラーの種類] - ポインターが有効なコントローラーのセット。

    • たとえば、PokePointer は、オブジェクトを指で "つつく" 役割を担い、既定では、多関節ハンド コントローラーの種類のみをサポートするようにマークされています。 ポインターがインスタンス化されるのは、コントローラーが使用可能になったときだけです。特に、[コントローラーの種類] によって、このポインターのプレハブを作成できるコントローラーが定義されます。
  • [利き手] - 特定の手 (左/右) に対してのみポインターをインスタンス化することを許可します

Note

ポインター エントリの [利き手] プロパティを [なし] に設定すると、そのポインターを一覧から削除する代わりに、システムから実質的に無効になります。

  • [ポインターのプレハブ] - 指定したコントローラーの種類と利き手に一致するコントローラーが追跡を開始すると、このプレハブ アセットがインスタンス化されます。

コントローラーに複数のポインターを関連付けすることができます。 たとえば、DefaultHoloLens2InputSystemProfile (Assets/MRTK/SDK/Profiles/HoloLens2/) では、多関節コントローラーは PokePointerGrabPointer、および DefaultControllerPointer (つまり、ハンド レイ) に関連付けられています。

Note

MRTK には、Assets/MRTK/SDK/Features/UX/Prefabs/Pointers にポインターのプレハブのセットが用意されています。 Assets/MRTK/SDK/Features/UX/Scripts/Pointers のいずれかのポインター スクリプト、または IMixedRealityPointer を実装する他のスクリプトが含まれている限り、新しいカスタムのプレハブを構築できます。

カーソルの構成

視線カーソルは、エディター内で MixedRealityInputSystemProfile 上の GazeCursorPrefab プロパティを使用して直接構成することができます。 他のポインターに使用されるカーソルを構成するには、対応する CursorPrefabBaseControllerPointer フィールドで使用されるプレハブを変更する必要があります。 カーソルをプログラムで変更するには、対応する IMixedRealityPointer 動作上の BaseCursor プロパティを変更します。

Cursor Prefab プロパティ

カーソルの動作の実装例については、Assets/MRTK/SDK/Features/UX/Prefabs/Cursors にあるカーソル プレハブを参照してください。 特に、DefaultGazeCursor には、コンテキスト状態に基づいてカーソルのグラフィックを変更する堅牢な実装が用意されています。

既定のポインター クラス

次のクラスは、上記で説明した既定の "MRTK ポインター プロファイル" で使用できる既定の MRTK ポインターです。 Assets/MRTK/SDK/Features/UX/Prefabs/Pointers の下に用意されている各ポインターのプレハブには、アタッチされたポインター コンポーネントのいずれかが含まれています。

MRTK の既定のポインター

far ポインター

LinePointer

LinePointer (基本ポインター クラス) は、ポインターの方向に入力のソース (コントローラー) から線を描き、この方向での 1 つのレイキャストをサポートします。 通常は、主に共通の機能を提供するこのクラスの代わりに、ShellHandRayPointer やテレポート ポインターなどの子クラスがインスタンス化されて利用されます (テレポートがどこに到達するかを示す線も描画されます)。

Oculus、Vive、Windows Mixed Reality のようなモーション コントローラーの場合、回転はコントローラーの回転と一致します。 HoloLens 2 多関節ハンドなどの他のコントローラーの場合、回転はシステムが提供する手のポイント姿勢と一致します。

MRTK ポインター行
CurvePointer

CurvePointer は、曲線に沿った複数ステップのレイキャストを可能にすることで、LinePointer クラスを拡張します。 この基本ポインター クラスは、線が常に放物線に曲がるテレポート ポインターなどの曲線インスタンスに役立ちます。

ShellHandRayPointer

LinePointer から拡張された ShellHandRayPointer の実装は、"MRTK ポインター プロファイル" の既定として使用されます。 DefaultControllerPointer プレハブは、ShellHandRayPointer クラスを実装します。

GGVPointer

Gaze/Gesture/Voice (GGV) ポインターとも呼ばれる GGVPointer は、主に、視線入力とエアタップまたは視線入力と音声の選択という操作によって、HoloLens 1 スタイルの外観とタップの操作を強化します。 GGV ポインターの位置と方向は、頭の位置と回転によって決まります。

TouchPointer

TouchPointerは、Unity タッチ入力 (つまり、タッチスクリーン) の操作を行います。 スクリーンにタッチする行為はカメラからシーン内の潜在的に遠い場所に光線をキャストするため、これらは "遠距離の操作" です。

MousePointer

MousePointer は、タッチではなくマウスでの遠距離の操作のために、ワールドのレイキャストにスクリーンを使用します。

マウス ポインター

Note

マウスのサポートは、MRTK では既定では使用できませんが、型 MouseDeviceManager の新しい "入力データ プロバイダー" を MRTK 入力プロファイルに追加し、MixedRealityMouseInputProfile をデータ プロバイダーに割り当てることで有効にできます。

near ポインター

PokePointer

PokePointer は、"近距離操作 - タッチ可能" をサポートするゲーム オブジェクトと対話するために使用されます。 これは、NearInteractionTouchable スクリプトがアタッチされている GameObjects です。 UnityUI の場合、このポインターは NearInteractionTouchableUnityUI を検索します。 PokePointer は SphereCast を使用して最も近いタッチ可能な要素を決定し、押しボタンなどを強化するために使用されます。

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

便利な指さしポインターのプロパティ:

  • [タッチ可能距離]: タッチ可能な画面を操作できる最大距離
  • [視覚効果]: 指先の視覚効果をレンダリングするために使用されるゲーム オブジェクト (既定では、指での輪)。
  • [直線]: 指先からアクティブな入力画面に描画する省略可能な線。
  • [指さしレイヤー マスク] - ポインターで操作できる可能性のある GameObject と、操作を試みる順序を決定するための、優先順位が付けられた LayerMask の配列。 指さしポインターを操作するには、GameObject にも NearInteractionTouchable コンポーネントが必要であることに注意してください。
ポケ ポインター
SpherePointer

SpherePointer は、操作のために最も近い NearInteractionGrabbable オブジェクトを識別するために UnityEngine.Physics.OverlapSphere を使用します。これは、ManipulationHandler のような "グラブ可能な" 入力に便利です。 PokePointer/NearInteractionTouchable 機能ペアと同様に、球体ポインターを使用して対話可能にするためには、ゲーム オブジェクトに NearInteractionGrabbable スクリプトであるコンポーネントが含まれている必要があります。

グラブ ポインター

便利な球体ポインターのプロパティ:

  • [球体キャスト半径]: グラブ可能なオブジェクトのクエリに使用される球体の半径。
  • [近距離オブジェクトの余白]: オブジェクトがポインターの近くにあるかどうかを検出するためにクエリを実行するための、球体キャスト半径の上部の距離。 近距離オブジェクトの検出半径の合計は [球体のキャスト半径] + [近距離オブジェクトの余白] です
  • [近距離オブジェクト セクターの角度]: 近くにあるオブジェクトのクエリを実行するための、ポインターの前方の軸を中心とする角度。 円錐のような IsNearObject クエリ関数を作成します。 これは、Hololens 2 の動作と一致させるために、既定では 66 度に設定されます

前方方向のオブジェクトに対してのみクエリを実行するように変更された球ポインター

  • [近距離オブジェクトのスムージング係数]: 近距離オブジェクトの検出のためのスムージング係数。 [近距離オブジェクトの半径] でオブジェクトが検出された場合、クエリが実行された半径は [近距離オブジェクトの半径] * (1 + [近距離オブジェクトのスムージング係数]) になって感度が低下し、オブジェクトが検出範囲を離れにくくなります。
  • [グラブ レイヤー マスク] - ポインターで操作できる可能性のある GameObject と、操作を試みる順序を決定するための、優先順位が付けられた LayerMask の配列。 SpherePointer を操作するには、GameObject にも NearInteractionGrabbable が必要であることに注意してください。

    Note

    MRTK によって提供される既定の GrabPointer プレハブでは、空間認識レイヤーは無効になっています。 これは、空間メッシュで球体オーバーラップ クエリを実行した場合のパフォーマンスへの影響を軽減するために行われます。 これは GrabPointer プレハブを変更することで有効にできます。

  • [視野角内にないコライダーを無視する] - ポインターの近くにあるが、実際にはビジュアル視野角にない可能性があるコライダーを無視するかどうか。 これにより誤ったグラブを防ぐことができ、グラブ可能な場所の近くにいる可能性があるのに見えないときに、ハンド レイをオンにすることができます。 ビジュアル視野角は、パフォーマンス上の理由から、通常の視錐台ではなく、円錐で定義されています。 この円錐は中心に配置され、カメラの視錐台と同じ方向であり、半径はディスプレイの高さの半分 (または垂直視野角) に等しくなります。
Sphere ポインター

テレポート ポインター

  • TeleportPointer は、ユーザーを移動させるためにアクションが実行された (つまり、テレポート ボタンが押された) ときにテレポート要求を発生させます。
  • ParabolicTeleportPointer は、ユーザーを移動させるために放物線のレイキャストでアクションが実行された (つまり、テレポート ボタンが押された) ときにテレポート要求を発生させます。
ポインターパラボリック

複合現実プラットフォームのポインターのサポート

次の表では、MRTK の共通プラットフォームで通常使用されるポインターの種類について詳しく説明します。 注: これらのプラットフォームには、さまざまなポインターの種類を追加できます。 たとえば、VR に指さしポインターまたは球体ポインターを追加することができます。 さらに、ゲームパッドを備えた VR デバイスでは、GGV ポインターを使用できます。

ポインター OpenVR Windows Mixed Reality HoloLens 1 HoloLens 2
ShellHandRayPointer 有効 有効 有効
TeleportPointer 有効 有効
GGVPointer 有効
SpherePointer 有効
PokePointer 有効

コードによるポインターの操作

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

次の 1 つ以上のインターフェイスを実装し、Collider を使用して GameObject オブジェクトに割り当てられている MonoBehaviours は、関連付けられているインターフェイスで定義されているように、ポインターによる操作イベントを受信します。

Event 説明 Handler
フォーカス変更の前/フォーカス変更 ポインターがフォーカスを変更するたびに、ゲーム オブジェクトがフォーカスを失ったときと取得したときの両方で発生します。 IMixedRealityFocusChangedHandler
フォーカスに入る/出る 最初のポインターが入るとフォーカスを取得し、最後のポインターが離れるとフォーカスを失うゲーム オブジェクトで発生します。 IMixedRealityFocusHandler
ポインターのダウン/ドラッグ時/アップ/クリック時 ポインターのプレス、ドラッグ、リリースをレポートするために発生します。 IMixedRealityPointerHandler
タッチの開始/更新/完了 タッチ アクティビティをレポートするために、PokePointer のようなタッチ認識ポインターによって発生します。 IMixedRealityTouchHandler

Note

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

ポインター入力イベントの動作

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

  1. MRTK 入力システムは、入力イベントが発生したと認識します
  2. MRTK 入力システムは、すべての登録済みグローバル入力ハンドラーに対して、入力イベントに関連するインターフェイス関数を起動します
  3. 入力システムは、イベントを起動するポインターのフォーカスがある GameObject を特定します
    1. 入力システムは、Unity のイベント システムを使用して、フォーカスがある GameObject 上の一致するコンポーネントすべてに関連するインターフェイス関数を起動します
    2. どの時点でも入力イベントが使用済みとしてマークされたら、プロセスは終了し、GameObjects はそれ以降のコールバックを受け取りません。
      • 例: インターフェイス IMixedRealityFocusHandler を実装するコンポーネントは、フォーカスを取得したり失ったりする GameObject について検索されます
      • 注: 目的のインターフェイスに一致するコンポーネントが現在の GameObject 上で見つからない場合、Unity イベント システムはバブルアップして親 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.OnPointerDown(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerDragged(
         MixedRealityPointerEventData eventData) { }

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

クエリ ポインター

使用可能な入力ソース (使用可能なコントローラーと入力) をループ処理して、現在アクティブなすべてのポインターを収集して、アタッチされているポインターを検出することができます。

var pointers = new HashSet<IMixedRealityPointer>();

// Find all valid pointers
foreach (var inputSource in CoreServices.InputSystem.DetectedInputSources)
{
    foreach (var pointer in inputSource.Pointers)
    {
        if (pointer.IsInteractionEnabled && !pointers.Contains(pointer))
        {
            pointers.Add(pointer);
        }
    }
}

プライマリ ポインター

開発者は FocusProviders PrimaryPointerChanged イベントをサブスクライブして、フォーカスがあるプライマリ ポインターが変更されたときに通知を受けることができます。 これは、ユーザーが視線入力、ハンド レイ、または別の入力ソースを使用してシーンを現在操作している場合に非常に便利です。

private void OnEnable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.SubscribeToPrimaryPointerChanged(OnPrimaryPointerChanged, true);
}

private void OnPrimaryPointerChanged(IMixedRealityPointer oldPointer, IMixedRealityPointer newPointer)
{
    ...
}

private void OnDisable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.UnsubscribeFromPrimaryPointerChanged(OnPrimaryPointerChanged);

    // This flushes out the current primary pointer
    OnPrimaryPointerChanged(null, null);
}

PrimaryPointerExample(Assets/MRTK/Examples/Demos/Input/Scenes/PrimaryPointer) シーンは、イベントに PrimaryPointerChangedHandler を使用して新しいプライマリ ポインターに応答する方法を示しています。

プライマリ ポインターの例

ポインターの結果

ポインターの Result プロパティには、フォーカスのあるオブジェクトを特定するために使用されるシーン クエリの現在の結果が含まれています。 モーション コントローラー、視線入力、ハンド レイ用に既定で作成されたもののようなレイキャスト ポインターの場合、ヒットしたレイキャストの位置と法線が含まれます。

private void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
{
    var result = eventData.Pointer.Result;
    var spawnPosition = result.Details.Point;
    var spawnRotation = Quaternion.LookRotation(result.Details.Normal);
    Instantiate(MyPrefab, spawnPosition, spawnRotation);
}

PointerResultExample シーン (Assets/MRTK/Examples/Demos/Input/Scenes/PointerResult/PointerResultExample.unity) は、ポインター Result を使用して、ヒット位置にオブジェクトを生成する方法を示しています。

ポインターの結果

ポインターを無効にする

ポインターを有効および無効にする (たとえば、ハンド レイを無効にする) には、PointerUtils を使用して指定したポインターの種類に PointerBehavior を設定します。

// Disable the hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff);

// Disable hand rays for the right hand only
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Right);

// Disable the gaze pointer
PointerUtils.SetGazePointerBehavior(PointerBehavior.AlwaysOff);

// Set the behavior to match HoloLens 1
// Note, if on HoloLens 2, you must configure your pointer profile to make the GGV pointer show up for articulated hands.
public void SetHoloLens1()
{
    PointerUtils.SetPokePointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGrabPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGGVBehavior(PointerBehavior.Default);
}

その他の例については、PointerUtils および TurnPointersOnOff を参照してください。

エディターによるポインターの操作

IMixedRealityPointerHandler によって処理されるポインター イベントの場合、MRTK は PointerHandler コンポーネントの形式でさらに便利になり、Unity イベントを介してポインター イベントを直接処理できるようになります。

ポインター ハンドラー

ポインターの範囲

far ポインターには、レイキャストしてシーン内の他のオブジェクトを操作する距離を制限する設定があります。 既定では、この値は 10 m に設定されます。 この値は、HoloLens シェルの動作と一貫性を維持するために選ばれました。

これは、DefaultControllerPointer プレハブの ShellHandRayPointer コンポーネントのフィールドを更新することによって変更できます。

[ポインターの範囲] - これは、ポインターで操作する最大距離を制御します。

[既定のポインターの範囲] - これは、ポインターが何も操作していない場合にレンダリングされる、ポインターの光線/線の長さを制御します。

関連項目