Version: 2023.2
言語: 日本語
モバイルキーボード
2D ゲーム開発

Unity の XR 入力

Unityユーザーマニュアルのこのセクションでは、仮想現実 (VR)、 拡張現実 (AR)、 Windows Mixed Reality アプリケーションのために Unity がサポートするすべての入力デバイスに関する情報を提供します。このページでは、以下のトピックについて説明します。

XR プラットフォームには豊富な種類の入力機能があり、 ユーザーインタラクションを設計するときに便利です。アプリケーションは、位置、回転、タッチ、ボタン、ジョイスティック、指センサーを参照する特定のデータを使用できます。ただし、これらの入力機能へのアクセスは、プラットフォームによって大きく異なります。例えば、Vive と Oculus Rift の間には多少違いがありますが、VR 対応のデスクトッププラットフォームと Daydream のようなモバイルプラットフォームでは、さらに多くの違いがあります。

Unity は InputFeatureUsage と呼ばれる C# 構造体を提供します。これは、任意のプラットフォームの ユーザー入力にアクセスするための標準の一群の物理的なデバイス制御 (ボタンやトリガーなど) を定義します。これらは、名前によって入力タイプを識別するのに役立ちます。各 InputFeatureUsage 定義については XR.Input.CommonUsages を参照してください。

InputFeatureUsage は、一般的な入力アクションまたはタイプに対応します。例えば、Unity は、人差し指で制御する (使用する XR プラットフォームに関係なく)、シングル軸の入力に trigger と呼ばれる InputFeatureUsage を定義します。InputFeatureUsage を使用すると、その名前を使用して trigger 状態を取得できます。そのため、従来の Unity Input システムの軸 (または、一部の XR プラットフォームではボタン) を設定する必要はありません。

XR 入力マッピング

以下の表は、標準コントローラーの InputFeatureUsage の名前と、それらが一般的な XR システムのコントローラーにどのようにマップされるかを示しています。

InputFeatureUsage 機能タイプ 古い入力インデックス (左コントローラー/右コントローラー) WMR Oculus GearVR Daydream OpenVR (全般) Vive OpenVR 経由の Oculus OpenVR 経由の WMR
primary2DAxis 2D 軸 [(1,2)/(4,5)] タッチパッド ジョイスティック タッチパッド タッチパッド トラックパッド/ジョイスティック トラックパッド ジョイスティック ジョイスティック
trigger [9/10] Trigger Trigger Trigger Trigger Trigger Trigger Trigger Trigger
grip [11/12] グリップ グリップ バンパー グリップ グリップ グリップ グリップ
secondary2DAxis 2D 軸 [(17,18)/(19,20)] ジョイスティック タッチパッド
secondary2DAxisClick ボタン [18/19] ジョイスティック - クリック
primaryButton ボタン [2/0] [X/A] - 押す アプリケーション 主要 プライマリ(サンドイッチボタン)(1) 主要 [Y/B] メニュー
primaryTouch ボタン [12/10] [X/A] - タッチ
secondaryButton ボタン [3/1] [Y/B] - 押す 代替 代替 (X/A)
secondaryTouch ボタン [13/11] [Y/B] - タッチ
gripButton ボタン [4/5] グリップ - 押す グリップ - 押す グリップ - 押す グリップ - 押す グリップ - 押す グリップ - 押す
triggerButton ボタン [14/15] トリガー - 押す トリガー - 押す トリガー - 押す トリガー - 押す トリガー - 押す トリガー - 押す トリガー - タッチ トリガー - 押す
menuButton ボタン [6/7] メニュー スタート (左コントローラーのみ)
primary2DAxisClick ボタン [8/9] タッチパッド - クリック サムスティック - 押す タッチパッド - 押す タッチパッド - 押す トラックパッド/ジョイスティック - 押す トラックパッド - 押す ジョイスティック - 押す タッチパッド - 押す
primary2DAxisTouch ボタン [16/17] タッチパッド - タッチ サムスティック - タッチ タッチパッド - タッチ タッチパッド - タッチ トラックパッド/ジョイスティック - タッチ トラックパッド - タッチ ジョイスティック - タッチ タッチパッド - タッチ
batteryLevel バッテリー残量
userPresence ボタン ユーザープレゼンス ユーザープレゼンス

