在開始談 WebVR 前,我們先來看看人眼中的三維立體是如何產(chǎn)生的。
外部世界是三維立體的,但是它在我們的視網(wǎng)膜上留下的投影卻是二維的。因為大腦會自動利用視覺信息中的各種深度知覺的線索,“重建”出立體的感知。人眼立體視覺的原理基本是依靠深度知覺+雙眼視差。
WebVR API 目前還停留在草案階段,僅能在安裝了 Firefox nightly 的 Oculus Rift、Chrome 的實驗性版本和 Samsung Gear VR 的瀏覽器上使用。除了使用原生 API 開發(fā)外,目前還可以使用 Mozilla 開發(fā)的 A-Frame 框架和 Three.js。本文主要描述的是使用 Three.js 的移動瀏覽器WebVR體驗。
Three.js是一個3D JavaScript 庫。封裝了底層的圖形接口,除了 WebGL 之外,Three.js 還提供了基于 Canvas、SVG 標簽的渲染器。2016年天貓雙十一宇宙邀請函中酷炫的“一鏡到底”就是用的 Three.js 實現(xiàn)的。
創(chuàng)建 Three.js
創(chuàng)建一個 Three.js 的項目,至少包括:
1)渲染器(Renderer)
渲染器決定了渲染的結(jié)果應(yīng)該顯示在頁面的什么元素上,并以怎樣的方式繪制。
以 Canvas 為例,可以綁定渲染器,也可以動態(tài)創(chuàng)建渲染器。
2)場景(Scene)
場景只有一種,是所有物體的容器。
3)相機(Camera)
WebGL 和 Three.js 使用的三維坐標軸遵循“右手坐標系”。使用 Three.js 創(chuàng)建的場景是三維的,而通常情況下顯示屏是二維的。相機它定義了三維空間到二維屏幕的投影方式。針對投影方式的不同,相機又分為正交投影(OrthographicCamera)與透視投影(PerspectiveCamera)。
正交投影,六個參數(shù)分別對應(yīng)x、y,z軸的最小最大值。它創(chuàng)建一個正射投影矩陣。為了保持相機的橫豎比例,需要保證(right - left)與(top - bottom)的比例與 Canvas 寬度與高度的比例一致。
透視投影,四個參數(shù)分別是視野在 y-z 平面的角度、投影平面寬高比、近平面(沿Z負軸)的距離,遠平面(沿Z負軸)的距離。它創(chuàng)建一個對稱的透視投影矩陣。
此外項目中加入光源(Light)與陰影(Shadow)會讓場景的渲染效果更加豐富逼真。
我們以 Three.js 官方 examples 中的 WebVR 360° 全景圖為例,看看一個完整的 WebVR 項目還依賴哪些 js。
其他 VR 插件
除了引入 Three.js 外,還引入了:
1)VRControls.js
移動瀏覽器上一般會使用 deviceorientation 事件來檢測設(shè)備的朝向,WebVR API 可以幫助我們更好的控制設(shè)備。使用 VRControls.js,能在 requestAnimationFrame 中不斷的獲取HMD狀態(tài)信息并應(yīng)用到相機(Camera)上。
2)VREffect.js
VREffect.js 會通過 getEyeParameters 獲取左眼所視信息,通過獲取的可視角度和瞳距用透視投影(PerspectiveCamera)把屏幕 render 為左右兩個屏幕,分別對應(yīng)左右眼,利用深度知覺+兩眼視差,讓大腦“重建”出立體場景。
3)WebVR.js
WebVR.js 主要提供 WebVR 環(huán)境檢測,在不兼容 WebVR 體驗下的內(nèi)容提示,以及顯示按鈕用來“進入”/“退出” WebVR 體驗?zāi)J健?/p>
編寫全景圖項目
引用完 Three.js 和3個 VR 插件后,就可以開始編寫全景圖項目主要代碼了。
首先需要判斷設(shè)備是否支持 WebVR,不支持就需要在屏幕上提醒用戶。
開始創(chuàng)建渲染器、場景和相機。
接著就是制作360°全景場景,一般可分為球面全景圖方式、柱狀全景圖方式和立方體全景圖方式。
球面全景圖雖然具有和人眼最接近的構(gòu)建模式。但實際制作球面貼圖時,因為上下兩個頂點處匯集了所有的經(jīng)線,需要很多立面拼接成一個球體,過于繁瑣并且瀏覽器性能消耗過高。
柱形全景圖的垂直視野小,不好做頂部底部的俯仰視角。貼圖在側(cè)面雖然最簡單,但頭頂和腳底是無法觀察的區(qū)域。
立方體型全景圖是由前,后,左,右,上,下6張圖片拼接而成。相機位于立方體的中心,也是360°全視角。
貼圖相對球形更簡單,但是因為是矩形關(guān)系,在8個頂點處會有畸變。
在 Three.js 官方示例中,使用的就是立方體全景圖。然后再用 Canvas 把全景圖片源文件轉(zhuǎn)化為所需數(shù)量的貼圖面,并用 THREE.Texture 創(chuàng)建紋理貼圖對象保存。
因為 VREffect.js 會渲染左右2個屏幕,左相機對應(yīng) layers=1 的 skyBox,所以還需要創(chuàng)建一份右相對應(yīng) layers=2的skyBoxR。
然后加入 VRControls、VREffect 和按鈕。
最后監(jiān)測一下 window 窗口的大小變化,resize 的時候調(diào)整相機角度、更新投影矩陣,調(diào)整 WebVR effect 渲染大小。在 requestAnimationFrame 中不斷監(jiān)測設(shè)備狀態(tài)并更新到 Camera 和 WebVR 渲染上。剩下的就是帶上 VR HMD 設(shè)備查看全景圖。
注:
部分圖片來自網(wǎng)絡(luò)
更多 Three.js 和 Web VR 內(nèi)容,請移步 https://threejs.org和 https://w3c.github.io/webvr
本文作者:陳自然(點融黑幫),高級前端開發(fā),現(xiàn)就職于點融網(wǎng)技術(shù)部 Clients 團隊。