19. Html5的局: 手把手写一个100行的VR程序

紧接上文

WebVR扩展了WebGL的标准,增加了HMD、PS等组件,让开发者可以在H5上开发VR程序。高级VR设备往往拥有了比手机更高精度的传感器、显示器、GPU等,让用户可以更加真实的感受虚拟世界。本节是《Html5的局》最后一节,我们手把手的写一段VR代码,感受WebVR的便捷。

本次Demo所需二维码

用户可以本地启动HTTP服务,将URL填写到播放路径
19. Html5的局: 手把手写一个100行的VR程序

3D地球

环境准备

  1. Three.js 到http://www.threejs.org下载最新源码,这里使用three.min.js作为渲染引擎。
  2. TrackballControls.js,在three.js的源码里面可以找到,作为交互控制器。

纹理准备

  1. 地球纹理,在网上可以找到最新的地图纹理,最好使用4k,比较清晰
    19. Html5的局: 手把手写一个100行的VR程序
  2. 星空纹理,虽然可以使用粒子系统来模拟星空,简单起见,使用4k纹理图
    19. Html5的局: 手把手写一个100行的VR程序

准备空白的html

我们会将所有JS代码写在单独的index.js中,因此index.html只是提供JS运行的环境,这一步为代码迁移到WebVRSDK做准备。代码如下:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL Earth</title>
    <style>
        body { margin: 0; overflow: hidden; background-color: #000; }
    </style>
</head>
<body>
    <script src="three.min.js"></script>
    <script src="TrackballControls.js"></script>
    <script src="index.js"></script> 
</body>
</html>

index.js核心代码

  1. 渲染器,使用WebGL渲染three.js中的3D对象
  2. 加载器,使用XMLHttpRequest或者Image,异步加载图片纹理
  3. 摄像机,模拟观察者的位置和方向,从不同角度来观看3D世界
  4. 控制器,接受用户点击、触摸、鼠标等事件,控制摄像机的参数,实现人机交互
  5. 材料,任何3D对象,是由骨骼和图像组成,材料就像油漆,粉刷过的对象更加真实
  6. 几何,3D对象的结构描述,这里只用球状几何
  7. 场景,用来管理所有需要展示的3D对象,以及他们之间的层级和关系
    代码如下
var w = window.innerWidth;
var h = window.innerHeight;

var renderer = new THREE.WebGLRenderer();        // 创建渲染器
renderer.setSize(w, h);                            // 设置渲染器为全屏
document.body.appendChild(renderer.domElement);    // 将渲染器添加到body上

var loader = new THREE.TextureLoader();                            // 创建纹理加载器,用于异步加载图片
var camera = new THREE.PerspectiveCamera(45, w / h, 0.01, 1000);// 创建摄像机,表示人眼的方向
camera.position.x = 4;
var controls = new THREE.TrackballControls(camera);                // 创建控制器,用来控制摄像机

var earth_mate = { map : loader.load('earth_map.jpg'), side : THREE.FrontSide };                                // 地球的表面,一张4096x2048的图片
var earth_mesh = new THREE.Mesh(new THREE.SphereGeometry(1.5, 32, 32), new THREE.MeshBasicMaterial(earth_mate));// 地球的模型,直径1.0,经纬各32切片

var stars_mate = { map : loader.load('stars_map.png'), side : THREE.BackSide };                                    // 星空的表面,一张4096x2048的图片
var stars_mesh = new THREE.Mesh(new THREE.SphereGeometry(100, 16, 16), new THREE.MeshBasicMaterial(stars_mate));// 星空的模型,直径100,经纬各32切片

var scene = new THREE.Scene();                // 创建场景
scene.add(earth_mesh);                        // 添加地球
scene.add(stars_mesh);                        // 添加星空
scene.add(new THREE.AmbientLight(0xFFFFFF));// 创建环境光

animate();
function animate() {
    requestAnimationFrame(animate);    // 下一帧回调
    earth_mesh.rotation.y += 0.002;    // 绕Y轴旋转
    controls.update();                // 控制器更新
    renderer.render(scene, camera);    // 刷新整个视图
}

用浏览器打开index.html

代码见附件:3D地球.zip
一个3D地球已经出现在了浏览器页面上。
我们可以双指上下滑动,来缩放地球
可以点击拖动,改变摄像机的视角
在手机的WebVRSDK上,可以使用三指滑动,改变摄像机的位置
19. Html5的局: 手把手写一个100行的VR程序

从Native到H5

代码量进一步减小

  1. 核心代码仅有30行,我们就实现了3D地球,只是缩放、旋转、平移。
  2. 无需编译,所见即所得,只要能够编辑文本,就可以写代码
  3. 所见即所得,浏览器页面直接刷新,妈妈再也不用担心打包慢的问题了(C++编译尤其慢)
  4. 运行时调试,程序员都懂得。

门槛进一步降低

  1. 阅读three.js后,发现3D引擎的原理也挺简单的,以前只要提到3D游戏引擎,感觉很高深的样子。
  2. 分工更加灵活,框架可以*切换,类似的3D框架在上一篇文章中已经列举,有兴趣的同学可以学习

从3D到VR

传感器由屏幕转交给HMD

屏幕、鼠标等传统人机交互,已经无法满足VR设备的输入,HMD会提供更加人性化的输入,但缺少了键盘,VR的I/O也成了难事。

定时器由VREffect触发

VR对于视频帧的刷新精度,要求更高,不同的WebVR标准表现不一样,可以简单的认为effect.requestAnimationFrame等同于window.requestAnimationFrame

3D地球升级为VR地球

只需要修改几行代码,就可以轻松的打开VR模式

环境准备

  1. VREffect.js,检查&兼容WebVR的运行环境,控制VR模式的开启与否
  2. VRControls.js,监听HMD返回的信息,并及时的操控camera来调整视角
  3. WebVR.js,人性化的展示WebVR的信息和按钮

修改代码

切换为VR控制器

var controls = new THREE.TrackballControls(camera);
改为:
var controls = new THREE.VRControls(camera);

切换帧管理器

requestAnimationFrame(animate);
effect.requestAnimationFrame(animate);

增加VR特效器

// 将renderer的任务,封装为VREffect,由VR来控制双屏显示
var effect   = new THREE.VREffect(renderer);

使用VR特效器渲染场景

effect.render(scene, camera);

增加VR检测

if (WEBVR.isAvailable() === true) {
    document.body.appendChild(WEBVR.getButton(effect));
    setTimeout(function() {
        effect.requestPresent(); // 请求双屏显示
    }, 1);
}

VR效果展示

由于附件只能上传一个,只放置了3D地球的源码,VR地球的源码和3D地球,除了index.js不一样,其他都一样,在线地址如下,自己下载一看即可。
这里放出二维码和在线链接地址,由于部分浏览器是没有兼容WebGL和WebVR,看到的效果可能不一致。
手机上,已经集成到最新的WebVRSDK中,用手机安装即可看到。

3D地球

19. Html5的局: 手把手写一个100行的VR程序
浏览器点击: 3D地球

VR地球

19. Html5的局: 手把手写一个100行的VR程序
浏览器点击: VR地球

如何使用WebVRSDK

WebVRSDK不支持Dom

WebVRSDK核心只有400k,集成了JS引擎、WebGL、WebVR、WebVideo、WebAudio、图像处理、网络处理等,如果参加Dom的支持,那和浏览器还是有什么差异?

WebVR如何加载已开发的H5工程

将核心的index.js所在的URL拷贝到APP的输入框,点击打开即可
19. Html5的局: 手把手写一个100行的VR程序

写法上有何差异

由于不支持Dom,所以加载JS的任务需要写在JS中,目前有两种写法可以支持,二者都是同步方式加载,不支持异步。

使用内置API加载外部JS资源

window.loadFile = window.__execute || function() {};    // WebVRSDK不支持Dom,所以需要自定义函数,加载JS资源。浏览器则不需要。
window.loadFile('three.js');                            // 加载当前目录的three.js
window.loadFile('promise.js');                            // 加载当前目录的promise.js
window.loadFile('RollerCoaster.js');                    // 加载当前目录的RollerCoaster.js
window.loadFile('WebVR.js');                            // 加载当前目录的WebVR.js
window.loadFile('VREffect.js');                            // 加载当前目录的VREffect.js
window.loadFile('VRControls.js');                        // 加载当前目录的VRControls.js

使用标准JS加载JS资源

var script = document.createElement("label");
script.src = 'http://xxxx.js';// 绝对路径
// 或者
script.src = 'xxx.js';//相对路径

WebVRSDK的目标

性能的极致

现在主流的手机,都是多核心CPU、支持大型3D游戏的GPU。
如果要把硬件性能发挥到极致,我认为使用C/C++,或者汇编,往往能够最大化的“榨干”硬件,但这是不现实的,因为开发效率和维护成本太高了。

所以,WebVRSDK为了追求性能的机制,底层完全使用C/C++编写,直接封装硬件最底层的API,并暴露给JS接口,实现H5的标准。

以上Demo都可以在浏览器上开发、调试、运行,运行性能可以对比IE、Chrome、Safari、FireFox,红米3也可以达到60FPS的帧率

灵活的开发方式

  1. WebVRSDK提供的只是运行环境,开发、调试完全可以在PC的浏览器上完成,开发规则除DOM不支持外,完全遵守WebGL、WebVR、WebVideo等标准

2.不挑剔渲染引擎
支持2D的pixi.js
支持3D的three.js
甚至自定义的JS引擎
。。。

WebVRSDK的未来

提供底层API运行时支持

经过数据测试(简单测试,每种开发语言都有自的优缺点,勿喷)
JS运行速度对比Java,慢10倍,甚至更多;
Java运行速度对比C/C++,慢5~10倍

JS语言作为技术底层,如何提高性能呢?
我们大胆的提出假设,JS在大规模数据计算时的性能不足,是否可以由C/C++来弥补呢?
比如,矩阵的变换和算法,针对目前向量、矩阵、四元数、欧拉角等,数学算法已经很固定,我们是否可以大胆的提出"WebTransform"标准,将这些常用的算法,用C/C++编写后,暴漏给JS,让JS只要传数据就可以瞬间获取结果?

开放平台

我们已经走到了WebVR技术的前沿,目前主流的浏览器,特别是在移动端能够支持的,还没有正式支持,即使已经支持的浏览器,性能也比较差。这点,是WebVRSDK的优势。
WebVR的发展,背后是IT巨头的博弈,毕竟谁也不愿意在同一个维度去竞争,这是时代给我们的机遇和挑战,目前VR购物、看片、游戏等场景不断增多,硬件发展又无法跟上的时候,我们技术人员是否可以做点什么呢?

下一回

Html5的局,到此结束,我也该整理整理思路。

上一篇:13. Html5的局:WebGL的模糊边界


下一篇:18. Html5的局: 用WebVR来解释小米VR眼镜