淺談 WebVR 全景
前言
近年來VR概念越來越火,相信大家在網(wǎng)上都有過VR的瀏覽體驗,比如VR全景看房[1]、VR全景看車[2]、VR全景旅游[3]等等,VR全景給了我們視覺上的沉浸式體驗。本文將會簡單探究Web VR全景的實現(xiàn)原理,同時也會用threejs實現(xiàn)兩個小的demo,希望對大家以后在業(yè)務上遇到類似的場景能有所幫助。
什么是VR
引用維基百科的定義:
虛擬現(xiàn)實(英語:virtual reality,縮寫VR),是利用電腦模擬產(chǎn)生一個三維空間的虛擬世界,提供用戶關于視覺等感官的模擬,讓用戶感覺仿佛身歷其境,可以即時、沒有限制地觀察三維空間內(nèi)的事物。用戶進行位置移動時,電腦可以立即進行復雜的運算,將精確的三維世界影像傳回產(chǎn)生臨場感。
與基于現(xiàn)實場景進行增強效果的 AR(Augmented Reality)的區(qū)別在于,VR 的場景需要完全重建,類似于進入另一個世界。
虛擬現(xiàn)實的實現(xiàn)原理
人眼對世界的感知,是通過將三維世界投射至視網(wǎng)膜上,以二維圖像建立的視覺體系。所以一張具備透視關系的圖像,在特定的角度,可以使人感受到三維的空間關系,這就是人眼的深度知覺(depth perception)。VR 技術則建立在這個基礎之上。
廣泛意義上來說,只要符合模擬三維空間這一行為,就可以稱為 VR,手機、電腦、大熒幕、VR 眼鏡甚至于空氣,都可以成為 VR 的載體。
如何在web上模擬三維空間
三維空間是由2D和3D圖形構成的,要模擬三維空間,必須繪制2D和3D圖形,我們寫js有ECMAScript規(guī)范,同理的繪制2D和3D圖形也有一套規(guī)范,這套規(guī)范就是OpenGL
?OpenGL是什么?
OpenGL(英語:Open Graphics Library,譯名:開放圖形庫或者“開放式圖形庫”)是用于渲染2D、3D矢量圖形的跨語言、跨平臺的應用程序編程接口(API)。
OpenGL規(guī)范描述了繪制2D和3D圖形的抽象API,常用于CAD、虛擬現(xiàn)實、科學可視化程序和電子游戲開發(fā)。
?在Web上能用OpenGL嗎?
可以的,在web上可以使用WebGL,它是Web瀏覽器中OpenGL的JavaScript綁定。
?什么是WebGL?
WebGL是一種JavaScript API,用于在不使用外掛程式的情況下在任何相容的網(wǎng)頁瀏覽器中呈現(xiàn)交互式2D和3D圖形。WebGL完全整合到瀏覽器的所有網(wǎng)頁標準中,可將影像處理和效果的GPU加速使用方式當做網(wǎng)頁Canvas的一部分。WebGL元素可以加入其他HTML元素之中并與網(wǎng)頁或網(wǎng)頁背景的其他部分混合。
有了WebGL API,我們就可以web網(wǎng)頁上構建三維空間啦。我們可以借助canvas標簽來獲取WebGL實例來進行WebGL API的調用,更多API可以戳WebGL: 2D and 3D graphics for the web - Web APIs | MDN[4]查看,下面是使用示例:
目前業(yè)界有很多成熟的WebGL3D引擎,比如three.js[5]、babylon.js[6]等等,這些3D引擎已經(jīng)對WebGL API做了非常高效的封裝,可以幫助我們快速繪制2D和3D圖形。
three.js實現(xiàn)vr全景
在實戰(zhàn)前先了解下three.js的基本概念
?基本概念?
在three.js中,渲染一個三維空間的必要因素是場景(scene)、攝像機(camera)、渲染器(renderer)。渲染出一個三維空間后,可以往里面增加各種各樣的物體、光源等等。
場景(scene)
一個容器,容納著除渲染器以外的3d世界里的一切。場景的元素采用右手坐標系,x軸正方向向右,y軸正方向向上,z軸由屏幕從里向外。
攝像機(camera)
就像人的眼睛,在一個空間里可以看向任意方向,可以通過參數(shù)調節(jié)可視角度和可視距離。
three.js中常用的camera有兩種,透視投影相機(PerspectiveCamera)與正交投影相機(OrthographicCamera)。這里的投影是指將三維空間中的物體坐標投影到二維平面上。
- 透視 投影是將每個點都投影到三維空間中,近大遠小,看起來更符合真實世界看到的物體。
- 正交 投影是只考慮所有點的XY坐標,每一個二維空間中的點都是與Z軸平行的直線在觀察平面上的投影。所看到的物體大小不會受到距離遠近的影響。
透視相機(PerspectiveCamera)
使用perspective projection(透視投影)來進行投影。
這一投影模式被用來模擬人眼所看到的景象,它是3D場景的渲染中使用得最普遍的投影模式。
PerspectiveCamera(fov, aspect, near, far) 有四個參數(shù):
- fov - field of view,視野角,下圖中綠色英文標注的地方,是距離觀測點near長度處,最上端與最下端之間的角度,F(xiàn)ov越大,表示眼睛睜得越大,離得越遠,看得更多。
- aspect - 畫面橫寬比
- near - 相機最近范圍內(nèi)可以看到的物體的距離
- far - 相機最遠范圍內(nèi)可以看到的物體的距離
正交相機(OrthographicCamera)
這一攝像機使用orthographic projection(正交投影)來進行投影。
在這種投影模式下,無論物體距離相機距離遠或者近,在最終渲染的圖片中物體的大小都保持不變。這對于渲染2D場景或者UI元素是非常有用的。
OrthographicCamera(left, right, top, bottom, near, far)有六個參數(shù)
left, right, top, bottom - 分別是紅色點距離左右上下邊框的距離,對應圖中XY軸的值;
near - 場景開始渲染并可以顯示的起點,對應圖中Z軸坐標的值,通常為負;
far - 場景結束渲染的終點,對應圖中Z軸坐標的值,通常為正;
渲染器(renderer)?
將camera在scene里看到的內(nèi)容渲染/繪制到畫布上
設置好 dpr、畫布寬高,Three.js 就會生成一個 canvas。
幾何體(geometry)
三維空間里的所有物體都是點組成面,面組成幾何體。
three.js核心中內(nèi)置了多種幾何體,如下圖的幾何體從左到右分別為:球緩沖幾何體(SphereGeometry)?、 圓柱緩沖幾何體(CylinderGeometry)、立方緩沖幾何體(BoxGeometry)、圓錐緩沖幾何體(ConeGeometry)?、 圓環(huán)(TorusGeometry)和圓環(huán)緩沖扭結幾何體(TorusKnotGeometry)等等
貼圖(texture)
想象一下你手里有一個幾何體,你用一張A4紙包裹上幾何體,并在上面畫畫。你畫的內(nèi)容就是貼圖。
下面給立方體貼上小黃鴨貼圖:
也可以給立方體貼上視頻
材質(material)
延續(xù)貼圖里的想象,你用白卡紙畫畫,還是用油紙畫畫,呈現(xiàn)出來的質感是不同的,這就是材質!
下面五個圓環(huán)扭結的顏色都是一樣的,而材質從左至右分別是:
- MeshBasicMaterial(基礎材質,簡單的幾何材料,不考慮光照的影響)
- MeshMatcapMaterial(網(wǎng)帽材質,在場景沒有光源的情況下,會模擬出物體被光照的效果)
- MeshPhongMaterial(高光材質,適用于陶瓷,烤漆類質感)
- MeshToonMaterial(卡通材質)
- MeshLambertMaterial (非光澤表面的材質,沒有鏡面高光,可以很好地模擬一些表面,例如未經(jīng)處理的木材或石材,但不能模擬具有鏡面高光的光澤表面,例如涂漆木材。)
環(huán)境光的情況下:
有從上往下的平行光:
燈光(light)
在沒有手動創(chuàng)建光的情況下會默認有個環(huán)境光,不然你什么都看不到。
常見的燈光有以下幾種類型:
AmbientLight:環(huán)境光,沒有方向,會均勻的照亮場景中的所有物體,不會產(chǎn)生陰影
DirectionalLight:平行光,常常用平行光來模擬太陽光 的效果; 太陽足夠遠,因此我們可以認為太陽的位置是無限遠,所以我們認為從太陽發(fā)出的光線也都是平行的。
PointLight:點光源,從一個點向各個方向發(fā)射的光源??梢阅M一個燈泡發(fā)出的光。
SpotLight?:聚光燈,光線從一個點沿一個方向射出,隨著光線照射的變遠,光線圓錐體的尺寸也逐漸增大。
?VR全景看房的實現(xiàn)?
原理
我們可以通過模擬人走在房子里的行為來實現(xiàn):
- 用攝像機模擬人,鏡頭相當于人的眼睛
- 用立方幾何體六個面貼上貼圖模擬房子,貼圖要求真實還原房子六個面的情況
- 將攝像機放置在幾何體里面,移動攝像機相當于人在房子里走動
素材準備
房子六面貼圖:
代碼實現(xiàn)
1.創(chuàng)建場景和攝像機,并且設置攝像機位置和添加加軌道控制器
2.創(chuàng)建立方幾何體,并且給幾何體貼上準備好的貼圖
頁面效果:
3.將攝像頭的位置移動到幾何體內(nèi)部
將攝像機移動到幾何體內(nèi)部后發(fā)現(xiàn)視野一片黑暗,這是因為貼圖是在幾何體外表面,所以需要將貼圖翻轉至內(nèi)表面。
4.將幾何體貼圖翻轉至內(nèi)表面,就能看到全景啦
5.監(jiān)聽鍵盤事件移動攝像機
最終效果
?VR全景看車的實現(xiàn)?
原理
VR全景看車的難點是汽車模型的設計,需要設計一個3d汽車模型,然后渲染到頁面上。汽車換裝則是通過對關鍵節(jié)點的操作來完成。
另外我們一般說的3d模型就是一個或多個幾何體,只是有的3d模型文件里除了包含幾何體還可以包含一些額外的信息,比如貼圖,材質等等需要在讀取模型文件時解析出來
3d模型的文件格式有很多,但threejs里常用的基本是:
- OBJ格式:老牌通用3d模型文件,不包含貼圖,材質,動畫等信息。
- GLTF格式(圖形語言傳輸格式):由OpenGL官方維護團隊推出的現(xiàn)代3d模型通用格式,可以包含幾何體、材質、動畫及場景、攝影機等信息,并且文件量還小。有3D模型界的JPEG之稱。GLTF格式有.gltf(JSON/ASCII)和.glb(二進制)兩種拓展名。
素材準備
官網(wǎng)上找了一個汽車模型,可以用PlayCanvas glTF Viewer[7]查看汽車模型的節(jié)點信息。
代碼實現(xiàn)
1.創(chuàng)建場景和攝像機,并且設置攝像機位置和添加加軌道控制器
2.加載汽車模型
通過GLTFLoader,我們可以加載一個gltf?格式的3d模型文件。需要注意的是,這些Loader都以插件的形式存在,需要引入相應的XXXLoader.js才能使用
3.車輪滾動
4.提供拾色器,改變車身(body)、細節(jié)(detail)和玻璃(glass)的顏色
最終效果
總結一下
以上只是本人對web VR全景的一個粗淺的探究,希望能夠引起你們對web VR的興趣。threejs(或其他3d引擎)能做的東西遠不止于此,還有非常多炫酷、好玩的3d場景,感興趣的可以私下探索哦!
參考資料
[1]VR全景看房: https://bj.ke.com/
[2]VR全景看車: https://car.autohome.com.cn/vr/list-0-0-0-1.html
[3]VR全景旅游: http://www.quanjingke.com/
[4]WebGL: 2D and 3D graphics for the web - Web APIs | MDN: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API
[5]three.js: https://github.com/mrdoob/three.js/
[6]babylon.js: https://github.com/BabylonJS/Babylon.js
[7]PlayCanvas glTF Viewer: https://playcanvas.com/viewer
[8]three.js docs: https://threejs.org/docs/index.html#manual/zh/introduction/Creating-a-scene
[9]three.js中兩種常用的攝像機模式: https://segmentfault.com/a/1190000013145246
[10]Three 之 three.js (webgl)涉及的各種材質簡單說明(常用材質配有效果圖)_仙魁XAN的博客-CSDN博客_threejs材質和紋理: https://blog.csdn.net/u014361280/article/details/124416631
[11]Threejs 實現(xiàn)簡單的全景圖: https://fangsueluo.github.io/2021/01/12/vr-threejs-learning/
[12]三種前端實現(xiàn)VR全景看房的方案!說不定哪天就用得上! - 掘金: https://juejin.cn/post/6973865268426571784
[13]一步步帶你實現(xiàn)web全景看房--three.js - 掘金: https://juejin.cn/post/6844903918409875469
[14]硬核看房利器——Web 全景的實現(xiàn): https://segmentfault.com/a/1190000024476102
[15]2天賺了4個W,手把手教你用Threejs搭建一個Web3D汽車展廳! - 掘金: https://juejin.cn/post/6981249521258856456
[16]WebGL坐標系介紹_桑榆未晚_的博客-CSDN博客_webgl坐標系: https://blog.csdn.net/TW934440653/article/details/102529017?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-102529017-blog-70878160.pc_relevant_multi_platform_whitelistv4&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-102529017-blog-70878160.pc_relevant_multi_platform_whitelistv4&utm_relevant_index=2
- EN?