随着VR生态的日益增长,以及Valve Knuckles控制器的逐渐完善,SteamVR未来能够提供给用户更多的交互方式,比如手指跟踪和力反馈。近期,Valve在Unity资源商店中将SteamVR插件更新到了2.0版,XR技术研习社将根据官方博客和SDK文档对此次更新进行介绍,本文同时也是《HTC VIVE 交互开发实例教程》第52课备课内容。
以下为本文将要涵盖的议题:
三年前,SteamVR SDK for Unity插件的第一个版本在Unity资源商店发布,在以后的时间里,VR生态发生了很多变化,比较显著的是出现了很多不同类型的控制器,如下图:
随着越来越多的VR设备推出,控制器类型逐渐趋向于碎片化。每当有新的控制器发布,都会给开发者带来一些额外的工作量——游戏项目需要修改交互代码以适配新的设备。从开发层面上来看,不同的控制器具有不同的键值映射,所以,当现有 VR 应用程序移植到另外一个VR平台的时候,需要针对目标平台进行交互适配。鉴于此,V社为Unity开发者推出了 SteamVR Unity Plugin 2.0(以下简称SteamVR 2.0),能够使开发者在编程中专注于用户的动作,而不是具体的控制器按键。
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动作设置默认按键和阈值,当程序运行时,也可修改这些数值以满足玩家的个人偏好。基于这种机制,不光能够解决控制器碎片化的问题,也可以快速适配未来发布的设备。
Input System 的核心概念是动作(Action),基于动作的输入系统对于游戏引擎来说更有意义, Unreal一直在沿用这种方案,而Unity目前在开发中的输入系统也将遵循这一原则。开发者需要放弃之前关于“按下某个按键发生什么事情”的思想,取而代之的是使用“做出某个动作发生什么事情”的思想。
SteamVR 2.0将动作抽象为以下6种类型,简介如下:
对于骨骼输入,Knuckles控制器为SteamVR体验带来了手指跟踪功能,能够估算用户手指的位置,然后将数据传递给驱动程序,驱动程序将其对应解析到手部模型的31块骨骼上,从而给用户带来更好的沉浸式体验。该功能并不是Knuckles所独有,SteamVR还能够为HTC Vive和Oculus Touch这样的设备提供手指状态估算,比如判断手部是否打开,手指是否放置在Touchpad上。同时Valve公司还将与Microsoft展开合作,以增加对Windows MR控制器的支持。
默认情况下,运行Interaction System示例场景中能够同时看到手部和控制器模型,此外,还有一个辅助组件SteamVR_Behaviour_Skeleton,如下图所示。有关该组件的使用,可以参考Interaction System的示例场景。
以上是介绍的都是输入动作,另外,目前还有一种输出动作——振动,用于触发VR控制器上的触觉反馈,调用方法如下代码所示:
SteamVR_Input._default.outActions.Haptic.Execute(float secondsFromNow, float durationSeconds, float frequency, float amplitude, SteamVR_Input_Sources inputSource);
动作通过动作集进行逻辑上的分组,以方便进行组织和管理。在Unity中对应的类为SteamVR_ActionSet。在不同的场景或应用程序之间可以切换使用不同的动作集,比如,应用程序中有一个场景是在地球上拾取并投掷物体,而另一个场景则是在太空中飞行,那么这两个场景可以使用不同的动作集。同时,当针对新设备进行交互适配时,开发者只需对动作进行配置,而不必修改项目代码。比如,使用 Vive 控制器时,定义了一个Fire动作,当需要支持 Rift Touch 时,只需通过配置Touch控制器上符合 Fire 动作的键值即可。
SteamVR插件默认包含了三套动作集default、platformer、buggy,开发者也可以在SteamVR Input窗口中自行添加或删除动作集。
使用组件SteamVR_ActivateActionSetOnLoad可以在场景中自动激活和停用指定的动作集。对应激活和停用的方法是在Start()和OnDestroy()中实现。如下图所示:
在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按钮,进入绑定编辑页面,如下图所示:
All right,像不像实况足球的手柄设置?V社是一家游戏公司。这样,对开发者来说,控制器也像对游戏玩家那样变得友好了。
在动作编辑页面中,点击每个按键旁边的加号按钮, 弹出窗口会询问将此按键绑定为哪种模式,如下图所示:
通常情况下,Single类型的动作可以设置为TRIGGER,Boolean类型的动作可以设置为BUTTON。设定以后,在按键左下角点击编辑按钮,在显示为None的位置指定相应的动作,如下图所示:
所有动作绑定完毕,点击页面底部的Replace Default Binding按钮,会将绑定设置保存到配置文件当中。在程序运行时,无论是开发者还是游戏玩家,都可以再次修改绑定配置,并且能够反映到游戏当中。
默认情况下,每个控制器上相同的按键绑定相同的动作,如果想为每个控制器设置不同的动作,比如,左手控制器按下Touchpad实现传送,而右手控制器按下Touchpad使用指针选择物体,那么在这种情况下,可以取消勾选页面中的Mirror Mode复选框,然后分别为每个控制器指定不同的动作。
在绑定编辑界面中同样可以进行动作测试,点击页面底部的Input Debugger按钮进入测试页面,在此页面中,将实时显示各动作的状态、动作绑定的按键、控制器的实时数据等信息,如下图所示:
此处以访问platformer动作集下的Move动作为例,演示如何获取动作状态,执行以下步骤:
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);
}
}
}
从功能层面来看,本次更新在Interaction System中并没有添加太多特性,这从Interaction System的更新文档中也可得出此结论,如下图所示:
Interaction System的示例场景进行了重新设计,如下图所示:
在目前的示例场景中,除包含SteamVR 2.0之前的大部分演示外,还加入了一些新的特性。比如,对投掷(Throwing)部分做了扩展、添加了遥控器和遥控车、简易的推动按钮、手榴弹,以及一些关于Hand的示例。
在Throwing部分中,目前的示例能够实现基于速度估计的交互,类似于另外一个VR开发工具NewtonVR能够实现的效果——被抓取的物体不会直接穿过固定静止的障碍物,而是跟随Hand沿障碍物边界滑动。所有这些交互相关的参数都可以在Throwable组件中进行设置。
Remotes部分有两个简易控制器,提供了一种与物体进行间接交互的演示。如下图所示。
随着版本的更新,Interaction System已经随之支持Input System。在源代码中,可以看到Interaction System 开始使用 Input System 配置的行为进行交互驱动,如下图所示:
所以读者可通过阅读 Interaction System 的源代码进一步学习 Input System的使用。
通过以上论述可见,如果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 进行下载。
欢迎关注我的微信公众号:XR技术研习社(ID:XRStudy)