Version: 6000.3
语言: 中文
移动键盘
传统输入

Unity XR 输入

Unity 用户手册的这一部分提供了有关所有 Unity 支持的输入设备的信息虚拟现实虚拟现实 (VR) 使用耳机和运动跟踪,让用户沉浸在逼真的图像和声音的人工 3D 世界中。更多信息
请参阅术语表
,增强现实增强现实 (AR) 使用在实时视频源之上合成的计算机图形或视频来增强视图并创建与真实和虚拟对象的交互。更多信息
请参阅术语表
和 Windows混合现实混合现实 (MR) 将自己的虚拟环境与用户的现实世界环境相结合,并允许他们相互交互。
请参阅术语表
应用。本页涵盖以下主题:

XR 平台具有丰富的输入功能,您可以在设计用户交互时利用这些功能。应用程序可以使用引用位置、旋转、触摸、按钮、纵杆和手指传感器的特定数据。但是,对这些输入功能的访问可能因平台而异。例如,Vive 和 Oculus Rift 之间存在细微差异,但支持 VR 的桌面平台和像 Daydream 这样的移动平台的差异要大得多。

Unity 提供了一个名为 InputFeatureUsage 的 C# 结构,它定义了一组标准的物理设备控件(例如按钮和触发器),用于访问任何平台上的用户输入。这些可帮助您按名称识别输入类型。请参阅 XR。Input.CommonUsages 用于每个InputFeatureUsage.

InputFeatureUsage对应于常见的输入作或类型。例如,Unity 定义了InputFeatureUsagetrigger作为食指控制的单轴输入,无论哪个XR一个总称,包括虚拟现实 (VR)、增强现实 (AR) 和混合现实 (MR) 应用。支持这些形式的交互式应用程序的设备可以称为 XR 设备。更多信息
请参阅术语表
您使用的平台。您可以使用InputFeatureUsage要获取trigger状态,因此您无需为传统的 Unity 输入系统设置轴(或某些 XR 平台上的按钮)。

XR 输入映射

下表列出了标准控制器InputFeatureUsage名称以及它们如何映射到流行的 XR 系统的控制器:

输入功能用法 特征类型 传统输入索引(左控制器/右控制器) WMR的 Oculus 齿轮VR 白日梦 OpenVR(完整版) 维夫 Oculus 通过 OpenVR 通过 OpenVR 的 WMR
primary2DAxis 二维轴 [(1,2)/(4,5)] 触摸板 操纵杆 触摸板 触摸板 触控板/纵杆 触控板 操纵杆 操纵杆
触发 [9/10] 触发 触发 触发 触发 触发 触发 触发 触发
[11/12] 缓冲器
中学2DAxis 二维轴 [(17,18)/(19,20)] 操纵杆 触摸板
辅助2DAxisClick 按钮 [18/19] 纵杆 - 单击
主按钮 按钮 [2/0] [X/A] - 按 应用程序 主要 主(夹层按钮)(1) 小学 (Y/B) 菜单
主触摸 按钮 [12/10] [X/A] - 触摸
辅助按钮 按钮 [3/1] [Y/B] - 按 互生 备用 (X/A)
次级触摸 按钮 [13/11] [Y/B] - 触摸
握把按钮 按钮 [4/5] 握把 - 按压 握把 - 按压 握把 - 按压 握把 - 按压 握把 - 按压 握把 - 按压
触发按钮 按钮 [14/15] 触发器 - 按 触发器 - 按 触发器 - 按 触发器 - 按 触发器 - 按 触发器 - 按 触发器 - 触摸 触发器 - 按
menu按钮 按钮 [6/7] 菜单 开始(仅限左侧控制器)
主2DAxis单击 按钮 [8/9] 触摸板 - 单击 摇杆 - 按 触摸板 - 按 触摸板 - 按 触控板/纵杆 - 按 触控板 - 按 纵杆 - 按 触摸板 - 按
主2DAxisTouch 按钮 [16/17] 触摸板 - 触摸 摇杆 - 触摸 触摸板 - 触摸 触摸板 - 触摸 触控板/纵杆 - 触摸 触控板 - 触控 纵杆 - 触摸 触摸板 - 触摸
电池电平 电池电量
用户存在 按钮 用户状态 用户状态

(1) 三明治按钮是指 Vive 菜单按钮。此按钮映射到 primaryButton,而不是 menuButton,以便更好地处理跨平台应用程序。

请参阅 XR。Input.CommonUsages 用于每个InputFeatureUsage.

