WebVR即web + VR的體驗方式,本文介紹如何開發一個WebVR網頁,在此以前,咱們有必要了解WebVR的體驗方式。css
體驗WebVR的方式html
WebVR的體驗方式能夠分爲VR模式和裸眼模式git
VR模式github
1.Mobile VRweb
如使用cardboard眼鏡來體驗手機瀏覽器的webVR網頁,瀏覽器將根據水平陀螺儀的參數來獲取用戶的頭部傾斜和轉動的朝向,並告知頁面須要渲染哪個朝向的場景。chrome
2.PC VRcanvas
經過佩戴Oculus Rift的分離式頭顯瀏覽鏈接在PC主機端的網頁,現支持WebVR API的瀏覽器主要是火狐的 Firefox Nightly和設置VR enabled的谷歌chrome beta。瀏覽器
裸眼模式網絡
除了VR模式下的體驗方式,這裏還考慮了裸眼下的體驗瀏覽網頁的方式,在PC端若是探測的用戶選擇進入VR模式,應讓用戶可使用鼠標拖拽場景,而在智能手機上則應讓用戶可使用touchmove或旋轉傾斜手機的方式來改變場景視角。
WebVR的概念大概就如此,此次咱們將採用cardboard + mobile的方式來測試咱們的WebVR場景,如今踏上咱們的開發之旅。app
測試工具:智能手機 + 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 API還沒被各大主流瀏覽器支持,所以須要引入webvr-polyfill.js來支持WebVR網頁,它提供了大量VR相關的API,好比Navigator.getVRDisplay()獲取VR頭顯信息的方法。
首先咱們建立一個HTML文件
<!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-helloworld</title> <style type="text/css"> * { margin: 0; padding: 0; } html,body { height: 100%; overflow: hidden; } </style> </head> <body> </body> <script src="./vendor/three.min.js"></script> <script src="./vendor/webvr-polyfill.js"></script> <script></script> </html>
接下來編寫js腳本,開始建立咱們的3d場景。
Three.js中的scene場景是繪製咱們3d對象的整個容器
var scene = new THREE.Scene();
Three.js中的camera相機表明用戶的眼睛,咱們經過設置FOV肯定視野範圍,
//定義一個60°的視角,視線範圍在1到1000的透視相機 var camera = new THREE. new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,1,1000); scene.add(camera);
Three.js的渲染器用來渲染camera所看到的畫面
//初始化渲染器 antialias參數爲ture表示開啓抗鋸齒策略 var renderer = new THREE.WebGLRenderer({ antialias: true } ); //設置渲染器渲染尺寸 renderer.setSize(window.innerWidth,window.innerHeight); //設置渲染背景爲白色 renderer.setClearColor(0xeeeeee); //將渲染場景的canvas放入body標籤裏 document.body.appendChild(renderer.domElement);
// 建立立方體 var geometry = new THREE.CubeGeometry( 10,10,10); var material = new THREE.MeshLambertMaterial( { color: 0xef6500,needsUpdate: true,opacity:1,transparent:true} ); var cube = new THREE.Mesh( geometry, material ); cube.position.set(0,100,-50); cube.rotation.set(Math.PI/6,Math.PI/4,0); scene.add(cube);
動畫渲染的原理:渲染器的持續調用繪製方法,方法裏動態改變物體的屬性。 舊版的three.js須要手動調用requestAnimationFrame()方法遞歸的方式來渲染動畫,新版three.js已經封裝了該屬性,所以只須要經過渲染器renderer.animate(callback)。
function update() { //讓立方體旋轉 cube.rotation.y += 0.01; //渲染器渲染場景,等同於給相機按下快門 renderer.render(scene, camera); } renderer.animate(update);//啓動動畫
至此,咱們已經繪製了一個簡單的3d場景而且讓它動了起來,接下來,咱們須要讓咱們的場景能夠支持WebVR模式。
使用navigator.getVRDisplays獲取vr設備實例vrdisplay,咱們須要將它傳給當前運行的renderer渲染器,當點擊按鈕時能夠進入VR模式,再次點擊退出VR模式。
function initVR(renderer) { renderer.vr.enabled = true; navigator.getVRDisplays().then( function(display) { renderer.vr.setDevice(display[0]); const button = document.querySelector('.vr-btn'); VRbutton(display[0],renderer,button,function() { button.textContent = '退出VR'; },function() { button.textContent = '進入VR'; }); }).catch(err => console.warn(err)); }
這裏須要經過按鈕控制當前的渲染模式邏輯以下:
/** VR按鈕控制 * @param {VRDisplay} display VRDisplay實例 * @param {THREE.WebGLRenderer} renderer 渲染器 * @param {HTMLElement} button VR控制按鈕 * @param {Function} enterVR 點擊進入VR模式時回調 * @param {Function} exitVR 點擊退出VR模式時回調 **/ function VRbutton(display,renderer,button,enterVR,exitVR) { if ( display ) { button.addEventListener('click', function() { // 點擊vr按鈕控制`isPresenting`狀態 display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: renderer.domElement } ] ); }); window.addEventListener( 'vrdisplaypresentchange', function() { // 是否處於vr體驗模式中,是則觸發enterVR,不然觸發exitVR display.isPresenting ? enterVR() : exitVR(); }, false ); } else { // 找不到vr設備實例,則移除按鈕 button.remove(); } }
咱們能夠在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 { constructor() { // 初始化場景 this.scene = new THREE.Scene(); // 初始化相機 this.camera = new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,0.1,1000); this.scene.add(this.camera); // 初始化渲染器 this.renderer = new THREE.WebGLRenderer({ antialias: true } ); this.renderer.setSize(window.innerWidth,window.innerHeight); this.renderer.setClearColor(0x519EcB); this.renderer.setPixelRatio(window.devicePixelRatio); document.body.appendChild(this.renderer.domElement); this.clock = new THREE.Clock(); // VR初始化 this.initVR(); // 往場景添加3d物體 this.start(); // 窗口大小調整監聽 window.addEventListener( 'resize', this.resize.bind(this), false ); // 渲染動畫 this.renderer.animate(this.update.bind(this)); } // 建立3d物體 start() { const {scene,camera} = this; // 建立光線 scene.add(new THREE.AmbientLight(0xFFFFFF)); // 建立地面 scene.add(this.createGround(1000,1000)); // 建立立方體 this.cube = this.createCube(2,2,2, 2,-1,-3); } // VR模式初始化 initVR() { const {renderer} = this; renderer.vr.enabled = true; // 獲取VRDisplay實例 navigator.getVRDisplays().then( display => { // 將display實例傳給renderer渲染器 renderer.vr.setDevice(display[0]); const button = document.querySelector('.vr-btn'); VRButton.init(display[0],renderer,button,() => button.textContent = '退出VR',() => button.textContent = '進入VR'); }).catch(err => console.warn(err)); } // 窗口調整監聽 resize() { const {camera,renderer} = this; // 窗口調整從新調整渲染器 camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } createCube(width=2,height=2,depth=2, posX,posY,posZ) { // 建立立方體 const geometry = new THREE.CubeGeometry(width,height,depth); const material = new THREE.MeshLambertMaterial({ color: 0xef6500 }); const cube = new THREE.Mesh( geometry, material ); cube.position.set({ x: posX, y: posY, z: posZ }); cube.castShadow = true; return cube; } createGround(width,height) { // 建立地平面 const geometry = new THREE.PlaneBufferGeometry( width, height ); coshPhongMaterial( { color: 0xaaaaaa } ); const ground = new THREE.Mesh( geometry, material ); ground.rotation.x = - Math.PI / 2; ground.position.y = -10; ground.receiveShadow = true; return ground; } // 動畫更新 update() { const {scene,camera,renderer,clock} = this; const delta = clock.getDelta() * 60; // 啓動渲染 this.cube.rotation.y += 0.1 * delta; renderer.render(scene, camera); } } new WebVRApp();
完整代碼:github.com/YoneChen/WebVR-helloworld。
結語:目前,國外的谷歌、火狐、Facebook和國內百度已推出支持WebVR瀏覽器的版本,微軟也宣佈將推出本身的VR瀏覽器,隨着後期5g網絡極速時代的到來以及HMD頭顯的價格和平臺的成熟,WebVR的體驗方式將是革命性的,用戶經過WebVR瀏覽網上商店,線上教學可進行「面對面」師生交流等,基於這種種應用場景,咱們能夠找到一個更好的動力去學習WebVR。