本文旨在介绍如何搭建WebVR工程以支持多场景开发。

首先,作为一个基本的前端工程来说,我们需要让代码“工程化”,不仅要提供编译构建、压缩打包功能,还要让每个页面模块化;
延伸到WebVR工程,我们也需要考虑“多页面”模块化,即提供多个场景模块化开发,因为一个完整的WebVR App不仅仅只有一个场景。这里可以参考google的WebVR多场景示例:Chrome Experiments for Virtual Reality

webvr多场景应用

多场景开发,最简单的方式就是,一个场景对应一份html、css、js,多个页面需要多个html,每次页面跳转需要重新进行VR渲染进行初始化。
实际上我们在多场景中,场景初始化只需要执行一次(比如,创建一个场景->创建相机->创建渲染器),我们只需要一个index.html作为入口页面,将VR场景初始化、创建、回收、切换封装成公用组件。

WebVR场景切换,用户的耐心是有限的

在首次进入场景时进行初始化,在需要场景切换时进行场景回收和按需加载,这样一来,用户切换场景时,不用把时间浪费在等待html和初始化场景上。基于以上思路,本人总结的一套WebVR工程搭建方案,供各位参考。

项目地址:YorkChan94/webvr-webpack2-boilerplate
Demo:yorkchan94.github.io/webvr-webpack2-boilerplate/dist
相关技术栈:three.js、webpack2、es6/7
想详细了解WebVR开发步骤,也欢迎参考我的文章《VR大潮来袭——前端开发能做些什么》

实现功能

  • VR多场景模块化开发
  • 支持VR场景创建、回收、切换
  • 项目自动化构建与压缩打包
  • 支持es7/6

WebVR相关库

  • three.js
  • vrcontrols.js
  • vreffect.js
  • webvr-manager.js
  • webvr-polyfill.js
  • three-onevent.js

主要目录结构

webpack
|-- webpack.config.js       # 公共配置
|-- webpack.dev.js          # 开发配置
|-- webpack.prod.js         # 生产配置
src                         # 项目源码
|-- page                    # WebVR场景目录
|   |-- index.js            # WebVR入口场景
|   |-- page1.js
|   |-- page2.js
|-- common                  # 公共目录,包括webvr封装类和polyfill
|   |-- VRCore.js
|   |-- VRPage.js
|   |-- vendor.js
|-- lib                     # vr三方插件,包括相机控制器和分屏器
|   |-- vrcontrol.js
|   |-- vreffect.js
|-- assets                  # 素材目录,包括3d模型、纹理、音频等
|   |-- audio
|   |-- model
|   |-- texture
|-- index.html              # WebVR公用页面
package.json
READNE.md

我们先来看看index.html,其实整个body就只有一个dom,用来append我们的canvas,毕竟所以场景都在canvas里运行。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no"><title>webVR-INDEX</title>
</head>
<body><section class="webvr-container"></section>
</body>
</html>

有了公用html,我们希望这样开发WebVR应用,即一个场景对应一个js脚本,形如:

