1. 程式人生 > >ThreeJs 3D 全景項目開發總結

ThreeJs 3D 全景項目開發總結

遠的 拾取 而是 css3 blog 視角 好用 論壇 方法

本文來自網易雲社區

作者:唐釗


項目背景

那是在一個毫無征兆的下午,我還沈浸在 vue 的世界中,突然編輯跑過來說N的新官網想做一些3D全景的東西,一開始其實我的內心是拒絕的,一是沒怎麽實質性做過 WEBGL 的東西,只是組內 mini 項目的時候看了看基礎的內容,再者當時也很忙,感覺這東西聽起來就很復雜,隨著項目開發結束在此寫下這篇文章,記錄一下自己在開發過程中遇到的問題和解決的思路以供備忘。


準備工作

開發使用: WS、threejs-r82,3DsMax;

最初遇到的問題:其實3D 全景其實並不一定非要使用 webgl,css3同樣可以做到,但是考慮到後續要增加模型動畫的問題,所以不得不用 webgl 了。那麽 webgl 到底是什麽呢?WebGL是一種3D繪圖標準,這種繪圖技術標準允許把JavaScript和OpenGL ES 2.0結合在一起,通過增加OpenGL ES 2.0的一個JavaScript綁定,WebGL可以為HTML5 Canvas提供硬件3D加速渲染,這樣Web開發人員就可以借助系統顯卡來在瀏覽器裏更流暢地展示3D場景和模型了,還能創建復雜的導航和數據視覺化。由於webgl是基於OpenGL和JavaScript技術結合,而OpenGL與微軟DirectX存在著競爭關系,而且微軟自身也開發了Silverlight插件,與webgl其實是類似的,所以微軟對webgl技術並不支持。但是最新的 IE11和 edge 瀏覽器是 ok 的。所以一開始的難點就在於怎麽去構建這個3D的場景和內部的模型動畫等。(特此說明:本文不會講解 threejs 的基本知識,所以以下內容需要一定的 webgl 基礎,見下面鏈接)

threejs基礎知識詳解

先安利一款 chrome 的 threeJs 插件 https://chrome.google.com/webstore/detail/threejs-inspector/dnhjfclbfhcbcdfpjaeacomhbdfjbebi 賊好用!


