导语:随着硬件和软件技术的发展,产业界对虚拟现实(Virtual Reality)用户体验产生了重大期望。技术的进步也使我们可能通过现代浏览器借助开放Web平台获得这种用户体验。这将帮助Web成为创建、分发以及帮助用户获得虚拟现实应用和服务生态系统的重要基础平台。
引言
2016年最令科技界激动的话题,莫过于VR会如何改变世界。一些电影已开始涉足VR,让用户不仅能看到3D影像,更能以“移形换影”之术身临其境,带来前所未有的沉浸式观影体验;此外,游戏领域也开始VR化,用户再也不用忍受游戏包里单一的场景。这些酷炫效果带来了巨大想象空间,VR正在走近人们的生活。然而现实是,除了偶尔体验下黑科技的奇妙外,VR并没有真正普及,在资本和硬件厂商狂热的背后,质疑声也此起彼伏。
目前,虽然VR硬件的发展已经走上了快车道,但内容却非常单薄。一部VR电影的成本相当高昂,VR游戏也不逊色。内容创作成本的居高不下,导致了VR的曲高和寡。要想脱下那一层高冷的贵族华裳,飞入寻常百姓家,VR尚需解决内容供给这一难题。以HTML5为代表的Web技术的发展,或将改变这一僵局。目前,最新的Google
Chrome和Mozilla Firefox浏览器已经加入面向HTML5技术的WebVR功能支持,同时各方也正在起草并充实业界最新的WebVR
API标准。基于Web端的这些虚拟现实标准将进一步降低VR内容的技术创作成本及门槛,有利于世界上最大的开发者群体—HTML5(JavaScript)开发者进入VR内容创作领域。这不仅是Web技术发展历程上的显著突破,也为VR造就了借力腾飞的契机。
Web端VR的优势
Web开发者基数庞大
除了技术上的实现优势,Web还能给VR带来一股巨大的创新动力,因为它拥有着广泛的应用范围与庞大的开发者基数,能帮助VR技术打赢一场人民战争,让VR不再只是产业大亨们的资本游戏,而是以平民化的姿态,进入广大用户日常生活的方方面面。
相信假以时日,VR应用会像现在满目皆是的App一样,大量的VR开发者借助于Web端开发的低门槛而大量进入,同时各种稀奇古怪的创意层出不穷,虚拟现实成为电商商家必须的经营手段等。若到了这个阶段,VR离真正的繁荣也就不远了。
WebVR 开发的方式
在Web上开发VR应用,有下面三种方式:
HTML5+ Java Scnipt + WebGL + WebVR API
传统引擎 + Emscripten[1]
第三方工具,如A-Frame[2]
第一种方法是使用WebGL与WebVR API结合,在常规Web端三维应用的基础上通过API与VR设备进行交互,进而得到对应的VR实现。第二种是在传统引擎开发内容的基础上,比如Unity、Unreal等,使用Emscripten将C/C++代码移植到Java
Scnipt版本中,进而实现Web端的VR。第三种是在封装第一种方法的基础上,专门面向没有编程基础的普通用户来生产Web端VR内容。在本文中我们主要以第一和第三种方法为例进行说明。
Web可降低VR体验门槛
Web技术不仅使创作VR的成本更加低廉,而且大大降低技术门槛。Web VR依托于WebGL技术的高速发展,利用GPU执行计算以及游戏引擎技术针对芯片级的API优化,提高了图形渲染计算能力,大大降低开发者进入VR领域的门槛,同时Web
VR还可以更好地结合云计算技术,补足VR终端的计算能力,加强交互体验。
可以肯定,Web扩展了VR的使用范围,广告营销,全景视频等领域已经涌现一批创新案例,很多生活化的内容也纳入了VR的创作之中,如实景旅游、新闻报道、虚拟购物等,其内容展示、交互都可以由HTML5引擎轻松创建出来。这无疑给其未来发展带来更多想象空间。
开发Web端的VR内容
接下来我们通过实践操作来真正制作一些Web端的VR内容,体验WebVR的便捷优势。我们知道,许多VR体验是以应用程序的形式呈现的,这意味着你在体验VR前,必须进行搜索与下载。而Web
VR则改变了这种形式,它将VR体验搬进了浏览器,Web+VR = WebVR。在进入实践之前,下面先来分析一下WebVR实现的技术现状。
使用A-Frame开发VR内容
如果想以较低的门槛体验一把WebVR开发,那么可以使MozVR团队开发的A-Frame框架。A-Frame是一个通过HTML创建VR体验的开源WebVR框架。通过该框架构建的VR场景能兼容智能手机、PC、
Oculus Rift和HTC Vive。MozVR团队开发A-Frame框架的的是:让构建3D/VR场景变得更易更快,以吸引Web开发社区进入WebVR的生态。WebVR要成功,需要有内容。但目前只有很少一部分WebGL开发者,却有数以百万的Web开发者与设计师。A-Frame要把3D/VR内容的创造权力赋予给每个人,其具有如下的优势与特点:
A-Frame能减少冗余代码。冗余复杂的代码成为了尝鲜者的障碍,A-Frame将复杂冗余的代码减至一行HTML代码,如创建场景则只需一个<a-scene>
标签。
A-Frame是专为Web开发者设计的。它基于 DOM,因此能像其他Web应用一样操作3D/VR内容。当然,也能结合box、d3、React等JavaScript
框架一起使用。
A-Frame让代码结构化。Three.js代码通常是松散的,A-Frame在Three.js之上构建了一个声明式的实体组件系统(entity-component-system)。另外,组件能发布并分享出去,其他开发者能以
HTML的形式进行使用。
WebVR草案
WebVR是早期和实验性的JavaScript API,它提供了访问如Oculus Rift、HTC Vive以及Google
Cardboard等VR设备功能的API。VR应用需要高精度、低延迟的接口,才能传递一个可接受的体验。而对于类似Device
Orientation Event接口,虽然能获取浅层的VR输入,但这并不能为高品质的VR提供必要的精度要求。WebVR提供了专门访问VR硬件的接口,让开发者能构建舒适的VR体验。
WebVR API目前可用于安装了Firefox nightly的Oculus Rift、Chrome的实验性版本和Samsung
Gear VR的浏览器。
代码实现如下:
A-frame框架代码
// 引入A-Frame框架 <script src="./aframe.min.js"></script> <a-scene> <!-- 定义并创建球体 --> <a-sphere position="0 1 -1" radius="1" color="#EF2D5E"></a-sphere> <!-- 定义交创建立方体 --> <a-box width="1" height="1" rotation="0 45 0" depth="1" color="#4CC3D9" position="-1 0.5 1"></a-box> <!-- 定义并创建圆柱体 --> <a-cylinder position="1 0.75 1" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder> <!-- 定义并创建底板 --> <a-plane rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane> <!-- 定义并创建基于颜色的天空盒背景--> <a-sky color="#ECECEC"></a-sky> <!-- 设置并指定摄像机的位置 --> <a-entity position="0 0 4"> <a-camera></a-camera> </a-entity> </a-scene> |
上述代码在A-Frame中执行的效果如图1所示。
使用Three.js开发VR内容
上文中我们提到另外了一种更加靠近底层同时更加灵活生产WebVR内容的方法,就是直接使用WebGL+WebVR的API。这种方法相对于A-Frame的优势在于可以将VR的支持方便地引入到我们自己的Web3D引擎中,同时对于底层,特别是渲染模块可以做更多优化操作从而提升VR运行时的性能与体验。
如果没有自己的Web3D引擎也没有关系,可以直接使用成熟的渲染框架,比如Three.js和Babylon.js等,这些都是比较流行且较为出色的Web3D端渲染引擎(框架)。接下来就以Three.js为例,说明如何在其上制作WebVR内容。
首先,对于任何渲染程序的三个要素是相似的,即是建立好scene、renderer、camera。设置渲染器、场景以及摄像机的操作如下:
渲染程序代码
var renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setPixelRatio(window.devicePixelRatio); document.body.appendChild(renderer.domElement); // 创建Three.js的场景 var scene = new THREE.Scene(); // 创建Three.js的摄像机 var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 10000); // 调用WebVR API中的摄像机控制器对象,并将其与主摄像机进行绑定 var controls = new THREE.VRControls(camera); // 设置为站立姿态 controls.standing = true; // 调用WebVR API中的渲染控制器对象,并将其与渲染器进行绑定 var effect = new THREE.VREffect(renderer); effect.setSize(window.innerWidth, window.innerHeight); // 创建一个全局的VR管理器对象,并进行初始化的参数设置 var params = { hideButton: false, // Default: false. isUndistorted: false // Default: false. }; var manager = new WebVRManager(renderer, effect, params); |
上述代码即完成了渲染前的初始化设置。接下来需要向场景中加具体的模型对象,主要操作如下所示:
模型对象代码
function onTextureLoaded(texture) { texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.set(boxSize, boxSize); var geometry = new THREE.BoxGeometry(boxSize, boxSize, boxSize); var material = new THREE.MeshBasicMaterial({ map: texture, color: 0x01BE00, side: THREE.BackSide }); // Align the skybox to the floor (which is at y=0). skybox = new THREE.Mesh(geometry, material); skybox.position.y = boxSize/2; scene.add(skybox); // For high end VR devices like Vive and Oculus, take into account the stage // parameters provided. setupStage(); } // Create 3D objects. var geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5); var material = new THREE.MeshNormalMaterial(); var targetMesh = new THREE.Mesh(geometry, material); var light = new THREE.DirectionalLight( 0xffffff, 1.5 ); light.position.set( 10, 10, 10 ).normalize(); scene.add( light ); var ambientLight = new THREE.AmbientLight(0xffffff); scene.add(ambientLight); var loader = new THREE.ObjectLoader(); loader.load('./assets/scene.json', function (obj){ mesh = obj; // Add cube mesh to your three.js scene scene.add(mesh); mesh.traverse(function (node) { if (node instanceof THREE.Mesh) { node.geometry.computeVertexNormals(); } }); // Scale the object mesh.scale.x = 0.2; mesh.scale.y = 0.2; mesh.scale.z = 0.2; targetMesh = mesh; // Position target mesh to be right in front of you. targetMesh.position.set(0, controls.userHeight * 0.8, -1); }); |
最后的操作便是在requestAnimationFrame设置更新。在animate的函数中,我们要不断地获取HMD返回的信息以及对camera进行更新。
Requestanimationframe设置更新代码
// Request animation frame loop function var lastRender = 0; function animate(timestamp) { var delta = Math.min(timestamp - lastRender, 500); lastRender = timestamp; // Update VR headset position and apply to camera. //更新获取HMD的信息 controls.update(); // Render the scene through the manager. //进行camera更新和场景绘制 manager.render(scene, camera, timestamp); requestAnimationFrame(animate); } |
最后,程序运行的效果如图2所示,可以直接在手机上通过VR模式并配合Google Cardboard即可体验无需下载的VR内容[3]。
上述示例中的代码实现可从[4]中下载。
经验
通过上述介绍我们基本可以实现一个具有初步交互体验的Web端VR应用,但这只是第一步,单纯技术上的实现距离真正的可工程化还有一定差距。因为最终工程化之后面向用户的产品必须比技术原型要考虑更多具体的东西,比如渲染的质量、交互的流畅度、虚拟化的沉浸度等,这些都最终决定用户是否会持续使用产品、接受产品所提供的服务等,所以将上述技术在工程化应用之前还有很多的优化与改进工作要做。以下是个人在做Web端VR应用过程中体会的一些心得经验,分享出来供读者参考。
引擎的选用。如果是使用已有的WebGL引擎,则可参考[5]中的文档来进行VR SDK集成。这里边需要做到引擎层与VR
SDK层兼容,以及VR模式与引擎的工具部分的整合,也可以参考桌面引擎如Unity3D和Unreal在VR
SDK集成上的开发模式。如果选用第三方的WebGL引擎则有Three.js或Babylon.js等可选,这些主流的WebGL引擎都已经(部分功能)集成了VR
SDK。
调试的设备。调试Web端的VR应用同样需要有具体的VR设备的支持。对于桌面WebM内容还是要尽量使用HTC
Vive或Oculus等强沉浸感VR设备。对于移动Web应用,由于Android平台上的各浏览器的差异较大,表现也会不太一致,所以建议使用iOS设备进行开发与调试,但是在最终发布前仍要对更多的Andnoid设备进行适配性测试与优化。
性能的优化。在Web端做三维的绘制与渲染,性能还是主要瓶颈,因而要尽可能的提高实时渲染的性能,这样才能有更多资源留给VR部分。目前的WebVR在渲染实时中并没有像桌面VR
SDK一样可以调用众多的GPU底层接口做诸如Stereo rendering等深层次的优化,因而对性能的占用还是较多。
已知的问题。目前,WebVR仍然不太稳定,还会有诸多的Bug,比如某些情况下会有设备跟踪丢失的情况,而且效率也不是太高。大多数WebVR应用可以作为后期产品的储备和预研,但要推出真正可供用户使用并流畅体验的产品,还是有较长的路要走。
总结
许多人将即将过去的2016称为VR元年,在这一年中VR的确经历了突飞猛进的发展,体现在技术与生态等各个方面。在新的2017年,相信VR必将会有更大的发展与进步,作为技术工作者,我们更应该从自身的技术专长作为出发点,参与到新技术对社会与生活的变革中来。
|