WebVR教程--交互事件

前两期主要介绍了开发WebVR应用的基本套路,不过开发出来的场景还只是“可远观而不可亵玩”,缺乏交互性,本期将带大家走进VR交互世界,看看WebVR事件是如何开发的。

VR交互有哪些?

在可交互的VR世界里,用户不再只是个观察者,而是虚拟世界中一个生命,可以与虚拟世界进行通信。这种通信应该是双向的:虚拟场景能感知你的存在(位置、方向),同时你的输入又对物体产生作用。这里借鉴一个VR游戏场景:

  1. 一位MM想让你给她选衣服,弹出一个菜单让你选,你用touchpad滑动选择给MM装扮,你选了一条裙子并点击手柄的按钮确认;
  2. MM问你看起来好不好看,你赶紧点头;
  3. MM很高兴,让你给她拍照,这时候你的手柄已变成了相机,对准她按下按钮就可以拍照;
  4. 然而你二话不说蹲下去想欣赏MM的裙底,结果MM生气了,游戏结束!

VR女友——点头与摇头

上述共采用了四种交互方式,根据输入设备可分为headset头显交互和gamepad手柄交互,前者通过头显行为触发事件(如2、4),后者通过手柄行为触发事件(如1、3)。

这些交互行为都需要硬件支持(比如陀螺仪和加速计提供方向追踪支持),我们需要通过JavaScript API来获取headset或者gamepad的动态数据。

由于各VR产商的头显和手柄具有差异,因此对于用户交互层面的支持度也参差不齐,以下展示各主流VR平台在头显和手柄方面的在交互上的支持情况。

VR类型 headset gamepad
Cardboard 3-DoF
Daydream Smartphone VR 3-DoF 3-DoF
Daydream Standalone VR 6-DoF ?-DoF
Gear VR 3-DoF 3-DoF
Oculus Rift 6-DoF 6-DoF
HTC Vive 6-DoF 6-DoF
Microsoft MR 6-DoF 6-DoF

表中的DoF(degree of freedom)就是我们常说的自由度,主要为Orientation自由度和Position自由度两种。

  • Orientation自由度,支持方向追踪,一般由陀螺仪、加速计等传感器支持

  • Position自由度,支持位置追踪,一般分为outside-in(外向追踪)的红外追踪技术和inside-out(内向追踪)的SLAM技术支持

通常在VR体系里,3-DoF指的是VR硬件支持Orientation,6-DoF指的是支持Orientation + Position。


Headset交互事件

Headset交互根据自由度可分为3-DoF和6-DoF,显然,所有的VR头显都应支持Orientation方向的3-DoF追踪。

  • 3-DoF依赖于设备的陀螺仪和加速计支持,根据头部朝向来渲染场景视角,可以支持gaze注视和摇头点头的行为,一般以手机VR为主;
  • 6-DoF则指的是支持空间追踪,由于可以感知空间移动,可以支持Lean, dodge, duck的交互方式,如Oculus Rift和Htc Vive,以及Microsoft MR和Daydream Standalone等。

DoF of Headset

实现headset交互,首先是要能看得到虚拟世界,上期WebVR深度剖析中VR渲染是实现headset交互的第一步,我们需要使用WebVR API来获取headset数据。

这里再复习一下:当用户戴着headset扭头或走动时,渲染器在每帧通过VRFrameData的视觉-投影矩阵,动态计算出每个物体的MVP复合矩阵,最后进行顶点和片元绘制。
令人兴奋的是,three.js已经将这个过程封装到了相机和渲染器中,帮我们实现了第一步。

第二步,我们需要让三维场景感知用户(头部)的存在,举个例子,当一个球朝着玩家丢过来的时候,玩家机灵一躲,程序根据球体与玩家的位置判断玩家是否躲闪成功。
6-DoF交互:躲闪小球
这时候,我们还需要用到VRFrameData一个重要属性pose,通过frameData.pose返回一个VRPose对象,可获取headset的传感器信息,比如位置、方向、速度和加速度等。

VRPose

属性 类型 说明
position Float32Array 返回headset的位置矩阵
orientation Float32Array 返回headset的方向矩阵
angularAcceleration Float32Array 返回x, y, z轴每秒的角加速度
angularVelocity Float32Array 返回x, y, z轴每秒的角速度
linearAcceleration Float32Array 返回x, y, z轴每秒的线性加速度
linearVelocity Float32Array 返回x, y, z轴的线性速度

通过这几个属性,我们可以让相机具备物理数据,拥有实体感知能力,而不单单只是观察者模式。

比如,下面实现用户在使用HTC Vive此类6-DoF的headset时,走动超过范围弹出警告的功能:

1
2
3
4
5
6
7
8
9
10
11
update() {
const { vrdisplay, frameData, userModel } = this;
frameData = vrdisplay.getFrameData(frameData);
const vrpose = frameData.pose;
userModel.position.fromArray(vrpose.position); // 将VRPose位置矩阵赋予用户角色
const { x, y, z } = userModel.position; // 解构用户位置的x,y,z坐标
if ( Math.abs(x) > 20 || Math.abs(y) > 20 || Math.abs(z) > 20 ) {
// 当用户离初始点超过20×20×20的空间时,弹出警告
showWarningToast(); // 展示警告框
}
}

同样,three.js在VR模式下会自动将VRPose的positionorientation转化成camera的Object3D属性,因此我们可以直接调用camera.positioncamera.quaternation/rotation获取用户的位置和朝向,代码简化如下:

1
2
3
4
5
6
7
8
update() {
const { camera, userModel } = this;
userModel.position.copy(camera.position);
const { x, y, z } = userModel.position; // 解构用户位置坐标
if ( Math.abs(x) > 20 || Math.abs(y) > 20 || Math.abs(z) > 20 ) {
showWarningToast(); // 用户离初始点超过20×20×20的空间时,弹出警告框
}
}

基本的headset交互事件就是这样,理解了这些,我们可以实现gaze事件监听,点头摇头事件监听等。


GamePad交互事件

除了headset,现在大部分VR还搭配gamepad,用户通过手持手柄可以与虚拟场景进行交互。

对于gamepad手柄而言,也有3-DoF和6-DoF的两种类型:

  • 3-DoF如daydream controller,只支持方向追踪,于是google推荐采用laser激光笔进行交互。

  • 6-DoF如Oculus touch,可以进行方向和位置追踪,因此可以很好的模拟手臂的动作。

相比headset传感器输入产生的交互,gamepad还多了各种输入元件,如按钮、touchpad触控板或thumbstick手摇杆等。

于是,根据手柄输入硬件又可将gamepad事件分为三类:

  • 传感器事件:由传感器对手柄进行物理追踪,如激光笔交互;
  • 按钮事件:通过点击按钮产生的交互行为;
  • 控制单元事件:由thumbstick, touchpad输入产生,如swipe滑动来翻页等。

那么如何访问手柄硬件数据进行gamepad的事件开发呢?答案是使用Gamepad API,下一期将针对Gamepad API的使用方法进行介绍。