(1) サンドイッチボタンは Vive メニュー ボタンを指します。このボタンは、クロスプラットフォームアプリケーションをより適切に処理するために、menuButton ではなく primaryButton にマップされます。

InputFeatureUsage の定義は XR.Input.CommonUsages を参照してください。

入力デバイスへのアクセス

InputDevice は、 コントローラー、 携帯電話、ヘッドセットなどの物理的なデバイスを表します。デバイストラッキング、ボタン、ジョイスティック、その他の入力制御に関する情報が含まれます。InputDevice API の詳細については、InputDevice のドキュメントを参照してください。

現在 XR システムに接続されている入力デバイスにアクセスするには、XR.InputDevices クラスを使用します。接続されているすべてのデバイスのリストを取得するには、InputDevices.GetDevices を使用してください。

var inputDevices = new List<UnityEngine.XR.InputDevice>();
UnityEngine.XR.InputDevices.GetDevices(inputDevices);

foreach (var device in inputDevices)
{
    Debug.Log(string.Format("Device found with name '{0}' and role '{1}'", device.name, device.role.ToString()));
}

入力デバイスは、XR システムがそれを切断するまで、フレーム全体で有効です。InputDevice がまだアクティブなコントローラーを示しているかを判断するには、InputDevice.IsValid プロパティを使用します。

以下の方法で入力デバイスにアクセスできます。

  • 特性 (Characteristics)
  • ロール (Role)
  • XR ノード

特性による入力デバイスへのアクセス

デバイスの特性 (Characteristics) は、 デバイスの機能や使用目的 (ヘッドマウントかどうかなど) を表します。 InputDeviceCharacteristics は、特定の仕様に適合するデバイスを検索するためにコードに追加できる一連のフラグです。以下の特性でデバイスをフィルタリングできます。

デバイス 特徴
HeadMounted デバイスはユーザーの頭に装着されます。 デバイストラッキングとセンターアイトラッキングがあります。このフラグは、大抵、ヘッドマウントディスプレイ (HMD) を識別するために使用されます。
Camera デバイスにはカメラトラッキングがあります。
HeldInHand ユーザーはデバイスを手に持っています。
HandTracking デバイスは、物理的に追跡される手を表します。 デバイストラッキングがあり、手とボーンの データが含まれている場合があります。
EyeTracking このデバイスはアイトラッキングを実行でき、 EyesData 機能を備えています。
TrackedDevice デバイスは 3D スペースで追跡されます。 デバイストラッキング機能があります。
Controller デバイスはボタンと軸の入力 データを持ち、 コントローラーとして使用できます。
TrackingReference デバイスは静的トラッキング参照オブジェクトを表します。 デバイスのトラッキング機能がありますが、トラッキングデータを変更しないでください。
Left この特性をHeldInHandまたはHandTracking特性と組み合わせて使用して、 デバイスを左手に関連付けられていると識別します 。
Right この特性をHeldInHandまたはHandTracking特性と組み合わせて使用して、 デバイスを右手に関連付けられていると識別します 。
Simulated6DOF デバイスは 6DOF データを報告しますが、3DOF センサーしかありません。 Unityは位置データをシミュレートします。

基礎となるXR SDKはこれらの特性を報告します。 InputDevice.Characteristicsでそれらを調べることができます。 デバイスは複数の特性を持つことができ、多くの場合、それらをフィルタリングしてビットフラグでアクセスできます。

InputDevices.GetDevicesWithCharacteristicsは、特定の特性を持つすべてのデバイスを検索する方法を提供します。例えば、システムで使用可能なLeft、HeldInHand、Controller InputDevicesは以下のコードで検索できます。

var leftHandedControllers = new List<UnityEngine.XR.InputDevice>();
var desiredCharacteristics = UnityEngine.XR.InputDeviceCharacteristics.HeldInHand | UnityEngine.XR.InputDeviceCharacteristics.Left | UnityEngine.XR.InputDeviceCharacteristics.Controller;
UnityEngine.XR.InputDevices.GetDevicesWithCharacteristics(desiredCharacteristics, leftHandedControllers);

foreach (var device in leftHandedControllers)
{
    Debug.Log(string.Format("Device name '{0}' has characteristics '{1}'", device.name, device.characteristics.ToString()));
}

