前两期主要介绍了开发WebVR应用的基本套路,不过开发出来的场景还只是“可远观而不可亵玩”,缺少交互性,本期将带你们走进VR交互世界,看看WebVR事件是如何开发的。dom
在可交互的VR世界里,用户再也不只是个观察者,而是虚拟世界中一个生命,能够与虚拟世界进行通讯。这种通讯应该是双向的:虚拟场景能感知你的存在(位置、方向),同时你的输入又对物体产生做用。这里借鉴一个VR游戏场景:ide
上述共采用了四种交互方式,根据输入设备可分为headset头显交互和gamepad手柄交互,前者经过头显行为触发事件(如二、4),后者经过手柄行为触发事件(如一、3)。this
这些交互行为都须要硬件支持(好比陀螺仪和加速计提供方向追踪支持),咱们须要经过JavaScript API来获取headset或者gamepad的动态数据。google
因为各VR产商的头显和手柄具备差别,所以对于用户交互层面的支持度也良莠不齐,如下展现各主流VR平台在头显和手柄方面的在交互上的支持状况。spa
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自由度两种。code
一般在VR体系里,3-DoF指的是VR硬件支持Orientation,6-DoF指的是支持Orientation + Position。对象
Headset交互根据自由度可分为3-DoF和6-DoF,显然,全部的VR头显都应支持Orientation方向的3-DoF追踪。教程
实现headset交互,首先是要能看获得虚拟世界,上期WebVR深度剖析中VR渲染是实现headset交互的第一步,咱们须要使用WebVR API来获取headset数据。three
这里再复习一下:当用户戴着headset扭头或走动时,渲染器在每帧经过VRFrameData的视觉-投影矩阵,动态计算出每一个物体的MVP复合矩阵,最后进行顶点和片元绘制。
使人兴奋的是,three.js已经将这个过程封装到了相机和渲染器中,帮咱们实现了第一步。
第二步,咱们须要让三维场景感知用户(头部)的存在,举个例子,当一个球朝着玩家丢过来的时候,玩家机灵一躲,程序根据球体与玩家的位置判断玩家是否躲闪成功。
这时候,咱们还须要用到VRFrameData一个重要属性pose
,经过frameData.pose
返回一个VRPose
对象,可获取headset的传感器信息,好比位置、方向、速度和加速度等。
属性|类型|说明
:------------:|:------------:|:------------:
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时,走动超过范围弹出警告的功能:
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的position
和orientation
转化成camera的Object3D属性,所以咱们能够直接调用camera.position
和camera.quaternation/rotation
获取用户的位置和朝向,代码简化以下:
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事件监听,点头摇头事件监听等。
除了headset,如今大部分VR还搭配gamepad,用户经过手持手柄能够与虚拟场景进行交互。
对于gamepad手柄而言,也有3-DoF和6-DoF的两种类型:
相比headset传感器输入产生的交互,gamepad还多了各类输入元件,如按钮、touchpad触控板或thumbstick手摇杆等。
因而,根据手柄输入硬件又可将gamepad事件分为三类:
A. 传感器事件:由传感器对手柄进行物理追踪,如激光笔交互;
B. 按钮事件:经过点击按钮产生的交互行为;
C. 控制单元事件:由thumbstick, touchpad输入产生,如swipe滑动来翻页等。
那么如何实现gamepad的交互事件呢?其实换个问题就是:如何访问手柄的硬件信息,答案是使用Gamepad API,详见WebVR开发教程——交互事件(二)使用Gamepad
WebVR开发教程——深度剖析 关于WebVR的开发调试方案以及原理机制
WebVR开发教程——标准入门 使用Three.js开发WebVR场景的入门教程