zt3ff3n 发表于 2022-2-13 17:20

Unity3D开发技术研究-SteamVR2.0杂谈

一、概述


笔者之前使用SteamV1.x+VRTK开发项目,发现SteamVR2.0与之前有重大更新,主要原因是随着越来越多的VR设备推出,控制器类型逐渐趋向于碎片化,
每当有新的控制器发布,都会给开发者带来一些额外的工作量:游戏项目需要修改交互代码以适配新的设备;意思就是每套VR硬件设备就有自身一套VR SDK,
所以,当现有VR应用程序移植到另外一个VR平台的时候,需要针对目标平台进行交互适配;从而增加开发者的工作量;SteamVR2.0的推出意味着能够使开发者
在编程中专注于用户的动作,而不是具体的控制器按键。(具体适配如何留待日后验证,目前只做整理)
二、重要更新:Input System


SteamVR 2.0 的重要更新是加入了 Input System。推出Input System的目的,是为了更加符合OpenXR标准,以及配合即将正式推出的Knuckles控制器。
目前多数主流VR平台均加入了OpenXR开放标准,如下图所示:

Input System 与之前处理用户输入有显著的不同,使用 SteamVR Input System,开发人员可以在应用程序之外定义默认的动作并与按键进行绑定,
而不需要将输入视为某一特定设备的特定按键。这样新的设备可以快速适配应用程序,无需更改代码。比如,当开发者检测玩家是否抓取某个物体的时候,
不是检测Vive控制器的Trigger键或Oculus Touch控制器的Grip键是否被按下,而是检测预定义的"Grab"动作是否为True即可。作为开发者,可以在
SteamVR中为Grab动作设置默认按键和阈值,当程序运行时,也可修改这些数值以满足玩家的个人偏好。基于这种机制,不光能够解决控制器碎片化的问题,
也可以快速适配未来发布的设备。
三、动作(Actions)


Input System 的核心概念是动作(Action),基于动作的输入系统对于游戏引擎来说更有意义, Unreal一直在沿用这种方案,而Unity目前在开发中的输入
系统也将遵循这一原则。开发者需要放弃之前关于“按下某个按键发生什么事情”的思想,取而代之的是使用“做出某个动作发生什么事情”的思想。
SteamVR 2.0将动作抽象为以下6种类型,简介如下:
Boolean类型的动作代表只有两种状态的动作——True或False,比如抓取(Grab)动作,只有抓取或未抓取两种状态,不存在中间状态。在Unity中对应类为
SteamVR_Action_Boolean。
Single类型的动作能够返回0~1之间的数值,比如 Trigger 键按下到松开的过程。在Unity中对应类为SteamVR_Action_Single。
Vector2类型动作能够返回二维数,比如Touchpad上的触摸或手柄摇杆。使用这样的数值能够控制物体在四个方向的运动,典型的应用时使用Touchpad控制无
人机或小车的运动。在Unity中对应类为SteamVR_Action_Vector2。
Vector3类型的动作能够返回三维数值,在Unity中对应类为SteamVR_Action_Vector3。
Pose类型的动作表示三维空间中的位置和旋转,一般用于跟踪VR控制器。在Unity中对应类为SteamVR_Action_Pose。
Skeleton类型的动作能够获取用户在持握手柄控制器时的手指关节数据,通过返回数据,结合手部渲染模型,能够更加真实的呈现手部在虚拟世界的姿态,虽
然不及像LeapMotion等设备获取手指输入那样精确,但是足以获得良好的沉浸感。在Unity中对应类为SteamVR_Action_Skeleton。
3.1 骨骼输入


对于骨骼输入,Knuckles控制器为SteamVR体验带来了手指跟踪功能,能够估算用户手指的位置,然后将数据传递给驱动程序,驱动程序将其对应解析到手部模
型的31块骨骼上,从而给用户带来更好的沉浸式体验。该功能并不是Knuckles所独有,SteamVR还能够为HTC Vive和Oculus Touch这样的设备提供手指状态
估算,比如判断手部是否打开,手指是否放置在Touchpad上。同时Valve公司还将与Microsoft展开合作,以增加对Windows MR控制器的支持。
默认情况下,运行Interaction System示例场景中能够同时看到手部和控制器模型,此外,还有一个辅助组件SteamVR_Behaviour_Skeleton,如下图所示。
有关该组件的使用,可以参考Interaction System的示例场景。