開發中碰到的問題

  • 整個場景分為3大部分,最外層的天空,中間的建築,以及內部的各種燈籠,蝴蝶,魚等等模型動畫,所以我們需要分布考慮各個場景如何構建,首先是最外層的天空和建築,因為 N 項目組有特殊的場景編輯工具,可以非常方便的輸出場景的魚眼圖,所以我打算利用這個魚眼圖直接構建一個球形,也就是構建了2個球形,一內一外,分別為天空和建築,讓天空的球形做 圍繞 Y 軸的TWEEN動畫,形成天空在轉動的效果,同時內部的建築使用 png 貼圖,對材質增加 transparent:true 的選項,讓天空可見,如果你不加透明度這個選項,png 貼圖的透明部分是會變成白色的。

  • 外面兩層的球形模型很好搭建,接下來的問題就來了,如何做模型動畫,因為大家都從來沒做過,所以一開始我是一籌莫展,因為這個玩意壓根不知道從何下手,後面了解到模型動畫需要由專門的動畫師去建模然後貼圖並且制作動畫,導出相應的文件由前端放進場景裏面去,所以我就興致沖沖的讓遊戲那邊的動畫導出 dae 文件給我,為什麽導出 dae 呢,因為我看 threejs 的示例裏面是用的 dae 的模型,所以當時想當然的認為只要導出 dae 就能放進去了,事實證明,我還是 too young too simple. 為什麽,我看著官方的示例那天下午一遍一遍的問自己,為什麽我的就不行,難道我導出的模型就不是模型,於是我又是一頓查資料,那一刻,搜狗百度谷歌全上陣,可是依舊苦苦無果,打算去研究官方的 dae 文件,可以導入max發現全亂掉了,根本沒法下手,終於在第二天中午快要吃飯的時候在一個 max 論壇發現一個哥兒們的一段話讓我們恍然大悟,他的原話我記不清了,不過中心意思就一個:web 所用的 dae 文件需要模型全部塌陷以後重新撘骨骼,並且不能用鏡像骨骼,我那個去,敲代碼的我肯定不懂這是什麽意思啊,但是從這裏面肯定說明了直接導出的 dae 文件就是有問題,於是我去問了我們組的動畫師,她看了看說:“原來是這樣,那我試試吧”。於是我們的動畫師開始了各種嘗試,給了我各種文件進行導入,一開始模型是可以正常導入了,但是動畫總是不對,要麽骨骼信息各種丟失,要麽就是各種奇葩的抖動頻率,我們再一次被打擊了,後面再查文檔時發現 R7X 以上的動畫調用和 R6X 的發生了變化,於是我進行了一定的代碼更改,oh my god 終於在場景裏面看到了一個活的模型了,接著我們又開始研究貼圖和自發光問題。

  • 總的來說上面這一部分是當時最打擊信心以及最費時間的一部分了,因為吃螃蟹總是不容易的,不過後續發現還有很多其他的問題等著自己,首先是模型由於沒有燈光,顯得很暗淡,所以需要增加一個光源,由於場景裏面的背景是一張圖片,如果增加一個照射範圍很大的光源勢必會影響到圖片,會改變圖片的曝光,所以只能去研究模型的自發光,後來發現還是比較簡單,需要動畫師給我一個合適的色值,設置自身的 color 和 emissive 即可。

  • 場景中的花瓣采用的是粒子發射器生成的隨機粒子,添加花瓣的紋理,花瓣的降落由隨機數生成在一個合適的值。但是由於粒子本身是沒有 XYZ 的,所以沒法做旋轉。

  • 場景中的貼圖由於 webgl 的同源策略,所以不能在跨域的情況下使用貼圖。

  • 場景中的字體問題,在 threejs 中默認是不支持中文字體的,只能使用英文,原因嘛,你懂得,中文字符太多了,所以如果項目中需要在場景中使用中文,可以參考該文章 地址,另外如果不是非得使用最好還是用英文吧,因為這加載的都是流量啊。

  • 最後是場景內的鼠標事件,如果你沒有做過你一定會一臉懵逼,因為這裏面根本沒有什麽 click 事件,就比如一個鼠標移入到可點擊物體上變成手型都不知道怎麽搞,然後找資料,知道了ThreeJS提供了一個 raycaster的API用於返回用戶光標所在位置的所有3維元素,它的實現原理是在屏幕上某個二維坐標點與相機位置和視角形成的向量方向上投射一條射線,返回與射線相交的所有三維物體的集合,集合的第一個物體為距離相機最近的物體,最後一個則為離相機最遠的。當使用拾取器去獲取用戶點擊的物體時,需要事先將所有可參與用戶交互的三維物體放到一個集合裏。在創建拾取器後獲取兩個集合的交集,即當前用戶在屏幕點擊的位置上所有被設置為可被選擇的物體,第一個即可視為用戶直接點擊的物體。所以在場景內部的所有交互都只能通過射線的方式去完成,當然 github 上也有一些封裝的場景物體點擊的事件庫,其原理也是基於射線。但是由於上面提到的 png 貼圖問題,我讓動畫師將交互對象也做成了動畫模型,然後我就發現為什麽我的射線發射過去沒有交集了,一開始以為是我鼠標有問題,但是後來重現了幾次發現確實是動畫模型就不行,普通的 mesh 就 OK,那麽問題就肯定在動畫上面了,去 github 上找了很久看到了有人和我有同樣的問題。 傳送門,回答者說skinnedMesh 已經從射線集合中移除了,老版本曾經有支持,所以我只能想想其他的方法,最後采用了在動畫模型前面添加了一個普通的 mesh,將其透明掉,這樣射線就有了交集。能完美的點擊到了物體。


最後的話

至此整個場景內部的物件基本上交互的功能和動畫功能都 OK 了,但是還有很多之前研究的內容最後沒有放到整個項目中去,比如攝像機的移動旋轉,場景更濃厚的氣氛渲染,一是受限於web 瀏覽器,說實話 web 上搞3D 本來就不是太好,又卡消耗又大,而是確實時間也不長,前前後後所有的算滿也才26天,這其中還要花很多時間整合雙端的新聞發布系統,還要做其他的整合適配等等,所以後面空了還是要再看看 threeJs 的東西,增強一下自己的技術棧,同時更深入的理解 webgl。


網易雲免費體驗館,0成本體驗20+款雲產品!

更多網易研發、產品、運營經驗分享請訪問網易雲社區


相關文章:
【推薦】 Android 標題欄(1)
【推薦】 Android TV 開發 (1)
【推薦】 The Beam Model:Stream & Tables翻譯(上)

ThreeJs 3D 全景項目開發總結