WebVR如此近 - three.js的WebVR示例程序解析
关于WebVR
最近VR的发展十分吸引人们的眼球,很多同学应该也心痒痒的想体验VR设备,然而现在的专业硬件价格还比较高,入手一个估计就要吃土了。但是,对于我们前端开发者来说,我们不仅可以简单地在手机上进行视觉上的VR体验,还可以立马上手进行Web端VR应用的开发!
WebVR是一个实验性的Javascript API,允许HMD(head-mounted displays)连接到web apps,同时能够接受这些设备的位置和动作信息。这让使用Javascript开发VR应用成为可能(当然已经有很多接口API让Javascript作为开发语言了,不过这并不影响我们为WebVR感到兴奋)。而让我们能够立马进行预览与体验,移动设备上的chrome已经支持了WebVR并使手机作为一个简易的HMD。手机可以把屏幕分成左右眼视觉并应用手机中的加速度计、陀螺仪等感应器,你需要做的或许就只是买一个cardboard。
不说了,我去下单了!
img cardborad纸盒,一顿食堂饭钱即可入手
前言
WebVR仍处于w3c的草案阶段,所以开发和体验都需要polyfill。
这篇解析基于 webvr-boilerplate ,这个示例的作者,任职google的 Boris Smus 同时也编写了 webvr-polyfill 。 three.js examples中也提供了关于VR的控制例子。这里主要通过对代码注释的方式来解读关键的文件。
示例的最终效果如下,打开Demo并把手机放进cardboard即可体验。你也可以在我的github对照有关的代码和注释。
Demo链接: http://soaanyip.github.io/webvr-boilerplate-cn/ 我的github: https://github.com/SoAanyip/WebVR-Boilerplate-CN/
按照惯例,这篇解析默认你至少有three.js相关的基础知识。有兴趣也可以浏览一下我之前写的一篇文章:
《ThreeJS 轻松实现主视觉太阳系漫游》 https://zhuanlan.zhihu.com/p/20796329 (复制链接在浏览器打开)
这篇解析中three.js的版本为V76。文中如有各种错误请指出!
先从html开始
在示例中只用到了一个index.html。首先meta标签有几个值得注意的:
这几个标签对web app开发的同学来说应该是十分熟悉了。其中 shrink-to-fit=no
是Safari的特性,禁止页面通过缩放去适应适口。
接下来在js引用的部分,引用了这几个资源:
//作者引入的一个promise polyfill;
<script src="node_modules/es6-promise/dist/es6-promise.js"></script>
//three.js核心库
<script src="node_modules/three/three.js"></script>
//从连接的VR设备中获得位置信息并应用在camera对象上,将在下文展开;
<script src="node_modules/three/examples/js/controls/VRControls.js"></script>
//处理立体视觉和绘制相关,将在下文展开;
<script src="node_modules/three/examples/js/effects/VREffect.js"></script>
//WebVR polyfill,下文简述调用的API option;
<script src="node_modules/webvr-polyfill/build/webvr-polyfill.js"></script>
// 界面按钮以及进入/退出VR模式的控制等。
<script src="build/webvr-manager.js"></script>
具体的整个项目文件,可以在这里查看有关的代码和注释。
VRControls.js - HMD状态感应
这个文件主要对HMD的状态信息进行获取并应用到camera上。例如在手机上显示的时候,手机的旋转倾斜等就会直接作用到camera上。
第一步是获取连接的VR设备,这一步是基本通过WebVR的API进行的:
然后是三个关于位置的参数:
通过WebVR API获取到用户的设备信息,并应用到camera上,是一个持续进行的过程。因此这部分的信息更新会在requestAnimationFrame中不断地调用。
以上是vrcontrols的关键代码。
VREffect.js - 立体视觉
VREffect.js主要把屏幕显示切割为左右眼所视的屏幕,两个屏幕所显示的内容具有一定的差异,使得人的双目立体视觉可以把屏幕中的内容看得立体化。这个文件主要的流程如下图:
首先是对画布大小进行了设定。其中 renderer.setPixelRatio( 1 );
是防止在retina等屏幕上出现图像变形等显示问题。
然后是关于全屏模式的设置,这里跟上面的设定差不远:
接下来是对表示左右眼的camera的设定。两个camera也肯定是PerspectiveCamera:
从WebVR API中获取关于某个眼睛所视的屏幕的信息:
由于左右camera的视锥体还没确定,需要对获得的FOV信息进行计算来确定。在涉及透视投影矩阵的部分会比较复杂,所以这里不展开来说。如果有错误请指出:
之后是确定左右camera的位置和方向。由于左右眼(左右camera)肯定是在头部(主camera,位置和方向由HMD返回的信息确定)上的,在我们获得把眼睛从头部飞出去的超能力之前,左右camera的位置和方向都是根据主camera来设定的。
最后便是对两个区域进行渲染。
VREffect文件的关键点差不多是上述这些。
webvr-polyfill.js - 让现在使用WebVR成为可能
webvr-polyfill.js
根据WebVR API的草案来实现了一套polyfill。例如根据所处环境是pc还是手机来确定使用的是 CardboardVRDisplay
还是 MouseKeyboardVRDisplay
,在手机环境下的话使用 Device API
来处理手机旋转、方向等参数的获取。此外作者还顺便做了几个提示图标和画面来优化体验。在这里我们来看一下其API参数:
其config主要是对一些用户可选项进行设定。在文件内部,更多的是对 Device API
的应用等等。
现在就开始编写WebVR应用吧!
在示例的最后是一个显示简单的旋转立方体的demo。此处可以帮助我们学习怎么创建一个WebVR应用。
首先是建立好scene、renderer、camera的三要素:
对上面解析过的controls、effect进行调用:
在场景中,添加一个网格显示的空间,在空间内加入一个小立方体:
最后便是设置requestAnimationFrame的更新。在animate的函数中,不但要考虑立方体的旋转问题,更重要的是要不断地获取HMD返回的信息以及对camera进行更新。
总结
以上便是此示例的各个文件的解析。我相信VR的形式除了在游戏上的应用的前景,在其他方面也有其值得探索的可行性。所以让我们一起来开始WebVR之旅吧!
参考文献
webvr.info WebVR_API http://threejs.org/docs/ https://github.com/borismus/webvr-polyfill https://github.com/borismus/webvr-boilerplate https://w3c.github.io/webvr/ Eye FOV http://blog.csdn.net/popy007/article/category/640562 http://blog.csdn.net/iispring/article/details/27970937 http://www.idom.me/articles/841.html
如果您觉得我们的内容还不错,就请转发到朋友圈,和小伙伴一起分享吧~
本文系腾讯Bugly独家内容,转载请在文章开头显眼处注明作者和出处“腾讯Bugly(http://bugly.qq.com)”
- CVE-2015-0235:Linux glibc高危漏洞的检测及修复方法
- zabbix监控在lnmp环境下编译安装小记
- 【重磅】百度开源分布式深度学习平台,挑战TensorFlow (教程)
- WordPress评论ajax动态加载,解决静态缓存下评论不更新问题
- WordPress显示访客UA信息:Show UserAgent纯代码轻度汉化版
- WordPress开启颜色评论但不造成XSS漏洞的小方法
- WordPress强迫症技巧:让文章(ID)地址完美连续(障眼法)
- iOS内存管理:从MRC到ARC实践
- MySQL错误修复:Table xx is marked as crashed and last (automatic?) repair failed
- PHP跨站脚本攻击(XSS)漏洞修复方法(一)
- Windows下获取网络连线实际名称,加强IP类设置脚本的兼容性
- Android APP 快速 Pad 化实现
- PHP彩蛋还是漏洞?expose_php彩蛋的触发和屏蔽方法
- 深入源码探索 ReactNative 通信机制
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Codeforces Beta Round #3 C. Tic-tac-toe
- [记录] 数据库中,根据经纬度,查询距离最近的地点
- PAT (Basic Level) Practice (中文)1010 一元多项式求导 (25 分)
- R语言随机森林模型中具有相关特征的变量重要性
- PAT (Basic Level) Practice (中文)1009 说反话 (20 分)
- Codeforces Beta Round #8 A. Train and Peter
- Codeforces Round #559 (Div. 2)B. Expansion coefficient of the array
- Codeforces Beta Round #72 (Div. 1 Only)B. Doctor
- pygame游戏常用方法
- node-blog:用 node 搭建的个人开源博客
- 2018-2019 ICPC, NEERC, Southern Subregional Contest D. Garbage Disposal
- 「查缺补漏」JavaScript执行上下文-执行栈
- 树状数组 _ 求逆序数
- PAT (Basic Level) Practice (中文)1012 数字分类 (20 分)
- PAT (Basic Level) Practice (中文)1018 锤子剪刀布 (20 分)