3.2 振动输出


以上是介绍的都是输入动作,另外,目前还有一种输出动作——振动,用于触发VR控制器上的触觉反馈,调用方法如下代码所示:
SteamVR_Input._default.outActions.Haptic.Execute(float secondsFromNow, float durationSeconds, float frequency, float amplitude, SteamVR_Input_Sources inputSource);四. 动作集(Action Sets)


动作通过动作集进行逻辑上的分组,以方便进行组织和管理。在Unity中对应的类为SteamVR_ActionSet。在不同的场景或应用程序之间可以切换使用不同的动作集,
比如,应用程序中有一个场景是在地球上拾取并投掷物体,而另一个场景则是在太空中飞行,那么这两个场景可以使用不同的动作集。同时,当针对新设备进行
交互适配时,开发者只需对动作进行配置,而不必修改项目代码。比如,使用 Vive 控制器时,定义了一个Fire动作,当需要支持 Rift Touch 时,只需通过
配置Touch控制器上符合 Fire 动作的键值即可。
SteamVR插件默认包含了三套动作集default、platformer、buggy,开发者也可以在SteamVR Input窗口中自行添加或删除动作集。
使用组件SteamVR_ActivateActionSetOnLoad可以在场景中自动激活和停用指定的动作集。对应激活和停用的方法是在Start()和OnDestroy()中实现。
如下图所示:


五、 SteamVR Input 窗口


在Unity编辑器中,使用 Window > SteamVR Input 命令,打开SteamVR Input 窗口。在SteamVR 2.0中,使用SteamVR Input窗口作为入口,
对所有动作进行管理。初次导入SteamVR 2.0并运行程序时,会弹出一个对话框,提示没有actions.json文件,并询问是否要使用默认值。如下图所示:

选择Yes,会将默认的actions.json文件以及一些常见的控制器相关绑定文件复制到当前项目的根目录下,如下图所示:


这些文件将在程序运行时被载入进来,并在程序最终构建时被复制到与可执行文件同级的目录下。复制完成后,SteamVR Input窗口将读取文件信息并展示其包
含的动作集合以及动作集合下的所有动作。如下图所示:


在Actions栏的右下角,可以点击加减号按钮添加或删除动作。每个动作具有名称(Name)、类型(Type)、本地化字符串(localization strings)等字段。
其中,类型对应上节介绍的动作类型;本地化字符串是面向用户进行绑定的动作名称,开发者可以通过SteamVR API直接访问动作以及动作集。

当点击Save and Generate按钮后,插件将为动作以及动作集生成可编程访问的对象类,将它们放置在项目的SteamVR_input目录下,如下图所示:


这些对象可以在相关组件的下拉列表中进行选择,如下图所示:

在项目代码中,使用SteamVR_Input类可以静态引用每个动作和动作集,在每个动作集中,可以找到其包含的动作的引用,如下代码所示:
void Update(){if(SteamVR_Input._default.inActions.Teleport.GetStateUp(SteamVR_Input_Sources.Any))   {      Teleport();    }}
以上代码实现的功能为:当检测到任意控制器发出default动作集中包含的Teleport动作时,执行Teleport()函数。
六、测试动作


选择 Window > SteamVR Input Live View 命令,即可打开一个测试输入窗口。运行程序,此时该窗口将实时展示所有动作集合的状态。如下图所示:

当一个动作的值发生变化时,对应右侧会突出显示绿色,然后逐渐消失。
七、 动作绑定


创建动作以后,需要将动作进行默认绑定。打开VR控制器,保持SteamVR客户端开启,在SteamVR Input窗口中,点击Open binding UI按钮,此时将使用操作
系统默认的网页浏览器打开SteamVR动作绑定页面。在此页面中选择需要绑定的控制器,点击Edit按钮,进入绑定编辑页面,如下图所示:

在动作编辑页面中,点击每个按键旁边的加号按钮, 弹出窗口会询问将此按键绑定为哪种模式,如下图所示:

通常情况下,Single类型的动作可以设置为TRIGGER,Boolean类型的动作可以设置为BUTTON。设定以后,在按键左下角点击编辑按钮,在显示为None的位置
指定相应的动作,如下图所示:

所有动作绑定完毕,点击页面底部的Replace Default Binding按钮,会将绑定设置保存到配置文件当中。在程序运行时,无论是开发者还是游戏玩家,都可以
再次修改绑定配置,并且能够反映到游戏当中。默认情况下,每个控制器上相同的按键绑定相同的动作,如果想为每个控制器设置不同的动作,比如,左手控制
器按下Touchpad实现传送,而右手控制器按下Touchpad使用指针选择物体,那么在这种情况下,可以取消勾选页面中的Mirror Mode复选框,然后分别为每个
控制器指定不同的动作。

在绑定编辑界面中同样可以进行动作测试,点击页面底部的Input Debugger按钮进入测试页面,在此页面中,将实时显示各动作的状态、动作绑定的按键、控
制器的实时数据等信息,如下图所示:

八、 在代码中使用动作


此处以访问platformer动作集下的Move动作为例,演示如何获取动作状态,执行以下步骤:

打开SteamVR示例场景Simple Sample,选择游戏对象,为其挂载SteamVR_ActivateActionSetOnLoad组件,并指定启用platformer动作集,
如下图所示:

新建C#脚本,并命名为GetMoveAction.cs,编写代码如下所示:
using UnityEngine;using Valve.VR; public class GetMoveAction : MonoBehaviour{    void Update()    {      if (SteamVR_Input.platformer.inActions.Move.GetChanged(SteamVR_Input_Sources.Any))      {            Vector2 pos = SteamVR_Input.platformer.inActions.Move.GetAxis(SteamVR_Input_Sources.Any);            Debug.Log(pos);      }    }}
返回场景,将此脚本挂载到任意游戏对象上,保存场景运行程序,在任意控制器上触摸Touchpad时,将在控制台输出如下信息:

九、Interaction System 的变化


从功能层面来看,本次更新在Interaction System中并没有添加太多特性,这从Interaction System的更新文档中也可得出此结论,如下图所示:

Interaction System的示例场景进行了重新设计,如下图所示:

在目前的示例场景中,除包含SteamVR 2.0之前的大部分演示外,还加入了一些新的特性。比如,对投掷(Throwing)部分做了扩展、添加了遥控器和遥控车、
简易的推动按钮、手榴弹,以及一些关于Hand的示例。
在Throwing部分中,目前的示例能够实现基于速度估计的交互,类似于另外一个VR开发工具NewtonVR能够实现的效果——被抓取的物体不会直接穿过固定静止的
障碍物,而是跟随Hand沿障碍物边界滑动。所有这些交互相关的参数都可以在Throwable组件中进行设置。
Remotes部分有两个简易控制器,提供了一种与物体进行间接交互的演示。如下图所示。

在场景中的Skeleton部分,可以通过点击按钮来显示和隐藏控制器模型,以及切换不同的手部模型,如下图所示:

随着版本的更新,Interaction System已经随之支持Input System。在源代码中,可以看到Interaction System 开始使用 Input System 配置的行为进
行交互驱动,如下图所示:

十、VRTK 是否能够继续结合 SteamVR 2.0 使用


通过以上论述可见,如果VRTK没有新版更新的话,理论上来说并不能使用 VRTK(当前版本为 3.2.1) 结合 SteamVR 2.0 进行开发,除非克隆VRTK源码,
自行对其进行修改。这在 Asset Store 中也可找到了印证,如下图所示:

所以,当前版本的 VRTK (3.2.1)并不支持 SteamVR 2.0。使用 VRTK 的开发者可继续使用 SteamVR 1.2.3 进行开发,SteamVR Plugin 的过往版本可
访问以下链接进行下载。

https://github.com/ValveSoftware/steamvr_unity_plugin/releases
页: [1]
查看完整版本: Unity3D开发技术研究-SteamVR2.0杂谈