WebVR開發教程——標準入門
WebVR即web + VR的體驗方式,本文介紹如何開發一個WebVR網頁,在此之前,我們有必要了解WebVR的體驗方式。
WebVR體驗模式
體驗WebVR的方式
WebVR的體驗方式可以分為VR模式和裸眼模式
VR模式
1.Mobile VR
如使用cardboard眼鏡來體驗手機瀏覽器的webVR網頁,瀏覽器將根據水平陀螺儀的參數來獲取用戶的頭部傾斜和轉動的朝向,並告知頁面需要渲染哪一個朝向的場景。
2.PC VR
通過佩戴Oculus Rift的分離式頭顯瀏覽連接在PC主機端的網頁,現支持WebVR API的瀏覽器主要是火狐的 Firefox Nightly和設置VR enabled的谷歌chrome beta。
裸眼模式
除了VR模式下的體驗方式,這裡還考慮了裸眼下的體驗瀏覽網頁的方式,在PC端如果探測的用戶選擇進入VR模式,應讓用戶可以使用滑鼠拖拽場景,而在智能手機上則應讓用戶可以使用touchmove或旋轉傾斜手機的方式來改變場景視角。
WebVR的概念大概就如此,這次我們將採用cardboard + mobile的方式來測試我們的WebVR場景,現在踏上我們的開發之旅。準備工作
測試工具:智能手機 + cardboard式頭顯 + chrome beta 60+(需開啟WebVR選項)
如果你練就了裸眼就能將手機雙屏畫面看成單屏的能力也可以省下頭顯。
技術和框架:three.js for WebGL
Three.js是構建3d場景的框架,它封裝了WebGL函數,簡化了創建場景的代碼成本,利用three.js我們可以更優雅地創建出三維場景和三維動畫,這裡我使用的是0.86版本。 如果想了解純WebGL開發WebVR應用以及WebVR具體環境配置,可以參考 webvr教程--深度剖析。
需要引入的js插件: 1.three.min.js 2.webvr-polyfill.js
webvr-polyfill.js
由於WebVR API還沒被各大主流瀏覽器支持,因此需要引入webvr-polyfill.js來支持WebVR網頁,它提供了大量VR相關的API,比如Navigator.getVRDisplay()獲取VR頭顯信息的方法。
3D場景構建
首先我們創建一個HTML文件
<!DOCTYPE html>n<html lang="en">n<head>n <meta charset="UTF-8">n <meta name="viewport" content="width_=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no">n <title>webVR-helloworld</title>n <style type="text/css">n * {nt margin: 0;nt padding: 0;n }n html,body {n height: 100%;n overflow: hidden;n }n </style>n</head>n<body>n</body>n<script src="./vendor/three.min.js"></script>n<script src="./vendor/webvr-polyfill.js"></script>n<script></script>n</html>n
接下來編寫js腳本,開始創建我們的3d場景。
1.創建場景
Three.js中的scene場景是繪製我們3d對象的整個容器
var scene = new THREE.Scene();n
2.添加相機
Three.js中的camera相機代表用戶的眼睛,我們通過設置FOV確定視野範圍,
//定義一個60°的視角,視線範圍在1到1000的透視相機nvar camera = new THREE. new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000);nscene.add(camera);n
3.添加渲染器
Three.js的渲染器用來渲染camera所看到的畫面
//初始化渲染器 antialias參數為ture表示開啟抗鋸齒策略nvar renderer = new THREE.WebGLRenderer({ antialias: true } );n//設置渲染器渲染尺寸nrenderer.setSize(window.innerWidth,window.innerHeight);n//設置渲染背景為白色nrenderer.setClearColor(0xeeeeee);n//將渲染場景的canvas放入body標籤里ndocument.body.appendChild(renderer.domElement);n
4.添加一個立方體網格
// 創建立方體nvar geometry = new THREE.CubeGeometry( 10,10,10);nvar material = new THREE.MeshLambertMaterial( { color: 0xef6500,needsUpdate: true,opacity:1,transparent:true} );nvar cube = new THREE.Mesh( geometry, material );ncube.position.set(0,100,-50);ncube.rotation.set(Math.PI/6,Math.PI/4,0);nscene.add(cube);n
5.啟動動畫
動畫渲染的原理:渲染器的持續調用繪製方法,方法里動態改變物體的屬性。 舊版的three.js需要手動調用requestAnimationFrame()方法遞歸的方式來渲染動畫,新版three.js已經封裝了該屬性,因此只需要通過渲染器renderer.animate(callback)。
function update() {n //讓立方體旋轉n cube.rotation.y += 0.01;n //渲染器渲染場景,等同於給相機按下快門n renderer.render(scene, camera);n}nrenderer.animate(update);//啟動動畫n
至此,我們已經繪製了一個簡單的3d場景並且讓它動了起來,接下來,我們需要讓我們的場景可以支持WebVR模式。
WebVR場景開發
使用navigator.getVRDisplays獲取vr設備實例vrdisplay,我們需要將它傳給當前運行的renderer渲染器,當點擊按鈕時可以進入VR模式,再次點擊退出VR模式。
function initVR(renderer) {n renderer.vr.enabled = true;n navigator.getVRDisplays().then( function(display) {n renderer.vr.setDevice(display[0]);n const button = document.querySelector(.vr-btn);n VRbutton(display[0],renderer,button,function() {n button.textContent = 退出VR;n },function() {n button.textContent = 進入VR;n });n }).catch(err => console.warn(err));n}n
這裡需要通過按鈕控制當前的渲染模式邏輯如下:
- 當點擊按鈕時,根據display.isPresenting判斷當前是否是使用vr設備下進行渲染,如果false,進入2,否則true進入3
- 當前非VR模式,點擊按鈕進入VR模式,此時調用display.requestPresent(),display.isPresenting被設置為true,觸發window的vrdisplaypresentchange事件
- 當前為VR模式,點擊按鈕退出模式,此時調用display.exitPresent(),display.isPresenting被設置為false,觸發window的vrdisplaypresentchange事件
/** VR按鈕控制n * @param {VRDisplay} display VRDisplay實例n * @param {THREE.WebGLRenderer} renderer 渲染器n * @param {HTMLElement} button VR控制按鈕n * @param {Function} enterVR 點擊進入VR模式時回調n * @param {Function} exitVR 點擊退出VR模式時回調n **/nfunction VRbutton(display,renderer,button,enterVR,exitVR) {n if ( display ) {n button.addEventListener(click, function() {n // 點擊vr按鈕控制`isPresenting`狀態n display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: renderer.domElement } ] );n });n window.addEventListener( vrdisplaypresentchange, function() {n // 是否處於vr體驗模式中,是則觸發enterVR,否則觸發exitVRn display.isPresenting ? enterVR() : exitVR();n }, false );n } else {n // 找不到vr設備實例,則移除按鈕n button.remove();n }n}n
我們可以在vrdisplaypresentchange事件中根據isPresenting的值來改變按鈕的UI,而three.js將根據isPresenting的值來決定是常規渲染還是vr模式渲染,在vr模式下,three.js將創建兩個camera進行渲染。
最後,將WebVR應用寫成ES6 class,按照下圖進行代碼規範:
第一步,構造函數先初始化VR場景、相機和渲染器;第二步,在渲染之前調用start方法,在start方法里我們為場景創建3d物體;最後,調起renderer.animate(this.update)開啟動畫渲染,update方法里我們可動態操作物體屬性,具體代碼如下:
class WebVRApp {n constructor() {n // 初始化場景n this.scene = new THREE.Scene();n // 初始化相機n this.camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,0.1,1000);n this.scene.add(this.camera);nn // 初始化渲染器n this.renderer = new THREE.WebGLRenderer({ antialias: true } );n this.renderer.setSize(window.innerWidth,window.innerHeight);n this.renderer.setClearColor(0x519EcB);n this.renderer.setPixelRatio(window.devicePixelRatio);n document.querySelector(.main-page).appendChild(this.renderer.domElement);nn this.clock = new THREE.Clock();n // VR初始化n this._initVR();n // 往場景添加3d物體n this.start();n // 窗口大小調整監聽n window.addEventListener( resize, this._resize.bind(this), false );n // 渲染動畫n this.renderer.animate(this.update.bind(this));n }n // 創建3d物體n start() {n const { scene, camera } = this;n // 創建光線、地面等n ...n // 創建立方體n const geometry = new THREE.CubeGeometry(2, 2, 2);n const material = new THREE.MeshLambertMaterial({ n color: 0xef6500,n });n this.cube = new THREE.Mesh( geometry, material );n this.cube.position.set({ x: 0, y: 0, z: -4 });n scene.add(this.cube);n }n // 動畫更新n update() {n const {scene,camera,renderer,clock} = this;n const delta = clock.getDelta() * 60;n // 啟動渲染n this.cube.rotation.y += 0.1 * delta;n renderer.render(scene, camera);n }n // VR模式初始化n _initVR() {n const { renderer } = this;n renderer.vr.enabled = true;n // 獲取VRDisplay實例n navigator.getVRDisplays().then( display => {n // 將display實例傳給renderer渲染器n renderer.vr.setDevice(display[0]);n const button = document.querySelector(.vr-btn);n VRButton.init(display[0],renderer,button,() => button.textContent = 退出VR,() => button.textContent = 進入VR);n }).catch(err => console.warn(err));n }n // 窗口調整監聽n _resize() {n const { camera, renderer } = this;n // 窗口調整重新調整渲染器n camera.aspect = window.innerWidth / window.innerHeight;n camera.updateProjectionMatrix();n renderer.setSize(window.innerWidth, window.innerHeight);n }n}nnew WebVRApp();n
完整代碼:github.com/YoneChen/WebVR-helloworld。
結語:目前,國外的谷歌、火狐、Facebook和國內百度已推出支持WebVR瀏覽器的版本,微軟也宣布將推出自己的VR瀏覽器,隨著後期5g網路極速時代的到來以及HMD頭顯的價格和平台的成熟,WebVR的體驗方式將是革命性的,用戶通過WebVR瀏覽網上商店,線上教學可進行「面對面」師生交流等,基於這種種應用場景,我們可以找到一個更好的動力去學習WebVR。
參考鏈接: responisve WebVR: 探討WebVR在不同頭顯(HMD)的適配方案 MolizaVR example: 火狐WebVR示例 webvr-boilerplate: A starting point for web-based VR experiences that work on all VR headsets. how to build webvr: How to Build VR on the Web Today
推薦閱讀:
※昨晚facebook F8開發者大會發布了React VR,並在github開源了,你怎麼看?
※Oculus VR為何會成為虛擬現實的最佳選擇呢?