访问输入设备

InputDevice 表示任何物理设备,例如控制器、移动电话或头戴显示设备。它可以包含有关设备跟踪、按钮、纵杆和其他输入控件的信息。有关InputDeviceAPI,请参阅 InputDevice 上的文档。

使用 XR。InputDevices 类来访问当前连接到 XR 系统的输入设备。若要获取所有已连接设备的列表,请使用 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.IsValid 属性确定InputDevice仍然表示活动控制器。

您可以通过以下方式访问输入设备:

  • 特性
  • 角色
  • XR 节点

按特性访问输入设备

设备特征描述了设备的功能或用途(例如,它是否是头戴式的)。InputDeviceCharacteristics 是一系列标志,您可以添加到代码中以搜索符合特定规范的设备。您可以按以下特征筛选设备:

装置 特征
头戴式 该设备连接到用户的头部。它具有设备跟踪和中心眼动跟踪功能。此标志最常用于标识头戴式显示器 (HMD)。
相机在场景中创建特定视点图像的组件。输出要么绘制到屏幕上,要么作为纹理捕获。更多信息
请参阅术语表
该设备具有摄像头跟踪功能。
HeldInHand (手持手) 用户将设备握在手中。
手部追踪 该设备代表一只物理跟踪的手。它具有设备跟踪功能,并且可能包含手部和骨骼数据。
眼动追踪 该设备可以执行眼动追踪并具有 EyesData 功能。
跟踪设备 该设备可以在 3D 空间中进行跟踪。它具有设备跟踪功能。
控制器 该设备具有按钮和轴的输入数据,可用作控制器。
跟踪参考 设备表示静态跟踪引用对象。它具有设备跟踪功能,但跟踪数据不应更改。
将此特征与 HeldInHand 或 HandTracking 特征结合使用,以识别与左手关联的设备。
将此特征与 HeldInHand 或 HandTracking 特征结合使用,以将设备标识为与右手关联。
模拟6DOF(模拟6自由度) 该设备报告 6DOF 数据,但只有 3DOF 传感器。Unity 模拟位置数据。

XR 提供程序插件在 Unity 外部创建的一组代码,用于在 Unity 中创建功能。可以在 Unity 中使用两种插件:托管插件(使用 Visual Studio 等工具创建的托管 .NET 程序集)和本机插件(特定于平台的本机代码库)。更多信息
请参阅术语表
报告这些特征。您可以使用 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 枚举指定设备角色。定义的角色包括:

角色 描述
游戏控制器 控制台风格游戏控制器控制游戏中对象和角色的设备。
请参阅术语表
.
通用 表示核心 XR 设备的设备,例如头戴式显示器或移动设备。
硬件跟踪器 跟踪设备。
左撇子 与用户左手关联的设备。
右撇子 与用户右手关联的设备。
跟踪参考 跟踪其他设备的设备,例如 Oculus 跟踪相机。

XR 提供程序插件报告这些角色,但不同的提供程序可能以不同的方式组织其设备角色。此外,用户可以切换手,因此角色分配可能与用户握住输入设备的手不匹配。例如,用户必须将 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 节点 描述
中心眼 用户眼睛瞳孔之间的一个点。
游戏控制器 控制台式游戏控制器。你的应用可以有多个游戏控制器设备。
硬件跟踪器 硬件跟踪设备,通常附加到用户或物理项目。可以存在多个硬件跟踪器节点。
XR 系统计算的用户头部中心点。
左眼 用户的左眼。
左手 用户的左手。
右眼 用户的右眼。
右手 用户的右手。
跟踪参考 跟踪参考点,例如 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.RightHandedXRNode.RightHand 获取右手设备的实例。
  2. 拥有正确的设备后,请使用 InputDevice.TryGetFeatureValue 方法访问当前状态。

TryGetFeatureValue()尝试访问特征的当前值,并返回:

  • 如果成功检索指定的特征值,则为 true
  • 如果当前设备不支持指定功能,或者设备无效(即控制器不再处于活动状态),则为 false

若要获取特定按钮、触摸输入或纵杆轴值,请使用 CommonUsages 类。CommonUsages包括每个InputFeatureUsageXR 输入映射表中,以及位置和旋转等跟踪功能。以下代码示例使用 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 项的列表,这些项具有描述功能的类型和名称属性。以下示例枚举了给定输入设备提供的所有布尔功能:

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 示例

