在开始谈 WebVR 前,我们先来看看人眼中的三维立体是如何产生的。
外部世界是三维立体的,但是它在我们的视网膜上留下的投影却是二维的。因为大脑会自动利用视觉信息中的各种深度知觉的线索,“重建”出立体的感知。人眼立体视觉的原理基本是依靠深度知觉+双眼视差。
WebVR API 目前还停留在草案阶段,仅能在安装了 Firefox nightly 的 Oculus Rift、Chrome 的实验性版本和 Samsung Gear VR 的浏览器上使用。除了使用原生 API 开发外,目前还可以使用 Mozilla 开发的 A-Frame 框架和 Three.js。本文主要描述的是使用 Three.js 的移动浏览器WebVR体验。
Three.js是一个3D JavaScript 库。封装了底层的图形接口,除了 WebGL 之外,Three.js 还提供了基于 Canvas、SVG 标签的渲染器。2016年天猫双十一宇宙邀请函中酷炫的“一镜到底”就是用的 Three.js 实现的。
创建 Three.js
创建一个 Three.js 的项目,至少包括:
1)渲染器(Renderer)
渲染器决定了渲染的结果应该显示在页面的什么元素上,并以怎样的方式绘制。
以 Canvas 为例,可以绑定渲染器,也可以动态创建渲染器。
2)场景(Scene)
场景只有一种,是所有物体的容器。
3)相机(Camera)
WebGL 和 Three.js 使用的三维坐标轴遵循“右手坐标系”。使用 Three.js 创建的场景是三维的,而通常情况下显示屏是二维的。相机它定义了三维空间到二维屏幕的投影方式。针对投影方式的不同,相机又分为正交投影(OrthographicCamera)与透视投影(PerspectiveCamera)。
正交投影,六个参数分别对应x、y,z轴的最小最大值。它创建一个正射投影矩阵。为了保持相机的横竖比例,需要保证(right - left)与(top - bottom)的比例与 Canvas 宽度与高度的比例一致。
透视投影,四个参数分别是视野在 y-z 平面的角度、投影平面宽高比、近平面(沿Z负轴)的距离,远平面(沿Z负轴)的距离。它创建一个对称的透视投影矩阵。
此外项目中加入光源(Light)与阴影(Shadow)会让场景的渲染效果更加丰富逼真。
我们以 Three.js 官方 examples 中的 WebVR 360° 全景图为例,看看一个完整的 WebVR 项目还依赖哪些 js。
其他 VR 插件
除了引入 Three.js 外,还引入了:
1)VRControls.js
移动浏览器上一般会使用 deviceorientation 事件来检测设备的朝向,WebVR API 可以帮助我们更好的控制设备。使用 VRControls.js,能在 requestAnimationFrame 中不断的获取HMD状态信息并应用到相机(Camera)上。
2)VREffect.js
VREffect.js 会通过 getEyeParameters 获取左眼所视信息,通过获取的可视角度和瞳距用透视投影(PerspectiveCamera)把屏幕 render 为左右两个屏幕,分别对应左右眼,利用深度知觉+两眼视差,让大脑“重建”出立体场景。
3)WebVR.js
WebVR.js 主要提供 WebVR 环境检测,在不兼容 WebVR 体验下的内容提示,以及显示按钮用来“进入”/“退出” WebVR 体验模式。
编写全景图项目
引用完 Three.js 和3个 VR 插件后,就可以开始编写全景图项目主要代码了。
首先需要判断设备是否支持 WebVR,不支持就需要在屏幕上提醒用户。
开始创建渲染器、场景和相机。
接着就是制作360°全景场景,一般可分为球面全景图方式、柱状全景图方式和立方体全景图方式。
球面全景图虽然具有和人眼最接近的构建模式。但实际制作球面贴图时,因为上下两个顶点处汇集了所有的经线,需要很多立面拼接成一个球体,过于繁琐并且浏览器性能消耗过高。
柱形全景图的垂直视野小,不好做顶部底部的俯仰视角。贴图在侧面虽然最简单,但头顶和脚底是无法观察的区域。
立方体型全景图是由前,后,左,右,上,下6张图片拼接而成。相机位于立方体的中心,也是360°全视角。
贴图相对球形更简单,但是因为是矩形关系,在8个顶点处会有畸变。
在 Three.js 官方示例中,使用的就是立方体全景图。然后再用 Canvas 把全景图片源文件转化为所需数量的贴图面,并用 THREE.Texture 创建纹理贴图对象保存。
因为 VREffect.js 会渲染左右2个屏幕,左相机对应 layers=1 的 skyBox,所以还需要创建一份右相对应 layers=2的skyBoxR。
然后加入 VRControls、VREffect 和按钮。
最后监测一下 window 窗口的大小变化,resize 的时候调整相机角度、更新投影矩阵,调整 WebVR effect 渲染大小。在 requestAnimationFrame 中不断监测设备状态并更新到 Camera 和 WebVR 渲染上。剩下的就是带上 VR HMD 设备查看全景图。
注:
部分图片来自网络
更多 Three.js 和 Web VR 内容,请移步 https://threejs.org和 https://w3c.github.io/webvr
本文作者:陈自然(点融黑帮),高级前端开发,现就职于点融网技术部 Clients 团队。