近來風生水起的VR虛擬現實技術,抽空想起年初完成的“星球計划”項目,總結篇文章與各位分享一下制作基於Html5的3D全景漫游秘籍。
QQ物聯與深圳市天文台合作,在手Q“發現新設備”-“公共設備”里,連接QQ物聯攝像頭為用戶提供2016年天體大事件的直播,大家可以通過手Q實時觀看到世界各地最佳觀測點的日食,流星等天體現象。承載整個“星球計划”活動的運營頁面,經多方討論,我們決定嘗試3D全景漫游模式的H5運營頁進行推廣,今天就不詳述活動的具體內容,先和大家聊一聊這H5里“3D全景漫游”的制作方法。
先貼一個體驗地址(請忽略GIF錄屏的卡頓及字體,iOS開啟陀螺儀體驗最佳),Page3的宇宙部分-轉動手機在模擬的宇宙里搜尋各大行星,就是我們今天要說的基於Html5的3D全景漫游。
要制作全景漫游,首先得有全景圖像。全景圖像的獲取通常是借助魚眼的全景攝像機的拍攝來完成的,或者是單反相機、魚眼鏡頭、雲台和三角架的組合。需要按照一個方向旋轉360度拍攝一組照片,照片之間要有部分重合的部分,方便進行后期的拼接和融合。在拍好照片后需要將它們無縫拼接在一起,生成的全景圖像可分為球面全景圖、立方體全景圖以及柱狀全景圖等。(咋們騰訊地圖的街景體驗,就是最常見的全景漫游技術啦)
沒有全景攝像機,也可以通過一些素材站點拿到適合我們項目的全景圖。例如:某素材站點
當然,星球計划的背景圖是宇宙星際,相對而言是無序的,所以靠視覺設計師進行拼接繪制也是可以的。
而什么是全景漫游呢,全景漫游技術可以讓體驗者在全景圖像構建的全景空間里切換視角的瀏覽。它是通過拍攝全景圖像,再采用計算機圖形圖像技術構建出全景空間,讓使用者能用控制瀏覽的方向,或左或右、或上或下觀看物體或場景,仿佛身臨其境一般。與傳統的3D建模相比,全景漫游技術制作簡單,數據量小,系統消耗低,且更有真實感。故近年來,也是VR技術的一大熱門實現手法,用前面的貼圖例子來個demo。而在移動端的全景漫游,更是可以綁定陀螺儀,讓你更有身臨其境的感覺。
在項目初期,預研了一些全景漫游制作方案,包括目前最為常用的全景漫游制作工具是Pano2vr & Krpano,以及用Flash,QuickTime,基於Java,js等其他方式制作全景漫游,但據預研所了解的個方案優劣勢對比圖如下圖,結合“星球計划”項目的具體情況,最終優先選擇了Threejs的實現方案。
這里順便和大家聊聊目前最為常用的全景漫游制作工具是Pano2vr & Krpano。
(1)Pano2vr操作簡單功能雖少但非常實用,“導入全景圖-設置交互熱點-微調-導出”即可直接生產flash,html5,Quicktime等格式。
Pano2vr對於僅用在PC,iOS上的需求非常合適快捷,但對Android機的支持表現不佳。
(2)Krpano,功能強大完善,各平台兼容性高,拓展性很強,各類VR場景特效都可承載。但自成體系,需要遵循Krpano xml的這套編程語言,沒有gui的軟件界面,新手上手及后期維護成本較大,生成的全景漫游專業但對載入速度,內存占用都有影響。但對於想做高階的,個性化,定制化全景漫游項目,Krpano是不二選擇。
但這2個工具都需要購買授權碼才可商用,非免費。
(3)Three.js源自Github的一個開源項目,https://github.com/mrdoob/three.js,官網:http://threejs.org/ 。
看到一個同行的解釋,說理解成Three + js就可以了。Three表示3D的意思,js表示javascript的意思,故three.js就是使用javascript來寫3D程序的意思,格外的直白清晰啊。依靠javascript的語言編寫,自然給這個方案帶來了高拓展,高兼容,低開發成本,可高性能且免費的幾大優勢。
(4)Flash,QuickTime,基於Java,js等其他方式這里就不一一詳述,大致的優劣勢對比請參考上面的表格(具體評分僅供參考,軟件版本更新也許會有各方面的升級)。
想要利用Three.js制作一個物體渲染到網頁中去,需要構建這3個組建:場景(scene)、相機(camera)和渲染器(renderer):
(1)場景(scene)
即是畫布,是所有物體object的容器。在最開始的時候對場景實例化,將之后構建的物體都添加到場景中即可。
(2)相機(camera)
用戶是通過相機Camare來查看在scene下的3d場景,在three.js里包含了正交投影照相機(Orthographic Camera)和透視投影照相機(Perspective Camera)2種,從模擬人眼看物體的方式來選,透視投影照相機更適合。如下圖所示,fov是相機視角的夾角,aspect等於相機畫幅比例,near和far分別是照相機到視景體最近、最遠的距離,均為正值,且far應大於near。
(3)渲染器(renderer)
渲染器是用來設定渲染的結果會在頁面的什么元素上面呈現,以及按什么規則來渲染。
在Three.js中,場景是容器,把我們星球計划的星星們放置在構建的3D場景中的不同位置;相機對着下場景拍攝,拍攝結果通過渲染器實時的繪制在我們的瀏覽器上。
(4)構建宇宙並置入場景中
定義了這三大元素之后,下一步,就是構建我們的星球計划所需的宇宙了。前文有提到,全景圖像可分為球面全景圖、立方體全景圖以及柱狀全景圖。
雖然球面全景圖具有和人眼最接近的構建模式,但需要很多個立面才可以構建成一個球體,球面的經緯度坐標無法展開成一個平面貼圖,相對於其他方案,性能消耗過高,拼接方法過於繁瑣;而柱形全景圖的垂直視野小,不好做頂部底部的俯仰視角。我們選定了最常見的立方圖全景圖來構建我們的3D場景。
立方體全景圖有6個面,我們需要定義每個面貼圖的背景圖片,3D位置,旋轉角度(默認的6個面都是朝着我們的,我們需要定義朝坐標軸的各個方向做90度的旋轉,才可以搭建成一個立方體)。
然后添加到THREE.Object3D 的數組中,這樣我們就在場景中構建好了一個3D的宇宙空間。
這里,考慮到星空背景主要為了氛圍烘托,我們將6個面的貼圖減少成2個,以此縮減了資源文件的大小,如下圖所示。
(5)渲染
這里我們用的是Threejs的 實時渲染:就是需要不停的對畫面進行渲染,即使畫面中什么也沒有改變,也需要重新渲染。其中一個重要的函數是requestAnimationFrame,這個函數就是讓瀏覽器去執行一次參數中的函數,這樣通過上面animate中調用requestAnimationFrame()函數,requestAnimationFrame()函數又讓animate()再執行一次,就形成了我們通常所說的渲染循環 了。
通過上面這些步驟,我們就構建好這個3D的宇宙空間了。
(6)構建星球放置在宇宙中
一期的星球計划中,需要增加8顆星球,為了避免畫面過於擁擠,星球們被分散定位在了6個面上。之前我們定義宇宙六個面的時候給了每個面一個固定的section id,通過簡單的js 我們可以往平面中加入星球的DOM結構。
因此也可以很輕松的利用CSS給這些星球定位及增加個性的動畫效果,這里要特別注意,不要增加陰影等耗內存特別大的動畫效果,它們是Crash罪魁禍首。
‘
(7)綁定陀螺儀
最后一步,將全景漫游綁定陀螺儀,這里涉及到需要對陀螺儀事件做個保護代碼,判斷機器是否支持陀螺儀。完成以上幾步,既可以實現一個在移動端的全景漫游啦。
(8)其他
在項目完成的初期,對部分安卓機的內存消耗還是過大,為此在完成項目之后繼續嘗試了一些優化工作,包括 縮減宇宙的尺寸,合並全景貼圖,禁用陀螺儀,預加載和懶加載,星球CSS3動畫縮減,資源文件深度壓縮等工作,但還是無法避免在內存不足的安卓機下存在Crash的風險,為保證項目的穩定上線,退而求其次對安卓機做了兼容版的體驗,預期在后續的項目迭代中再優化頁面在安卓下的表現,實現全平台的體驗統一。
最后,僅以此文總結在移動端構建3D全景漫游的試水總結,該嘗試基本上能夠滿足項目的需求,但在性能優化,細節完善上還繼續打磨,希望能對有興趣的小伙伴帶來一些幫助^^。