この関数が検出するデバイスには、少なくとも指定された特性が含まれますが、追加の特性も含まれる場合があります。例えば、左利きのコントローラーを見つけるには、InputDeviceCharacteristic.Leftのみを検索し、InputDeviceCharacteristic.Controllerは検索しません。

ロールによる入力デバイスへのアクセス

デバイスロールは、入力デバイスの一般的な機能を説明します。 InputDeviceRole列挙型を使用してデバイスの役割を指定します。定義されているロールは以下のとおりです。

ロール 説明
GameController コンソールスタイルのゲームコントローラー
Generic ヘッドマウントディスプレイ 、またはモバイルデバイスのようなコアXRデバイス。
HardwareTracker トラッキングデバイス。
LeftHanded ユーザーの左手に関連付けられたデバイス。
RightHanded ユーザーの右手に関連付けられたデバイス。
TrackingReference Oculus トラッキングカメラなどの他のデバイスを追跡するデバイス。

基礎となるXR SDKはこれらのロールを報告しますが、プロバイダーによってデバイスのロールの編成が異なる場合があります。さらに、 ユーザーは手を切り替えることができるため、ロールの割り当ては、 ユーザーが入力デバイスを持っている手とマッチしない場合があります。例えば、 ユーザーは Daydream コントローラーを右利き、または左利きに設定する必要がありますが、 コントローラーを反対の手に持つこともできます。

GetDevicesWithRoleは、特定の InputDeviceRole 持つデバイスのリストを提供します。例えば、 InputDeviceRole.GameController を使用して、接続されている GameController デバイスを取得できます。

var gameControllers = new List<UnityEngine.XR.InputDevice>();
UnityEngine.XR.InputDevices.GetDevicesWithRole(UnityEngine.XR.InputDeviceRole.GameController, gameControllers);

foreach (var device in gameControllers)
{
    Debug.Log(string.Format("Device name '{0}' has role '{1}'", device.name, device.role.ToString()));
}

XRノードによる入力デバイスへのアクセス

XRノードは、XRシステムでの物理的な基準点(例えば、ユーザーの頭の位置、右手と左手、Oculusカメラなどのトラッキング基準)を表します。

XRNode列挙は以下のノードを定義します。

XRノード 説明
CenterEye ユーザーの目の瞳孔の中間点。
GameController コンソールスタイルのゲームコントローラーアプリケーションは複数のゲームコントローラーデバイスを持つことができます。
HardwareTracker ハードウェアトラッキングデバイス。通常、ユーザーや物理的なアイテムに取り付けられます。複数のハードウェアトラッカーノードが可能です。
Head XRシステムによって計算された、ユーザーの頭の中心点。
LeftEye ユーザーの左目。
LeftHand ユーザーの左手。
RightEye ユーザーの右目。
RightHand ユーザーの右手。
TrackingReference Oculusカメラなどのトラッキング基準点。複数のトラッキング参照ノードが存在できます。

InputDevices.GetDevicesAtXRNodeを使用して、特定の XRNode に関連付けられたデバイスのリストを取得します。以下の例は、左利きのコントローラーを取得する方法を示しています。

var leftHandDevices = new List<UnityEngine.XR.InputDevice>();
UnityEngine.XR.InputDevices.GetDevicesAtXRNode(UnityEngine.XR.XRNode.LeftHand, leftHandDevices);

if(leftHandDevices.Count == 1)
{
    UnityEngine.XR.InputDevice device = leftHandDevices[0];
    Debug.Log(string.Format("Device name '{0}' with role '{1}'", device.name, device.role.ToString()));
}
else if(leftHandDevices.Count > 1)
{
    Debug.Log("Found more than one left hand!");
}

デバイスの接続と切断のリッスン

入力デバイスはフレームごとに一貫していますが、いつでも接続や切断が可能です。 デバイスがプラットフォームに接続されているかどうかを繰り返し確認しないようにするには、 InputDevices.deviceConnectedInputDevices.deviceDisconnectedを使用して、 デバイスが接続または切断されたときにアプリケーションに通知します。これらは、新しく接続された入力デバイスへの参照も提供します。