// 继承VRPage父类,开发每一个场景
import VRPage from 'common/js/VRPage';class Page1 extends VRPage {start() { // 启动渲染之前,创建场景3d模型let geometry = new THREE.CubeGeometry(5,5,5);let material = new THREE.MeshBasicMaterial( { color:0x00aadd} );this.box = new THREE.Mesh(geometry,material);this.box.position.set(3,-2,-3);WebVR.Scene.add(this.box);}loaded() { // 场景资源加载完毕,可执行音频播放等。}update(delta) { // 开启渲染之后,执行模型动画this.box.rotation.y += 0.05;}
}
export default (() => {return new Page1();
})();

这里参照了类似Unity3d和React的开发模式,在start方法里创建3d模型,在update方法里处理3d动画,这样的好处在于:

  1. 每一个场景都可以进行独立开发而互不影响;
  2. 一旦VR环境初始化之后,不需要在每次场景跳转切换时重新初始化一遍。

WebVR多场景运行机制

VRCore.js作为公用模块管理整个webvr应用的所有子场景,包括场景初始化、VR相机渲染、场景切换、场景回收等静态函数。
VRPage.js作为每个场景的工厂类,支持不同3d页面(场景)之间的代码独立。
每一个VR页面的生命周期都是:创建物体->加载模型->启动渲染的过程,因此,需要创建一个基类,来实现每一个VR场景实例的生命周期。

//common/VRPage.js
import * as WebVR from 'VRCore.js' //管理所有场景的公用模块
// VR场景工厂
export default class VRPage {constructor(options={}) {// 创建场景,如果场景已初始化WebVR.createScene(options);this.start();this.loadPage();}loadPage() {THREE.DefaultLoadingManager.onLoad = () => {// 模型加载完毕,即开启渲染WebVR.renderStart(this.update);this.loaded(); }}start() { // 实例的start方法将在启动渲染之前,场景相机初始化后执行。}loaded() {// 实例的loaded方法将在场景资源加载后执行。}update(delta) { // 实例的update方法将在渲染器每一次渲染时执行。}
}

这里使用THREE.DefaultLoadingManager.onLoad方法监听场景是否加载完毕,一旦加载完毕,便启动渲染。

WebVR场景首次渲染

主要包括四个步骤

  1. 新建场景
  2. 创建VR相机
  3. 加载场景脚本与资源
  4. 开启动画渲染

VR环境初始化

function createScene({domContainer=document.body,fov=70,far=4000}) {// 创建场景Scene = new THREE.Scene();// 创建相机Camera = new THREE.PerspectiveCamera(fov,window.innerWidth/window.innerHeight,0.1,far);Camera.position.set( 0, 0, 0 );Scene.add(Camera);// 创建渲染器Renderer = new THREE.WebGLRenderer({ antialias: true } );Renderer.setSize(window.innerWidth,window.innerHeight);Renderer.shadowMapEnabled = true;Renderer.setPixelRatio(window.devicePixelRatio);domContainer.appendChild(Renderer.domElement);initVR();resize();
}

首先是three.js开发三部曲,创建场景、相机、渲染器,接着调用initVR函数来完成VR场景分屏和陀螺仪控制,WebVR基本开发步骤可以参考。

function initVR() {// 初始化VR分屏器和控制器Effect = new THREE.VREffect(Renderer);Controls = new THREE.VRControls(Camera);// 初始化VR管理器Manager = new WebVRManager(Renderer, Effect);window.addEventListener( 'resize', e => {// 调整渲染器和相机以适应窗口拉伸时宽高变动Camera.aspect = window.innerWidth / window.innerHeight;Camera.updateProjectionMatrix();Effect.setSize(window.innerWidth, window.innerHeight);}, false );
}

开启动画渲染

// VRCore.js
function renderStart(callback) {// 设置loopID变量记录每一帧IDloopID = 0;const loop = () => {if(loopID === -1) return;loopID = requestAnimationFrame(loop);callback();Controls.update();Manager.render(Scene, Camera);};loop();
}

这里传入参数动画渲染做了三件事,使用loopID作为整个VR应用的全局变量,记录每一帧动画的更新;更新相机控制器和VR渲染器,

WebVR场景切换

主要包括四个步骤

  1. 暂停渲染
  2. 清空当前场景物体
  3. 请求并加载目标场景脚本与资源
  4. 重启渲染

暂停动画渲染

function renderStop() {if (loopID !== -1) {window.cancelAnimationFrame(loopID);loopID = -1;}
}

回收当前场景

function clearScene() {for(let i = Scene.children.length - 1; i >= 0; i-- ) {Scene.remove(Scene.children[i]);}
}

按需加载

切换到下一场景,我们需要请求对应的场景脚本,这里使用webpack2的import函数进行代码分离,当然你也可以使用require.ensure(filename => {require(filename)})方法。

import(`page/${fileName}.js`);

最终将清空当前场景与请求加载目标场景功能封装为forward跳转方法,就可以在页面里直接调用了。

// common/VRCore.js
function forward(fileName) {renderStop();clearScene();import(`page/${fileName}.js`);
}
// page/index.js
...
class Index extends VRPage {start() {let geometry = new THREE.CubeGeometry(5,5,5);let material = new THREE.MeshBasicMaterial({ color: 0x00aadd});this.box = new THREE.Mesh(geometry,material);this.box.position.set(3,-2,-3);// add gaze eventLisenterthis.box.on('gaze',mesh => { // gazeIn triggerWebVR.forward('page2.js');});WebVR.Scene.add(box);}
}
...
// page2.js
class page2 extends VRPage {start() {this.addPanorama(1000, ASSET_TEXTURE_SKYBOX);}addPanorama(radius,path) {// create panoramalet geometry = new THREE.SphereGeometry(radius,50,50);let material = new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader().load(path),side:THREE.BackSide } );let panorama = new THREE.Mesh(geometry,material);WebVR.Scene.add(panorama);return panorama;}
}
export default (() => {return new page2();
})();

我们在场景里创建一个立方体,当凝视到该物体时,执行forward方法跳转至page2场景。

至此,我们的WebVR工程已经完成了一半,接下来,我们使用Webpack2来构建我们的工程。

webpack配置

开发环境和生产环境下webpack配置略有不同,这里主要给出webpack的基本配置,具体可参考项目地址。

const path = require('path');
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ProvidePlugin = require('webpack/lib/ProvidePlugin');module.exports = {entry: {'vendor': './src/common/js/vendor.js','app': './src/page/index.js'},output: {path: path.resolve(__dirname, '../dist/'),filename: '[name].js',sourceMapFilename: '[name].map',chunkFilename: '[id]-chunk.js',publicPath: '/'},

这里我们将webvr首个场景src/page/index.js作为项目打包入口,同时将page目录下的文件也作为单独chunk,配合按需加载来支持场景切换。

  module: {rules: [{test: /\.js/,exclude: /node_modules/,use: [{ loader:'babel-loader',options: { presets: ["latest",["es2015", {"modules": false}]] }]},{test: /\.css/,use: ['style-loader','css-loader']},{test: /\.(jpg|png|mp4|wav|ogg|obj|mtl|dae)$/,loader: 'file-loader'}]},

这里引入file-loader,这样就能在场景里直接import需要用到的素材,如下。

//page/page2.js
import ASSET_TEXTURE_SKYBOX from 'assets/texture/360_page2.jpg';

webpack相关的plugin配置如下

  plugins: [new CommonsChunkPlugin({name: ['app', 'vendor'],minChunks: Infinity}),new ProvidePlugin({'THREE': 'three','WebVR': path.resolve(__dirname,'../src/common/js/VRCore.js')}),new HtmlWebpackPlugin({inject: true,template: path.resolve(__dirname, '../src/index.html'),favicon: path.resolve(__dirname, '../src/favicon.ico')})]};

使用ProvidePlugin将three.js作为公用模块输出,以省去在每个脚本import THREE from 'three'的重复工作,同时将管理所有场景的核心模块VRCore.js作为全局公用模块输出。
使用HtmlWebpackPlugin将公用的html打包到dist目录下。

polyfill配置

最后是polyfill配置,我们需要引入webvr-polyfill和babel-polyfill来分别支持webvr API和ES6 API,并作为一个页面独立脚本。

// common/vendor.js
import 'babel-polyfill';
import 'webvr-polyfill';

以上WebVR工程已经基本搭建完毕,欢迎各位提出宝贵意见,后续我们将探索daydream和Oculus在webvr上的开发模式,敬请期待。

最后,献上前几天在google开发者网站上看到的:预测未来,不如创造未来。

转载于:https://my.oschina.net/u/3499139/blog/907142

VR进化论|教你搭建通用的WebVR工程相关推荐

  1. 手把手0基础项目实战(一)——教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)...

    本文你将学到什么? 本文将以原理+实战的方式,首先对"微服务"相关的概念进行知识点扫盲,然后开始手把手教你搭建这一整套的微服务系统. 项目完整源码下载 https://github ...

  2. 手机端创新体验——手把手教你搭建VRAR架构

    声明:本文阿里巴巴技术论坛整理文章,首发于CSDN,未经许可,禁止任何形式的转载. 作者:袁岳峰,阿里移动平台虚拟&互动实验室负责人,GM Lab技术负责人. 责编:钱曙光,关注架构和算法领域 ...

  3. 手把手0基础项目实战(一)——教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)......

    手把手0基础项目实战(一)--教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)... 原文: 手把手0基础项目实战(一)--教你搭建一套可自动化构 ...

  4. 0基础教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)

    2019独角兽企业重金招聘Python工程师标准>>> 本文你将学到什么? 本文将以原理+实战的方式,首先对"微服务"相关的概念进行知识点扫盲,然后开始手把手教你 ...

  5. 手把手教你搭建Linux开发环境(VMware+Ubuntu)(一)——安装VMware虚拟机和Ubuntu

    前言 近期好多小伙伴都开始学习Linux内核了,那么如何搭建一个Linux运行环境,变成Linux内核初学者的拦路虎,今天我就一步步详细解说一下,如何使用虚拟机VMware安装Ubuntu,跟我一起开 ...

  6. 手把手教你搭建 ELK 实时日志分析平台

    来自:武培轩 本篇文章主要是手把手教你搭建 ELK 实时日志分析平台,那么,ELK 到底是什么呢? ELK 是三个开源项目的首字母缩写,这三个项目分别是:Elasticsearch.Logstash ...

  7. OceanBase技术直播间开播啦!蚂蚁金服技术专家手把手教你搭建OB数据库~

    OceanBase技术直播间是OceanBase为用户和技术爱好者带来的系列技术直播课程,由蚂蚁金服一线技术专家分享最全面的理论知识和最实用的技术实践,内容包含数据库内核系列.手把手实操系列和最佳实践 ...

  8. 手把手教你搭建Linux开发环境(VMware+Ubuntu)(二)——安装VMwareTools并设置共享文件夹

    刚刚装好了Ubuntu,安装VMware Tools会让我们有更好的体验,那么为什么要安装VMware Tools?该如何安装呢?本篇博客将手把手教你安装VMware Tools,并设置共享文件夹. ...

  9. 手把手教你搭建Hadoop生态系统伪分布式集群

    Hello,我是 Alex 007,一个热爱计算机编程和硬件设计的小白,为啥是007呢?因为叫 Alex 的人太多了,再加上每天007的生活,Alex 007就诞生了. 手把手教你搭建Hadoop生态 ...

最新文章

  1. python数据库查询不出结果_记一次pymysql查询不到表中最新插入的数据的问题
  2. View及ViewGroup的事件分发及传递(二)
  3. linux date英文时间,date(时间),timedatectl(时区),cal(日历)的用法
  4. 设计模式(创建型)之原型模式
  5. cf1523B. Lord of the Values
  6. Java学习 第三章 数组(二)多维数组
  7. pip 更改源   pip加速
  8. CListCtrl控件的使用指南 (转)
  9. 23矩阵——LU分解、用LU 分解解线性方程组、LU分解的存在性和唯一性、对称矩阵的 L D L 分解、置换矩阵、PA=LU 分解
  10. JVM-深入虚拟机字节码执行引擎
  11. linux怎么创建swap分区,linux下创建swap分区
  12. Python的数据类型
  13. Java_多线程_模拟电影院售票
  14. 程序员涨工资大多数靠跳槽吗?
  15. oracle exclude table,EXPDP/IMPDP:关于EXCLUDE参数
  16. 不会聊天的程序员,如何开发聊天机器人
  17. win7右键 windows资源管理器已停止完美解决
  18. 计算机的顶会有哪些?
  19. xinxin - 初步学习tkinter
  20. 有n个结构体变量,内含学生学号、姓名、3门课程的成绩,要求输出平均成绩最高的学生信息

热门文章

  1. 传感器配件/胀差卡件A6210Emerson
  2. 美团2018校招笔试
  3. 不用找,你想要的中国风ppt模板素材都在这里
  4. Threes.js入门篇之5 - 场景操纵器Trackball
  5. java jdk 7 64位_jdk1.7 64位下载-jdk7 64位(Java SE Development Kit 7)下载 7u80 官方正式版-IT猫扑网...
  6. python perlin noise
  7. 选择大于努力?看涛思数据两名90后如何获得“胡润U30企业领袖奖”
  8. Oracle - 同义词
  9. 英语二-议论文写作词汇、话题、模板、范文参考
  10. python编写关不掉的流氓表白软件