VR控制器硬件介绍与适配
在虚拟现实(VR)游戏中,控制器是玩家与虚拟世界进行交互的主要工具。不同的VR平台(如Oculus、HTC Vive、Windows Mixed Reality等)使用不同的控制器硬件,因此在开发VR游戏时,适配多种控制器是一个重要的环节。本节将详细介绍如何在Unity引擎中适配不同类型的VR控制器,并提供具体的代码示例。
1. VR控制器硬件概述
1.1 主流VR控制器
目前市面上主流的VR控制器包括但不限于以下几种:
-
Oculus Touch:Oculus Rift和Quest系列头显的控制器。
-
HTC Vive Wands:HTC Vive系列头显的控制器。
-
Windows Mixed Reality Controllers:Windows Mixed Reality头显的控制器。
-
Valve Index Controllers:Valve Index头显的控制器。
-
PS VR Move:PlayStation VR头显的控制器。
1.2 控制器功能与特点
每种控制器都有其独特的功能和特点,例如:
-
Oculus Touch:具有触控板、扳机键、摇杆和按钮等多种输入方式,支持手势识别。
-
HTC Vive Wands:具有触控板、扳机键、按钮和轨迹球,支持手势识别。
-
Windows Mixed Reality Controllers:具有触控板、扳机键和按钮,支持手势识别。
-
Valve Index Controllers:具有高度灵敏的手指追踪、触控板和按钮,支持手势识别。
-
PS VR Move:具有触控板、扳机键、按钮和运动追踪,支持手势识别。
2. Unity中的VR控制器适配
2.1 VR输入系统概述
Unity引擎提供了多种方式来处理VR控制器的输入。从Unity 2019.3开始,推荐使用Input System包来处理输入,因为它更加灵活和强大。然而,对于旧版本的Unity,通常使用Legacy Input System。
2.2 Legacy Input System
2.2.1 基本输入处理
Legacy Input System通过Input.GetAxis
和Input.GetButton
等方法来处理控制器输入。以下是一些常用的输入轴和按钮:
-
Oculus Touch:
-
Oculus_CV1_Left_Trigger
-
Oculus_CV1_Right_Trigger
-
Oculus_CV1_Left_Grip
-
Oculus_CV1_Right_Grip
-
Oculus_CV1_Left_Primary2DAxis
-
Oculus_CV1_Right_Primary2DAxis
-
-
HTC Vive Wands:
-
SteamVR_Actions_Click
-
SteamVR_Actions_Touchpad
-
SteamVR_Actions_Trigger
-
SteamVR_Actions_Grip
-
-
Windows Mixed Reality Controllers:
-
WindowsMR_LeftTrigger
-
WindowsMR_RightTrigger
-
WindowsMR_LeftThumbstick
-
WindowsMR_RightThumbstick
-
2.2.2 示例代码
以下是一个简单的示例,展示了如何使用Legacy Input System处理Oculus Touch控制器的扳机键输入,使虚拟手抓取物体:
using UnityEngine;
public class OculusTouchGrab : MonoBehaviour
{
// 抓取距离
public float grabDistance = 1.5f;
// 抓取物体的标签
public string grabTag = "Grabbable";
// 左手控制器
private OVRInput.Controller leftController = OVRInput.Controller.LTouch;
// 右手控制器
private OVRInput.Controller rightController = OVRInput.Controller.RTouch;
// 当前抓取的物体
private GameObject heldObject;
void Update()
{
// 检查左手扳机键是否按下
if (OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger, leftController))
{
HandleGrab(leftController);
}
else if (heldObject != null && OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger, leftController) == false)
{
HandleRelease(leftController);
}
// 检查右手扳机键是否按下
if (OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger, rightController))
{
HandleGrab(rightController);
}
else if (heldObject != null && OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger, rightController) == false)
{
HandleRelease(rightController);
}
}
void HandleGrab(OVRInput.Controller controller)
{
// 获取控制器位置
Vector3 controllerPosition = OVRInput.GetLocalControllerPosition(controller);
// 获取控制器方向
Quaternion controllerRotation = OVRInput.GetLocalControllerRotation(controller);
// 射线检测
RaycastHit hit;
if (Physics.Raycast(controllerPosition, controllerRotation * Vector3.forward, out hit, grabDistance))
{
// 检查击中的物体是否可抓取
if (hit.collider.CompareTag(grabTag))
{
heldObject = hit.collider.gameObject;
// 设置物体为子对象
heldObject.transform.SetParent(this.transform);
// 重置物体的位置和旋转
heldObject.transform.localPosition = Vector3.zero;
heldObject.transform.localRotation = Quaternion.identity;
}
}
}
void HandleRelease(OVRInput.Controller controller)
{
if (heldObject != null)
{
// 释放物体
heldObject.transform.SetParent(null);
heldObject = null;
}
}
}
2.3 Input System
2.3.1 安装Input System包
-
打开Unity Hub,选择您的项目。
-
点击“打开”按钮进入Unity编辑器。
-
转到
Window
>Package Manager
。 -
在搜索框中输入
Input System
。 -
点击
Install
按钮安装Input System包。
2.3.2 配置Input System
安装完成后,需要在项目中启用Input System:
-
转到
Edit
>Project Settings
>Player
。 -
在
Other Settings
中找到Active Input Handling
。 -
选择
Both
或Input System (Preview)
。
2.3.3 基本输入处理
Input System通过InputAction
来处理控制器输入。首先,需要创建一个输入动作(Input Action):
-
转到
Window
>Input System
>Input Actions
。 -
点击
New Input Action
按钮。 -
命名输入动作,例如
Grab
。 -
在
Bindings
中添加控制器输入,例如LeftHand/Trigger
和RightHand/Trigger
。
2.3.4 示例代码
以下是一个使用Input System处理Oculus Touch控制器扳机键输入的示例,使虚拟手抓取物体:
using UnityEngine;
using UnityEngine.InputSystem;
public class InputSystemGrab : MonoBehaviour
{
// 抓取距离
public float grabDistance = 1.5f;
// 抓取物体的标签
public string grabTag = "Grabbable";
// 左手控制器输入
private InputAction leftTrigger;
// 右手控制器输入
private InputAction rightTrigger;
// 当前抓取的物体
private GameObject heldObject;
void Awake()
{
// 加载输入动作
leftTrigger = new InputAction("LeftTrigger", binding: "<Oculus>/lefthand/trigger");
rightTrigger = new InputAction("RightTrigger", binding: "<Oculus>/hand/trigger");
}
void OnEnable()
{
// 启用输入动作
leftTrigger.Enable();
rightTrigger.Enable();
}
void OnDisable()
{
// 禁用输入动作
leftTrigger.Disable();
rightTrigger.Disable();
}
void Update()
{
// 检查左手扳机键是否按下
if (leftTrigger.ReadValue<float>() > 0.5f)
{
HandleGrab(leftTrigger);
}
else if (heldObject != null && leftTrigger.ReadValue<float>() <= 0.5f)
{
HandleRelease(leftTrigger);
}
// 检查右手扳机键是否按下
if (rightTrigger.ReadValue<float>() > 0.5f)
{
HandleGrab(rightTrigger);
}
else if (heldObject != null && rightTrigger.ReadValue<float>() <= 0.5f)
{
HandleRelease(rightTrigger);
}
}
void HandleGrab(InputAction trigger)
{
// 获取控制器位置
Vector3 controllerPosition = trigger.bindings[0].effectiveDevice.currentControlScheme == "LeftHand" ?
OVRInput.GetLocalControllerPosition(OVRInput.Controller.LTouch) :
OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch);
// 获取控制器方向
Quaternion controllerRotation = trigger.bindings[0].effectiveDevice.currentControlScheme == "LeftHand" ?
OVRInput.GetLocalControllerRotation(OVRInput.Controller.LTouch) :
OVRInput.GetLocalControllerRotation(OVRInput.Controller.RTouch);
// 射线检测
RaycastHit hit;
if (Physics.Raycast(controllerPosition, controllerRotation * Vector3.forward, out hit, grabDistance))
{
// 检查击中的物体是否可抓取
if (hit.collider.CompareTag(grabTag))
{
heldObject = hit.collider.gameObject;
// 设置物体为子对象
heldObject.transform.SetParent(this.transform);
// 重置物体的位置和旋转
heldObject.transform.localPosition = Vector3.zero;
heldObject.transform.localRotation = Quaternion.identity;
}
}
}
void HandleRelease(InputAction trigger)
{
if (heldObject != null)
{
// 释放物体
heldObject.transform.SetParent(null);
heldObject = null;
}
}
}
3. 适配不同VR平台
3.1 适配Oculus平台
3.1.1 安装Oculus Integration包
-
打开Unity Hub,选择您的项目。
-
点击“打开”按钮进入Unity编辑器。
-
转到
Window
>Package Manager
。 -
在搜索框中输入
Oculus Integration
。 -
点击
Install
按钮安装Oculus Integration包。
3.1.2 示例代码
以下是一个使用Oculus Integration包处理Oculus Touch控制器触控板输入的示例,使虚拟手进行交互:
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.Oculus;
public class OculusTouchInteraction : MonoBehaviour
{
// 交互距离
public float interactionDistance = 1.5f;
// 交互物体的标签
public string interactionTag = "Interactive";
// 左手控制器
private OVRInput.Controller leftController = OVRInput.Controller.LTouch;
// 右手控制器
private OVRInput.Controller rightController = OVRInput.Controller.RTouch;
void Update()
{
// 检查左手触控板是否按下
if (OVRInput.Get(OVRInput.Button.PrimaryThumbstick, leftController))
{
HandleInteraction(leftController);
}
// 检查右手触控板是否按下
if (OVRInput.Get(OVRInput.Button.PrimaryThumbstick, rightController))
{
HandleInteraction(rightController);
}
}
void HandleInteraction(OVRInput.Controller controller)
{
// 获取控制器位置
Vector3 controllerPosition = OVRInput.GetLocalControllerPosition(controller);
// 获取控制器方向
Quaternion controllerRotation = OVRInput.GetLocalControllerRotation(controller);
// 射线检测
RaycastHit hit;
if (Physics.Raycast(controllerPosition, controllerRotation * Vector3.forward, out hit, interactionDistance))
{
// 检查击中的物体是否可交互
if (hit.collider.CompareTag(interactionTag))
{
// 调用交互对象的方法
if (hit.collider.TryGetComponent(out InteractiveObject interactiveObject))
{
interactiveObject.OnInteract();
}
}
}
}
}
// 交互对象的接口
public interface InteractiveObject
{
void OnInteract();
}
// 交互对象的实现
public class InteractiveObjectExample : MonoBehaviour, InteractiveObject
{
public void OnInteract()
{
Debug.Log("互动对象被交互了!");
// 在这里添加具体的交互逻辑
}
}
3.2 适配HTC Vive平台
3.2.1 安装SteamVR插件
-
打开Unity Hub,选择您的项目。
-
点击“打开”按钮进入Unity编辑器。
-
转到
Window
>Package Manager
。 -
在搜索框中输入
SteamVR
。 -
点击
Install
按钮安装SteamVR插件。
3.2.2 示例代码
以下是一个使用SteamVR插件处理HTC Vive控制器扳机键输入的示例,使虚拟手抓取物体:
using UnityEngine;
using UnityEngine.XR;
using Valve.VR;
public class SteamVRGrab : MonoBehaviour
{
// 抓取距离
public float grabDistance = 1.5f;
// 抓取物体的标签
public string grabTag = "Grabbable";
// 左手控制器
private SteamVR_Action_Boolean grabAction = SteamVR_Input_GetAction<SteamVR_Action_Boolean>("Grab");
// 右手控制器
private SteamVR_Action_Boolean releaseAction = SteamVR_Input_GetAction<SteamVR_Action_Boolean>("Release");
// 当前抓取的物体
private GameObject heldObject;
void Update()
{
// 检查左手扳机键是否按下
if (grabAction.GetState(SteamVR_Input_Sources.LeftHand))
{
HandleGrab(SteamVR_Input_Sources.LeftHand);
}
else if (heldObject != null && !grabAction.GetState(SteamVR_Input_Sources.LeftHand))
{
HandleRelease(SteamVR_Input_Sources.LeftHand);
}
// 检查右手扳机键是否按下
if (grabAction.GetState(SteamVR_Input_Sources.RightHand))
{
HandleGrab(SteamVR_Input_Sources.RightHand);
}
else if (heldObject != null && !grabAction.GetState(SteamVR_Input_Sources.RightHand))
{
HandleRelease(SteamVR_Input_Sources.RightHand);
}
}
void HandleGrab(SteamVR_Input_Sources hand)
{
// 获取控制器位置
Vector3 controllerPosition = SteamVR_Input_GetPosition(hand);
// 获取控制器方向
Quaternion controllerRotation = SteamVR_Input_GetRotation(hand);
// 射线检测
RaycastHit hit;
if (Physics.Raycast(controllerPosition, controllerRotation * Vector3.forward, out hit, grabDistance))
{
// 检查击中的物体是否可抓取
if (hit.collider.CompareTag(grabTag))
{
heldObject = hit.collider.gameObject;
// 设置物体为子对象
heldObject.transform.SetParent(this.transform);
// 重置物体的位置和旋转
heldObject.transform.localPosition = Vector3.zero;
heldObject.transform.localRotation = Quaternion.identity;
}
}
}
void HandleRelease(SteamVR_Input_Sources hand)
{
if (heldObject != null)
{
// 释放物体
heldObject.transform.SetParent(null);
heldObject = null;
}
}
// 获取控制器位置
private Vector3 SteamVR_Input_GetPosition(SteamVR_Input_Sources hand)
{
return SteamVR_Input_GetHandPose(hand).headPose.pos;
}
// 获取控制器方向
private Quaternion SteamVR_Input_GetRotation(SteamVR_Input_Sources hand)
{
return SteamVR_Input_GetHandPose(hand).headPose.rot;
}
}
3.3 适配Windows Mixed Reality平台
3.3.1 安装Windows XR Plugin
-
打开Unity Hub,选择您的项目。
-
点击“打开”按钮进入Unity编辑器。
-
转到
Window
>Package Manager
。 -
在搜索框中输入
Windows XR Plugin
。 -
点击
Install
按钮安装Windows XR Plugin。
3.3.2 示例代码
以下是一个使用Windows XR Plugin处理Windows Mixed Reality控制器扳机键输入的示例,使虚拟手抓取物体:
using UnityEngine;
using UnityEngine.XR;
public class WindowsMRGrab : MonoBehaviour
{
// 抓取距离
public float grabDistance = 1.5f;
// 抓取物体的标签
public string grabTag = "Grabbable";
// 左手控制器
private XRNode leftHand = XRNode.LeftHand;
// 右手控制器
private XRNode rightHand = XRNode.RightHand;
// 当前抓取的物体
private GameObject heldObject;
void Update()
{
// 检查左手扳机键是否按下
if (Input.GetAxis("WindowsMR_LeftTrigger") > 0.5f)
{
HandleGrab(leftHand);
}
else if (heldObject != null && Input.GetAxis("WindowsMR_LeftTrigger") <= 0.5f)
{
HandleRelease(leftHand);
}
// 检查右手扳机键是否按下
if (Input.GetAxis("WindowsMR_RightTrigger") > 0.5f)
{
HandleGrab(rightHand);
}
else if (heldObject != null && Input.GetAxis("WindowsMR_RightTrigger") <= 0.5f)
{
HandleRelease(rightHand);
}
}
void HandleGrab(XRNode hand)
{
// 获取控制器位置
Vector3 controllerPosition = Vector3.zero;
bool positionValid = InputTracking.GetNodeStates(new List<XRNodeState>()).Find(x => x.nodeType == hand).TryGetPosition(out controllerPosition);
// 获取控制器方向
Quaternion controllerRotation = Quaternion.identity;
bool rotationValid = InputTracking.GetNodeStates(new List<XRNodeState>()).Find(x => x.nodeType == hand).TryGetRotation(out controllerRotation);
if (positionValid && rotationValid)
{
// 射线检测
RaycastHit hit;
if (Physics.Raycast(controllerPosition, controllerRotation * Vector3.forward, out hit, grabDistance))
{
// 检查击中的物体是否可抓取
if (hit.collider.CompareTag(grabTag))
{
heldObject = hit.collider.gameObject;
// 设置物体为子对象
heldObject.transform.SetParent(this.transform);
// 重置物体的位置和旋转
heldObject.transform.localPosition = Vector3.zero;
heldObject.transform.localRotation = Quaternion.identity;
}
}
}
}
void HandleRelease(XRNode hand)
{
if (heldObject != null)
{
// 释放物体
heldObject.transform.SetParent(null);
heldObject = null;
}
}
}
3.4 适配Valve Index平台
3.4.1 安装SteamVR插件
-
打开Unity Hub,选择您的项目。
-
点击“打开”按钮进入Unity编辑器。
-
转到
Window
>Package Manager
。 -
在搜索框中输入
SteamVR
。 -
点击
Install
按钮安装SteamVR插件。
3.4.2 示例代码
以下是一个使用SteamVR插件处理Valve Index控制器扳机键输入的示例,使虚拟手抓取物体:
using UnityEngine;
using UnityEngine.XR;
using Valve.VR;
public class ValveIndexGrab : MonoBehaviour
{
// 抓取距离
public float grabDistance = 1.5f;
// 抓取物体的标签
public string grabTag = "Grabbable";
// 左手控制器
private SteamVR_Action_Boolean grabAction = SteamVR_Input_GetAction<SteamVR_Action_Boolean>("Grab");
// 右手控制器
private SteamVR_Action_Boolean releaseAction = SteamVR_Input_GetAction<SteamVR_Action_Boolean>("Release");
// 当前抓取的物体
private GameObject heldObject;
void Update()
{
// 检查左手扳机键是否按下
if (grabAction.GetState(SteamVR_Input_Sources.LeftHand))
{
HandleGrab(SteamVR_Input_Sources.LeftHand);
}
else if (heldObject != null && !grabAction.GetState(SteamVR_Input_Sources.LeftHand))
{
HandleRelease(SteamVR_Input_Sources.LeftHand);
}
// 检查右手扳机键是否按下
if (grabAction.GetState(SteamVR_Input_Sources.RightHand))
{
HandleGrab(SteamVR_Input_Sources.RightHand);
}
else if (heldObject != null && !grabAction.GetState(SteamVR_Input_Sources.RightHand))
{
HandleRelease(SteamVR_Input_Sources.RightHand);
}
}
void HandleGrab(SteamVR_Input_Sources hand)
{
// 获取控制器位置
Vector3 controllerPosition = SteamVR_Input_GetPosition(hand);
// 获取控制器方向
Quaternion controllerRotation = SteamVR_Input_GetRotation(hand);
// 射线检测
RaycastHit hit;
if (Physics.Raycast(controllerPosition, controllerRotation * Vector3.forward, out hit, grabDistance))
{
// 检查击中的物体是否可抓取
if (hit.collider.CompareTag(grabTag))
{
heldObject = hit.collider.gameObject;
// 设置物体为子对象
heldObject.transform.SetParent(this.transform);
// 重置物体的位置和旋转
heldObject.transform.localPosition = Vector3.zero;
heldObject.transform.localRotation = Quaternion.identity;
}
}
}
void HandleRelease(SteamVR_Input_Sources hand)
{
if (heldObject != null)
{
// 释放物体
heldObject.transform.SetParent(null);
heldObject = null;
}
}
// 获取控制器位置
private Vector3 SteamVR_Input_GetPosition(SteamVR_Input_Sources hand)
{
return SteamVR_Input_GetHandPose(hand).headPose.pos;
}
// 获取控制器方向
private Quaternion SteamVR_Input_GetRotation(SteamVR_Input_Sources hand)
{
return SteamVR_Input_GetHandPose(hand).headPose.rot;
}
}
3.5 适配PS VR平台
3.5.1 安装PS VR插件
-
打开Unity Hub,选择您的项目。
-
点击“打开”按钮进入Unity编辑器。
-
转到
Window
>Package Manager
。 -
在搜索框中输入
PS VR
。 -
点击
Install
按钮安装PS VR插件。
3.5.2 示例代码
以下是一个使用PS VR插件处理PS VR Move控制器扳机键输入的示例,使虚拟手抓取物体:
using UnityEngine;
using UnityEngine.XR;
public class PSVRGrab : MonoBehaviour
{
// 抓取距离
public float grabDistance = 1.5f;
// 抓取物体的标签
public string grabTag = "Grabbable";
// 左手控制器
private XRNode leftHand = XRNode.LeftHand;
// 右手控制器
private XRNode rightHand = XRNode.RightHand;
// 当前抓取的物体
private GameObject heldObject;
void Update()
{
// 检查左手扳机键是否按下
if (Input.GetAxis("PSVR_LeftTrigger") > 0.5f)
{
HandleGrab(leftHand);
}
else if (heldObject != null && Input.GetAxis("PSVR_LeftTrigger") <= 0.5f)
{
HandleRelease(leftHand);
}
// 检查右手扳机键是否按下
if (Input.GetAxis("PSVR_RightTrigger") > 0.5f)
{
HandleGrab(rightHand);
}
else if (heldObject != null && Input.GetAxis("PSVR_RightTrigger") <= 0.5f)
{
HandleRelease(rightHand);
}
}
void HandleGrab(XRNode hand)
{
// 获取控制器位置
Vector3 controllerPosition = Vector3.zero;
bool positionValid = InputTracking.GetNodeStates(new List<XRNodeState>()).Find(x => x.nodeType == hand).TryGetPosition(out controllerPosition);
// 获取控制器方向
Quaternion controllerRotation = Quaternion.identity;
bool rotationValid = InputTracking.GetNodeStates(new List<XRNodeState>()).Find(x => x.nodeType == hand).TryGetRotation(out controllerRotation);
if (positionValid && rotationValid)
{
// 射线检测
RaycastHit hit;
if (Physics.Raycast(controllerPosition, controllerRotation * Vector3.forward, out hit, grabDistance))
{
// 检查击中的物体是否可抓取
if (hit.collider.CompareTag(grabTag))
{
heldObject = hit.collider.gameObject;
// 设置物体为子对象
heldObject.transform.SetParent(this.transform);
// 重置物体的位置和旋转
heldObject.transform.localPosition = Vector3.zero;
heldObject.transform.localRotation = Quaternion.identity;
}
}
}
}
void HandleRelease(XRNode hand)
{
if (heldObject != null)
{
// 释放物体
heldObject.transform.SetParent(null);
heldObject = null;
}
}
}
4. 总结
在Unity引擎中适配不同类型的VR控制器是一个复杂但必要的过程。通过了解每种控制器的功能和特点,并使用适当的输入系统(Legacy Input System或Input System),开发者可以确保游戏在多个VR平台上都能提供一致的用户体验。以上示例代码展示了如何处理Oculus Touch、HTC Vive Wands、Windows Mixed Reality Controllers、Valve Index Controllers和PS VR Move控制器的输入,使虚拟手抓取和释放物体。希望这些示例能帮助您在开发VR游戏时更好地适配多种控制器。
如果您有任何疑问或需要进一步的帮助,请查阅Unity官方文档或相关VR平台的开发指南。祝您开发顺利!