複数のフレームにわたってこれらの参照を保持できるため、デバイスが切断されることで、デバイスが使用できなくなることがあります。デバイスの入力がまだ使用可能かどうかを確認するには、InputDevice.isValidを使用します。 入力デバイスにアクセスするスクリプトは、デバイスを使用する前の各フレームの開始時に、これをチェックする必要があります。

入力 デバイスの 入力機能にアクセスする

トリガーボタンの状態などの入力機能を特定のInputDeviceから読み取ることができます。例えば、正しいトリガーの状態を読み取るには、以下の手順に従います。

  1. InputDeviceRole.RightHandedまたはXRNode.RightHandを使用して、右利きのデバイスのインスタンスを取得します。
  2. 正しいデバイスを取得したらInputDevice.TryGetFeatureValue 方法を使用して現在の状態にアクセスします。

TryGetFeatureValue() は、機能の現在の値へのアクセスを試み、以下を返します。

  • 指定された機能の値を正常に取得した場合はtrue
  • 現在のデバイスが指定された機能をサポートしていない場合、またはデバイスが無効な場合(つまり、コントローラーがアクティブでなくなった場合)はfalse

特定のボタン、タッチ入力、またはジョイスティックの軸の値を取得するには、 CommonUsages クラスを使用します。 CommonUsages には、XR 入力 マッピングテーブルの各 InputFeatureUsage と、位置や回転などのトラッキング機能が含まれます。次のコード例は、CommonUsages.triggerButtonを使用して、 ユーザーが現在、特定の InputDevice インスタンスのトリガーボタンを押しているかどうかを検出します。

bool triggerValue;
if (device.TryGetFeatureValue(UnityEngine.XR.CommonUsages.triggerButton, out triggerValue) && triggerValue)
{
    Debug.Log("Trigger button is pressed.");
}

InputDevice.TryGetFeatureUsages 方法を使用して、 デバイスが提供するすべての InputFeatureUsage リストを取得することもできます。この関数は、InputFeatureUsage 項目のリストを返します。項目は、機能を説明するtypeとname プロパティを持っています。次の例では、指定された入力デバイスが提供するすべてのブール機能を列挙します。

var inputFeatures = new List<UnityEngine.XR.InputFeatureUsage>();
if (device.TryGetFeatureUsages(inputFeatures))
{
    foreach (var feature in inputFeatures)
    {
        if (feature.type == typeof(bool))
        {
            bool featureValue;
            if (device.TryGetFeatureValue(feature.As<bool>(), out featureValue))
            {
                Debug.Log(string.Format("Bool feature {0}'s value is {1}", feature.name, featureValue.ToString()));
            }
        }
    }
}

primaryButtonの例

コントローラーの設定によって、使用できる機能は異なります。例えば、1つのシステムに複数のコントローラーを配置したり、異なるシステムに異なるコントローラーを配置したり、同じSDKの異なるコントローラーに異なるボタンを配置したりできます。この多様性により、さまざまなXRシステムからの入力をサポートすることがより複雑になります。 Unity InputFeatureUsage APIは、プラットフォームに依存しない入力を取得するのに役立ちます。

次の例では、アクセス InputFeatureUsage 呼ば primaryButton 、 コントローラーや入力 デバイスがそれを提供しない物質を。この例には、接続時に primaryButton 使用可能なデバイスをスキャンするクラスが含まれています。 クラスは接続されたデバイスの機能の値を監視し、値が変更された場合にクラスはUnityEventをディスパッチします。

このクラスを使用するには、シーン内の任意のゲームオブジェクトにコンポーネントとして追加します。以下はその例です。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.XR;

[System.Serializable]
public class PrimaryButtonEvent : UnityEvent<bool> { }

public class PrimaryButtonWatcher : MonoBehaviour
{
    public PrimaryButtonEvent primaryButtonPress;

    private bool lastButtonState = false;
    private List<InputDevice> devicesWithPrimaryButton;

    private void Awake()
    {
        if (primaryButtonPress == null)
        {
            primaryButtonPress = new PrimaryButtonEvent();
        }

        devicesWithPrimaryButton = new List<InputDevice>();
    }