不同的控制器配置提供对不同功能的访问。例如,您可能在一个系统上有多个控制器,在不同系统上有不同的控制器,或者在同一控制器上具有不同 SDK 的不同按钮。这种多样性使得支持来自一系列 XR 系统的输入变得更加复杂。团结InputFeatureUsageAPI 可帮助您获取不依赖于平台的输入。

以下示例访问InputFeatureUsageprimaryButton,无论哪个控制器或输入设备提供它。该示例包括一个类,用于扫描可用设备的primaryButton当他们连接时。该类监视任何连接设备上的功能值,如果值发生变化,该类会分派 UnityEvent

要使用此类,请将其作为组件添加到任何游戏对象Unity 场景中的基本对象,可以表示角色、道具、风景、相机、航路点等。游戏对象的功能由附加到它的组件定义。更多信息
请参阅术语表
场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表
.例如:

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),然后拖动PrimaryButtonWatcherWatcher 属性的引用。

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 支持手部跟踪设备。手部跟踪设备始终:

手部跟踪数据由一个手部对象和一系列多达21个骨骼输入特征组成。每个骨骼都有一个位置和方向,以及对其父骨骼和层级中任何子骨骼的引用。手(Hand) 对象可以获取根骨骼,也可以获取每个手指的骨骼列表。

Hand.TryGetRootBone 获取根骨骼时,它会检索一个对象,该对象表示位于手腕正上方的骨骼。您还可以获得代表每个手指的骨骼列表。调用 Hand.TryGetFingerBones 将返回一个列表,其中包含表示该手指的骨骼(从指关节到尖端)。

访问眼动追踪数据

输入设备支持眼动追踪设备以及手部跟踪设备。眼动追踪包括左眼和右眼位置、用户在 3D 空间中注视的位置以及每只眼睛眨眼的次数。它的数据类型是 Eyes。要从设备中检索它,请使用 CommonUsages.eyesData

XRInputSubsystem 和 InputDevice 关联

Unity 提供了两种输入系统:旧版输入系统和 2019.2 中引入的 XR 插件架构。在新设置中,每个 InputDevice 都与 XRInputSubsystem 相关联。这些子系统对象控制与任何特定输入设备无关的全局输入行为 (例如,管理跟踪源或重新定位跟踪设备) 。

每个 InputDevice 都包含对其关联子系统的引用。如果设备来自集成平台,则此引用为 null。还可以使用 SubsystemManager.GetInstances<XRInputSubsystem> 获取所有活动的 XRInputSubsystem 对象,并且每个 XRInputSubsystem 都可以使用 XRInputSubsystem.TryGetInputDevices 获取其设备。

可以使用输入子系统将设备与 UnityEngine.XR.XRInputSubsystem 重新居中。重新居中将 HMD 的当前位置设置为所有设备的新原点。对于无法重新居中的设备,或者平台不支持重新居中,它返回 false。

若要检索跟踪边界,请使用 TryGetBoundaryPoints。它由一系列顺时针顺序的 3D 点组成,其中 y 值位于地板水平,它们标记出用户指定的“安全区域”来放置内容和交互。可以使用 XRInputSubsystem.boundaryChanged 侦听对此边界的更改。

XRInputSubsystem 还负责跟踪原点模式,该模式提供跟踪世界原点所在位置的上下文。Unity 支持以下跟踪源模式:

  • 设备:源的位置位于主显示设备的第一个已知位置;通常是头戴式显示器或手机。
  • 楼层:原点的位置位于楼层上的已知位置。
  • 跟踪引用:原点的位置位于设置了 TrackingReference 特征的 InputDevice 上。
  • 未知:跟踪来源的类型未知。这可能是由于系统故障或缺乏跟踪源模式支持。

您可以使用三个 API 来管理跟踪源模式:

通过传统输入系统进行 XR 输入

您仍然可以使用由输入和 XR 组成的旧版输入系统。InputTracking,用于检索 XR 输入要素。为此,请使用此页面上 XR 输入映射表中的相应旧版输入索引。在 输入 部分玩家设置设置,可让您为 Unity 构建的最终游戏设置各种特定于玩家的选项。更多信息
请参阅术语表
(菜单:编辑 > 项目设置(Project Settings) 广泛的设置集合,允许您配置物理、音频、网络、图形、输入和项目的许多其他区域的行为方式。更多信息
请参阅术语表
> Input),创建轴映射,以将从输入名称到平台设备功能的轴索引添加适当的映射。若要检索按钮或轴值,请使用 Input.GetAxisInput.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);
            }
    }
}
移动键盘
传统输入