three.js實現數字孿生3D倉庫一期(開源)

大家好,本文使用three.js實現了3D倉庫一期項目,給出了代碼,分析了關鍵點,感謝大家~

關鍵詞:數字孿生、three.js、Web3D、WebGL、智慧倉庫、開源

代碼:Github

我正在承接Web3D數字孿生項目,具體介紹可看承接各種Web3D業務

加QQ羣交流:106047770

需求描述

客戶想要把兩個倉庫3D化,方便可視化地查看倉庫的內容。未來可以進行搜索之類的操作

需要在PC端、平板、安卓手機、蘋果手機的瀏覽器上運行

實際場景如下圖所示:
倉庫1有兩排櫃子:
image
image

第一排的櫃子都是一樣的,其中每個櫃子有80個一樣的抽屜:
image

第二排的每個櫃子也是一樣的,並且不需要顯示櫃子中的畫

倉庫2有一排櫃子,每個櫃子都是一樣的:
image

一期的需求如下:

  • 1比1地還原場景
  • 點擊櫃子的抽屜,可彈出抽屜,並顯示綁定的數據

最終實現效果演示:

image

下面開始實現各個關鍵點,給出實現的思路:

建模

我們首先拿着捲尺、激光測距儀,到現場去測量,得到實際場景中的櫃子大小、抽屜大小、間隙、倉庫大小、櫃子在倉庫的位置等數據,我們要根據這些數據來1比1建模

現在對倉庫1建模,首先要創建倉庫:
通過拼接多個立方體(BoxGeometry)來創建牆、門;
通過PlaneGeometry來創建地面,設定它的材質的map來貼上瓷磚。值得注意的是瓷磚的大小要與實際場景一致,這是通過設置map的repeat來實現。瓷磚紋理可以從這裏獲得

建模後的倉庫如下圖所示:
image

倉庫由牆、地面、門組成

接着,我們對第一排的一個櫃子建模:
我們通過CSG來構造櫃體;
因爲客戶對模型要求較高,所以不用CSG來構造抽屜,而是由美術來建模抽屜。值得注意的是要烘焙抽屜拉口中的陰影到貼圖中。另外,本來還想把抽屜之間的AO(抽屜之間是黑色的)也烘焙到ao貼圖或者normal貼圖中,但美術始終沒有做出來。另外,進行了簡化處理,如抽屜上的兩個標籤就不需要顯示;
通過拼接圓柱體、立方體來創建櫃子把手、櫃子軌道

建模後的櫃子如下圖所示,其中抽屜是克隆的:
image

第一排的其餘櫃子都是一樣的,只是Transform不同

最後,我們對第二排的櫃子建模:
同樣通過CSG來構造櫃體;
使用GridHelper來構造網格;
同樣通過拼接圓柱體、立方體來創建櫃子把手、櫃子軌道

建模後的櫃子如下圖所示:
image

第二排的其餘櫃子都是一樣的,只是Transform不同

最終,建模後的倉庫1如下圖所示:
image

倉庫2的建模也是類似的,建模後如下圖所示:
image

Instanced Draw

因爲倉庫1第一排櫃子的抽屜數量較多(有1千多個),所以會造成drawcall過多(每個抽屜都是一個drawcall),這在移動端會有明顯的性能問題

因爲有抽屜動畫(彈出抽屜),不能將其merge,所以使用Instanced Draw來批量繪製抽屜

值得注意的是抽屜可能是多材質的Object3D(雖然此處是單材質的Mesh),所以要將其中的每個Mesh拆分到一組Instanced Draw中。舉例來說,如果抽屜有個3個材質(即3個子Mesh),則需要創建3個InstancedMesh,然後將所有抽屜的第一個材質的Mesh對應到第一個InstancedMesh中,其餘的以此類推

Label

每個櫃子上面需要顯示編號,如下圖所示:
image

它是billboard,通過Sprite來實現

實現人物

可以切換軌道相機和第三人稱相機,後者會顯示人物。如下圖所示:

image

第三人稱相機的實現請參考Threejs 從零開始實現第三人稱漫遊

人物我們是在這裏下載的,帶骨骼動畫的FBX

使用AnimationMixer來播放人物的骨骼動畫,需要實現動畫的管理

人物需要與倉庫、櫃子進行碰撞檢測。我們使用Octree來構造場景的八叉樹(只構造一次,構造牆、門、地面、櫃體的八叉樹,爲了性能考慮這裏排除掉抽屜),人物則用Capsule作爲包圍盒,通過檢測Capsule和八叉樹的相交來處理碰撞

彈出抽屜

雙擊倉庫1的第一排的櫃子,可以進入單個櫃子的操作模式;然後點擊任意的抽屜,可彈出該抽屜,顯示綁定的數據。如下圖所示:

image

實現點擊的原理是:
我們將第一排的櫃子的layer設置爲可點擊的,並通過Raycaster與該layer進行ray picking(這是優化,以免與其餘的物體進行ray picking),並區分單擊和雙擊

進入單個櫃子的操作模式後,我們使用TrackControls、OrthographicCamera來正交地查看單個櫃子,並隱藏其餘的櫃子

通過使用Tween來創建彈出、彈回抽屜的關鍵幀動畫。點擊單個抽屜時,播放彈出動畫。彈出後顯示綁定的數據(此處只顯示了櫃子編號和抽屜編號,以後可通過後端請求來獲得相關的數據)

UI

UI框架使用React+Redux

普通UI使用Antd

大屏UI使用DataV-React+ECharts

大屏UI如下圖所示:
image

“3D倉庫-倉庫1”這個Header、左側的餅圖是大屏UI

切換場景

能夠切換倉庫1、倉庫2場景,如下圖所示:
image

切換時,需要先深度刪除當前場景的所有運行時數據(包括Mesh、Material、Geometry、Texture等),然後創建下一個場景的運行時數據

值得注意的是這兩個場景的資源只需加載一次

適配

對於移動端需要進行適配

橫屏

移動端需要橫屏顯示。我們檢測如果是豎屏,則提示用戶橫屏

在微信中開啓橫屏的方法:
1、我->通用->開啓橫屏模式
2、開啓手機的自動旋轉
3、將手機橫屏

第三人稱在移動端顯示虛擬搖桿

如下圖所示:
image

通過nipplejs來實現虛擬搖桿

第三人稱相機在移動端的使用說明:
將左手拇指放到屏幕左方透明的操作杆上,右手拇指放到屏幕右方的任意位置。其中,左手控制人物移動,右手旋轉屏幕視角

IOS系統適配

IOS系統中值得注意的地方:

  • 不應該動態插入/刪除dom
  • 構造octree太慢
  • 紋理大小不能太大(不能>=4096*4096)

參考資料

Web3D數字孿生有什麼參考資料(最好有源碼)?

如何用webgl(three.js)搭建一個3D庫房-第一課

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章