    void OnEnable()
    {
        List<InputDevice> allDevices = new List<InputDevice>();
        InputDevices.GetDevices(allDevices);
        foreach(InputDevice device in allDevices)
            InputDevices_deviceConnected(device);

        InputDevices.deviceConnected += InputDevices_deviceConnected;
        InputDevices.deviceDisconnected += InputDevices_deviceDisconnected;
    }

    private void OnDisable()
    {
        InputDevices.deviceConnected -= InputDevices_deviceConnected;
        InputDevices.deviceDisconnected -= InputDevices_deviceDisconnected;
        devicesWithPrimaryButton.Clear();
    }

    private void InputDevices_deviceConnected(InputDevice device)
    {
        bool discardedValue;
        if (device.TryGetFeatureValue(CommonUsages.primaryButton, out discardedValue))
        {
            devicesWithPrimaryButton.Add(device); // Add any devices that have a primary button.
        }
    }

    private void InputDevices_deviceDisconnected(InputDevice device)
    {
        if (devicesWithPrimaryButton.Contains(device))
            devicesWithPrimaryButton.Remove(device);
    }

    void Update()
    {
        bool tempState = false;
        foreach (var device in devicesWithPrimaryButton)
        {
            bool primaryButtonState = false;
            tempState = device.TryGetFeatureValue(CommonUsages.primaryButton, out primaryButtonState) // did get a value
                        && primaryButtonState // the value we got
                        || tempState; // cumulative result from other controllers
        }

        if (tempState != lastButtonState) // Button state changed since last frame
        {
            primaryButtonPress.Invoke(tempState);
            lastButtonState = tempState;
        }
    }
}

次の PrimaryReactor クラスは PrimaryButtonWatcher を使用して、主ボタンが押されたことを検出し、 押されたことに応答して、親ゲームオブジェクトを回転させます。このクラスを使用するには、それをCubeなどの表示可能な PrimaryButtonWatcher オブジェクトに追加し、 PrimaryButtonWatcher 参照を Watcher プロパティにドラッグします。

using System.Collections;
using UnityEngine;

public class PrimaryReactor : MonoBehaviour
{
    public PrimaryButtonWatcher watcher;
    public bool IsPressed = false; // used to display button state in the Unity Inspector window
    public Vector3 rotationAngle = new Vector3(45, 45, 45);
    public float rotationDuration = 0.25f; // seconds
    private Quaternion offRotation;
    private Quaternion onRotation;
    private Coroutine rotator;

    void Start()
    {
        watcher.primaryButtonPress.AddListener(onPrimaryButtonEvent);
        offRotation = this.transform.rotation;
        onRotation = Quaternion.Euler(rotationAngle) * offRotation;
    }

    public void onPrimaryButtonEvent(bool pressed)
    {
        IsPressed = pressed;
        if (rotator != null)
            StopCoroutine(rotator);
        if (pressed)
            rotator = StartCoroutine(AnimateRotation(this.transform.rotation, onRotation));
        else
            rotator = StartCoroutine(AnimateRotation(this.transform.rotation, offRotation));
    }

    private IEnumerator AnimateRotation(Quaternion fromRotation, Quaternion toRotation)
    {
        float t = 0;
        while (t < rotationDuration)
        {
            transform.rotation = Quaternion.Lerp(fromRotation, toRotation, t / rotationDuration);
            t += Time.deltaTime;
            yield return null;
        }
    }
}

ハンドトラッキングデータへのアクセス

InputDevicesはハンドトラッキングデバイスをサポートします。ハンドトラッキングデバイスは常に、

ハンドトラッキングデータは、Hand オブジェクトと一連の最大21のBone 入力機能で構成されます。各Boneには位置と方向があり、階層内の親Boneと子Boneの両方への参照があります。 Hand オブジェクトは、 ルートの ボーン、または個々の指のボーンのリストのいずれかを取得できます。

Hand.TryGetRootBone がルートのボーンを取得すると、手首の真上にあるボーンを表すオブジェクトを取得します。個々の指を表すボーンのリストを取得することもできます。Hand.TryGetFingerBones を呼び出すと、指を表すボーンの指関節 (knuckle) から先端までのリストを返します。

アイトラッキングデータへのアクセス

