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

紧接上文

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

本次Demo所需二维码

用户可以本地启动HTTP服务,将URL填写到播放路径

3D地球

环境准备

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

纹理准备

  1. 地球纹理,在网上可以找到最新的地图纹理,最好使用4k,比较清晰
  2. 星空纹理,虽然可以使用粒子系统来模拟星空,简单起见,使用4k纹理图

准备空白的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上,可以使用三指滑动,改变摄像机的位置

从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地球


浏览器点击: 3D地球

VR地球


浏览器点击: VR地球

如何使用WebVRSDK

WebVRSDK不支持Dom

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

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

将核心的index.js所在的URL拷贝到APP的输入框,点击打开即可

写法上有何差异

由于不支持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的局,到此结束,我也该整理整理思路。

时间: 2024-07-28 17:29:14

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

vc 如何创建服务-VC 开机自动启动。不用写注册表的方法。想写一个服务来启动这个程序。

问题描述 VC 开机自动启动.不用写注册表的方法.想写一个服务来启动这个程序. 有个EXE程序想要它开机自动启动.我不想用写注册表的方法启动.看能不能够写一个服务来启动这个程序.如果可以麻烦大家能够提供源码.谢谢!!!!! 解决方案 创建服务,CreateService()

windows-用MFC写一个window蓝牙通讯的程序需要用到哪些

问题描述 用MFC写一个window蓝牙通讯的程序需要用到哪些 在vs2013环境下用MFC写一个window蓝牙通讯的程序,需要哪些东西,要Windows SDK吗?vs 2013是否自带有 windows SDK? 解决方案 #include < Winsock2.h > #include < Ws2bth.h > #include < BluetoothAPIs.h > #pragma comment(lib, "ws2_32.lib") #p

ava 基础-如何使用JavaSEAPI写一个实现DOS命令的程序?

问题描述 如何使用JavaSEAPI写一个实现DOS命令的程序? javaseAPI可以写出能够控制系统开关机,之类的程序...

log4j-想写一个docx转html的程序但是控制台显示的是这样,并且在html的第一行有警告

问题描述 想写一个docx转html的程序但是控制台显示的是这样,并且在html的第一行有警告 log4j:WARN No appenders could be found for logger (org.docx4j.jaxb.Context). log4j:WARN Please initialize the log4j system properly. 解决方案 实际上这种警告很正常的,网上也有对应消除警告的方法:http://blog.sina.com.cn/s/blog_5f7d1a6

c语言-如何用C语言写一个暴力破解SSH的程序

问题描述 如何用C语言写一个暴力破解SSH的程序 也就是用同文件夹里的一个字典,可以用fopen和fgets把密码一条一条打开,可是我不知道怎么在C语言里对一个其他地址进行SSH 求大神解答 解决方案 C语言没有 SSH 的功能,所以需要你去自己搞 SSH 算法. 解决方案二: 参考openssh,这个是开源的,可以用它来调用,连接http://www.openssh.com/

写一个用户在线显示的程序

在开始这篇文章时,作者假设读者已能够写出一个用户的登入认证程序. ---------------------------------------------------------- 记数器可完成访问 web 页的总次数,但却不能得知一个时段中访问量的动态记载,下面就来介绍如何写一个各个时段动态显示访问量的方法. 要记载访问量,首先就要在 mysql 内建立一个数据库,姑且给这个数据库取名为 line,同时建立一个名为 line 的数据表,表内的字段分别为"用户名(name varchar(20

写了100万行代码的程序员身上发生了什么故事

今天在社群上闲逛,突然发现一个十分有趣的帖子,<写了100W行的代码是啥感觉?> 看完之后就头皮一阵发麻,让我写一万行的代码?!are you kidding me?(黑人问号脸)我估计写到20万的时候就会突然有个疑问--"咦?我的头发呢?" A同学:我写两千行代码功能都得琢磨个两三天,一百万行真的是好多啊,最多了五年写了也就 20-30万行代码左右,还是有任务在身的情况被逼着写的,让我写一百万行代码,恐怕这辈子得死在电脑前了- B同学:我是觉得如果说你一个工作写了一百万行

php 进阶:写一个用户在线显示的程序

在开始这篇文章时,作者假设读者已能够写出一个用户的登入认证程序. ---------------------------------------------------------- 记数器可完成访问 web 页的总次数,但却不能得知一个时段中访问量的动态记载,下面就来介绍如何写一个各个时段动态显示访问量的方法. 要记载访问量,首先就要在 mysql 内建立一个数据库,姑且给这个数据库取名为 line,同时建立一个名为 line 的数据表,表内的字段分别为"用户名(name varchar(20

用ASP.Net写一个发送ICQ信息的程序代码

asp.net|程序 这里我给大家提供一个很实用的例子,就是在线发送ICQ信息.想一想我们在网页上直接给朋友发送ICQ信息,那是多么美妙的事情啊.呵呵,在吹牛啊,其实ICQ本来就有在线发送的代码,不过,这些都是AOL给你写好的代码,多没有意思啊.还是自已写的比较好,呵呵,废话少说,大家来看代码吧. <% @ Page Language="C#" %><% @ Assembly Name="System.Net" %><% @ Impor