赞
踩
OpenXR是一个针对XR应用程序接口,简称API。 OpenXR的最终目标是将VR/AR应用和头显之间的通信方式标准化。在2017年,由Khronos Group发起,联合多家行业头部公司一起制定了一个开放标准Open XR。 该标准的目标是为开发人员提供一个简化的方式来创建跨平台VR和AR应用程序和游戏,这些应用程序和游戏可以在支持OpenXR的各种设备上运行。
注:最新OpenXR标准规范1.0版于2019年推出,尽管采用缓慢,但一直稳定增长。目前,Meta、Sony、Valve、Microsoft、HTC、NVIDIA 和 AMD 已相继支持该标准(Apple 暂不支持)。Meta还在2021年7月将OpenXR兼容性支持纳入了新发行Quest App的基本要求。 总而言之,OpenXR 是VR/AR领域的一个重要里程碑。这个API将允许游戏和其他应用程序在各种硬件平台上轻松运行,而无需专有的SDK。
① 创建一个3D URP项目(效果适中,HDRP适合大团队),将开发环境切换至Android,Pico 一体机VR搭载是安卓系统。
②安装PICO Unity Integration SDK 、XR Interaction Toolkit及 PICO Unity OpenXR SDK。
首先按照官网配置完成PICO Developer
XR Interaction Toolkit:打开Packages Manage中搜索XR Interaction Toolkit并安装
PICO Unity Integration SDK:在官网中直接下载SDK进行安装,补全开发中针对PICO一体机的关键XR能力
Pico OpenXR SDK:在官网中直接下载SDK进行安装
如遇安装过程异常:如果直接安装Pico OpenXR Plugin SDK后并没有自动安装OpenXR SDK(Unity原生),则应卸载Pico OpenXR Plugin SDK,然后先安装OpenXR SDK(Unity原生)再安装Pico OpenXR Plugin SDK,否则项目依旧不支持PICO,没有进行相关链接。
注:目前Pico OpenXR SDK处于Preview版,暂时无法用于商业开发,使用该插件开发的应用将无法通过商店审核。只能用于个人开发者尝鲜学习使用。
④打开Packages Manage中安卓AndroidLogcat,方便后续直接接入PicoVR一体机进行调试,使用adb进行软件安装(具体的adb简单使用在我的博客VR——Oculus篇会提到),但效率太慢。这时候就有人问我,为什么不用PICO Unity Live Preview Plugin 串流调试,我的回答是这个SDK不太稳定,针对不同的PC系统/配置还存在Bug,换台电脑可能连通讯都通不上。
①增添左右射线控制器
- [Tooltip("玩家左射线控制")] public XRRayInteractor RayInteractor_Left;
- [Tooltip("玩家右射线控制")] public XRRayInteractor RayInteractor_Right;
-
- private InputDevice curLeftController, curRightController;
- private GameObject curLeftGameObject, lastLeftGameObject;
- private GameObject curRightGameObject, lastRightGameObject;
- private RaycastHit rayInfoLeft, rayInfoRight;
- private bool isEnterLeftPrimaryButton = false, isEnterRightPrimaryButton;
- private Dictionary<string, bool> vrButtonStateDic;
②增添射线检测接口
- using UnityEngine.XR.Interaction.Toolkit;
-
- public interface IRayPointCheck
- {
- /// <summary>
- /// 射线进入
- /// </summary>
- public void OnRayEnter(HoverEnterEventArgs arg0);
- /// <summary>
- /// 射线退出
- /// </summary>
- public void OnRayExit(HoverExitEventArgs arg0);
- /// <summary>
- /// 射线点击
- /// </summary>
- public void OnRayClick();
- }
③根据左右手柄对于碰撞物体的检测状态进行判定射线进入、点击及退出逻辑
- /// <summary>
- /// 射线进入控制
- /// </summary>
- /// <param name="curObj"></param>
- private void RayEnterControl(GameObject curObj)
- {
- //射线进入逻辑
- }
-
- /// <summary>
- /// 射线点击控制
- /// </summary>
- /// <param name="curObj"></param>
- private void RayStayClickControl(GameObject curObj)
- {
- //射线点击逻辑
- }
-
- /// <summary>
- /// 射线退出控制
- /// </summary>
- /// <param name="lastObj"></param>
- private void RayExitControl(GameObject lastObj)
- {
- //射线退出逻辑
- }
-
- private bool isRayStay = false;
- private bool isRayLeftStay = false;
- /// <summary>
- /// 获取左手柄对3D的射线碰撞信息
- /// </summary>
- /// <returns></returns>
- private void GettLeftRayInfo()
- {
- if(RayInteractor_Left.TryGetCurrent3DRaycastHit(out rayInfoLeft))
- {
- curLeftGameObject = rayInfoLeft.collider.gameObject;
- }
- else
- {
- curLeftGameObject = null;
- }
-
- //射线进入
- if(curLeftGameObject != null && lastLeftGameObject == null)
- {
- isRayLeftStay = false;
-
- RayEnterControl(curLeftGameObject);
- lastLeftGameObject = curLeftGameObject;
- }
-
- //射线停留点击
- if (curLeftGameObject != null && lastLeftGameObject != null && curLeftGameObject == lastLeftGameObject)
- {
- isRayLeftStay = true;
-
- RayStayClickControl(curLeftGameObject);
- lastLeftGameObject = curLeftGameObject;
- }
- else //射线退出
- {
- isRayLeftStay = false;
- curLeftGameObject = null;
- if(lastLeftGameObject != null)
- {
- RayExitControl(lastLeftGameObject);
- }
-
- lastLeftGameObject = null;
- }
- }
-
- /// <summary>
- /// 获取右手柄对3D的射线碰撞信息
- /// </summary>
- /// <returns></returns>
- private void GetRightRayInfo()
- {
- if (RayInteractor_Right.TryGetCurrent3DRaycastHit(out rayInfoRight))
- {
- curRightGameObject = rayInfoRight.collider.gameObject;
- }
- else
- {
- curRightGameObject = null;
- }
-
- //射线进入
- if (curRightGameObject != null && lastRightGameObject == null)
- {
- isRayStay = false;
- RayEnterControl(curRightGameObject);
-
- lastRightGameObject = curRightGameObject;
- }
-
- //射线点击
- if (curRightGameObject != null && lastRightGameObject != null && curRightGameObject == lastRightGameObject)
- {
- isRayStay = true;
- RayStayClickControl(curRightGameObject);
-
- lastRightGameObject = curRightGameObject;
- }
- else //射线退出
- {
- isRayStay = false;
- curRightGameObject = null;
- if (lastRightGameObject != null)
- {
- RayExitControl(lastRightGameObject);
- }
-
- lastRightGameObject = null;
- }
- }
Pico手柄按键映射示意:手柄&头戴输入映射 | PICO 开发者平台
①初始化手柄左右控制器
- /// <summary>
- /// 重新初始化
- /// </summary>
- private void InitControler()
- {
- if (!curLeftController.isValid)
- {
- curLeftController = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
- }
-
- if (!curRightController.isValid)
- {
- curRightController = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
- }
- }
②针对手柄通用4个按键注册按键进入、按下及退出事件
- private void ChangeLeftPrimaryButtonState()
- {
- if (isRayLeftStay)
- {
- isEnterLeftPrimaryButton = true;
- }
- }
-
- private void ChangeRightPrimaryButtonState()
- {
- if (isRayStay)
- {
- isEnterRightPrimaryButton = true;
- }
- }
-
- /// <summary>
- ///按键检测函数
- /// </summary>
- /// <param name="device"></param>
- /// <param name="usage"></param>
- /// <param name="buttonEnter"></param>
- /// <param name="buttonDown"></param>
- /// <param name="buttonUp"></param>
- private void ButtonDispatch(InputDevice device,InputFeatureUsage<bool> usage,Action buttonEnter,Action buttonDown,Action buttonUp)
- {
- //必须这个名称,里面包含device信息
- string featureKey = device.characteristics + usage.name;
- //string featureKey = usage.name;
- if (!vrButtonStateDic.ContainsKey(featureKey))
- {
- vrButtonStateDic.Add(featureKey, false);
- }
-
- bool isDown;
- if(device.TryGetFeatureValue(usage,out isDown) && isDown)
- {
- //Enter按键按下只执行一次
- if (!vrButtonStateDic[featureKey])
- {
- Debug.Log(featureKey + "---Button Enter");
- vrButtonStateDic[featureKey] = true;
- buttonEnter?.Invoke();
- }
-
- //Down在按键按下会执行多次,主要还是帧时间不适配
- Debug.Log(featureKey + "--Button Down");
- buttonDown?.Invoke();
- }
- else
- {
- //Enter按键按下只执行一次
- if (vrButtonStateDic[featureKey])
- {
- Debug.Log(featureKey + "--Button Up");
- buttonUp?.Invoke();
- vrButtonStateDic[featureKey] = false;
- }
- }
- }
-
- /// <summary>
- /// 获取手柄输入信息
- /// </summary>
- private void GetControllerStatus()
- {
- if (curLeftController.isValid)
- {
- ButtonDispatch(curLeftController, CommonUsages.primaryButton, onLeftPrimaryEnter, onLeftPrimaryDown, onLeftPrimaryUp);
- ButtonDispatch(curLeftController, CommonUsages.secondaryButton, onLeftSecondaryEnter, onLeftSecondaryDown, onLeftSecondaryUp);
- ButtonDispatch(curLeftController, CommonUsages.triggerButton, onLeftTriggerEnter, onLeftTriggerDown, onLeftTriggerUp);
- ButtonDispatch(curLeftController, CommonUsages.gripButton, onLeftGripEnter, onLeftGripDown, onLeftGripUp);
- }
- else
- {
- InitControler();
- }
-
- if (curRightController.isValid)
- {
- ButtonDispatch(curRightController, CommonUsages.primaryButton, onRightPrimaryEnter, onRightPrimaryDown, onRightPrimaryUp);
- ButtonDispatch(curRightController, CommonUsages.secondaryButton, onRightSecondaryEnter, onRightSecondaryDown, onRightSecondaryUp);
- ButtonDispatch(curRightController, CommonUsages.triggerButton, onRightTriggerEnter, onRightTriggerDown, onRightTriggerUp);
- ButtonDispatch(curRightController, CommonUsages.gripButton, onRightGripEnter, onRightGripDown, onRightGripUp);
- }
- else
- {
- InitControler();
- }
- }
③测试代码,可参考以下
- if (primaryButton_A)
- {
- Text.text = "ALeft";
- SetHapticImpulse_Left();
- }
- else if (secondaryButton_B)
- {
- Text.text = "BLeft";
- }
- else if (triggerButton_Left)
- {
- Text.text = "triggerLeft";
- }
- else if (gripButton_Left)
- {
- Text.text = "gripButtonLeft";
- }
-
- if (primaryButton_X)
- {
- Text.text = "ARight";
- SetHapticImpulse_Right();
- }
- else if (secondaryButton_Y)
- {
- Text.text = "BRight";
- }
- else if (triggerButton_Right)
- {
- Text.text = "triggerRight";
- }
- else if (gripButton_Right)
- {
- Text.text = "gripButtonRight";
- }
①注册左右手柄的震动事件,我这边是用我写的事件框架里添加,读者可以使用Action自定义添加手柄震动事件,注意好震动Api的三个形参就行
- //震动事件
- EventManager.AddEventListener<float, int, int>("TurnOnHaptics", SetHapticImpulse_Left);
- EventManager.AddEventListener<float, int, int>("TurnOnHaptics", SetHapticImpulse_Right);
②调用XR封装好的震动API
- /// <summary>
- /// 左手柄触发震动
- /// 默认amplitude:0.5f,duration : 500,frequency : 100
- /// </summary>
- private void SetHapticImpulse_Left(float amplitude, int duration, int frequency = 150)
- {
- PXR_Input.SendHapticImpulse(PXR_Input.VibrateType.LeftController, amplitude, duration, frequency);
- }
-
- /// <summary>
- /// 右手柄触发震动
- /// </summary>
- private void SetHapticImpulse_Right(float amplitude, int duration, int frequency = 150)
- {
- PXR_Input.SendHapticImpulse(PXR_Input.VibrateType.RightController, amplitude, duration, frequency);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。