入力デバイスは、アイトラッキングデバイスとハンドトラッキングデバイスをサポートしています。アイトラッキングは、左目と右目の位置、 ユーザーが見ている3D スペースの位置、個々の目が点滅している量で構成されます。データ型は Eyesです。デバイスから取得するにはCommonUsages.eyesDataを使用します。

XRInputSubsystemとInputDeviceの関連付け

Unity は 2 つの入力システムを提供します。古い入力システムと 2019.2 で導入されたXR プラグインアーキテクチャです。新しい設定では、各 InputDevice は XRInputSubsystem に関連付けられています。これらのサブシステムオブジェクトは、特定の入力デバイスに関連付けられていないグローバルな入力動作を制御します (例えば、追跡元の管理や追跡されたデバイスのリセンターなど)。

各 InputDevice には、関連するサブシステムへの参照が含まれています。統合プラットフォームのデバイスの場合、この参照は null です。また、SubsystemManager.GetInstances<XRInputSubsystem> を使って、すべてのアクティブな XRInputSubsystem オブジェクトを取得することができます。各 XRInputSubsystem のデバイスは、XRInputSubsystem.TryGetInputDevices を使って取得できます。

Input Subsystem を使って、UnityEngine.XR.XRInputSubsystem を持つデバイスをリセンターできます。リセンターは、HMD の現在の位置をすべてのデバイスの新しい原点として設定します。リセンターできないデバイスの場合、またはプラットフォームがリセンター機能をサポートしていない場合は false を返します。

トラッキング範囲を取得するには、 TryGetBoundaryPoints を使用します。これは一連の右回りの 3D 位置で構成され、Y 値はフロアレベルにあり、ユーザーが指定した “セーフゾーン” をマークしてコンテンツとインタラクションを配置します。XRInputSubsystem.boundaryChanged を使用して、この境界に対する変更をリッスンできます。

XRInputSubsystem はトラッキング原点モードも把握します。トラッキング原点モードは、トラッキングワールドの原点のコンテキストを提供します。Unity は以下のトラッキング原点モードをサポートしています。

  • Device: 原点の位置は、主要ディスプレイデバイスの最初の既知の位置です。多くの場合、HMD やスマートフォンです。
  • Floor: 原点の位置は、床上の既知の位置です。
  • Tracking Reference: 原点の位置は、TrackingReference 特性がある InputDevice にあります。
  • Unknown: トラッキング原点のタイプが不明です。これは、システム障害やトラッキング元のモードのサポートの欠如が原因である可能性があります。

トラッキング元モードの管理に使用できる API は 3 つあります。

古い入力システムによる XR 入力

古い入力システム使うこともできます。InputXR.InputTracking を使い、XR 入力機能を取得します。これを行うには、このページの XR input mappings table の適切な古い入力インデックスを使います。Player 設定 (Edit > Project Settings > Input) の Input セクションで軸のマッピングを行い、入力名からプラットフォームデバイス機能の軸インデックスに適切なマッピングを加えます。ボタンや軸の値を取得するには、 Input.GetAxis または Input.GetButton を使用し、マップされた軸またはボタン名にパスします。

ボタンとジョイスティックの軸の使い方の詳細は、 InputManager のドキュメントを参照してください。

ハプティクス

ハプティクス (触覚) イベントを InputDevice に送信できます。ハプティクスは、振幅と継続時間によるインパルスの形をとります。

すべてのプラットフォームがすべてのタイプのハプティクスに対応しているわけではありませんが、デバイスにハプティックの能力を照会することができます。以下の例では、右手用の入力デバイスを使用し、デバイスがハプティクスに対応できるかどうかを確認します。次に、それが可能な場合は、刺激を再生します。

List<UnityEngine.XR.InputDevice> devices = new List<UnityEngine.XR.InputDevice>(); 

UnityEngine.XR.InputDevices.GetDevicesWithRole(UnityEngine.XR.InputDeviceRole.RightHanded, devices);

foreach (var device in devices)
{
    UnityEngine.XR.HapticCapabilities capabilities;
    if (device.TryGetHapticCapabilities(out capabilities))
    {
            if (capabilities.supportsImpulse)
            {
                uint channel = 0;
                float amplitude = 0.5f;
                float duration = 1.0f;
                device.SendHapticImpulse(channel, amplitude, duration);
            }
    }
}
モバイルキーボード
2D ゲーム開発