Cesium在2016年3月份左右推出3D Tiles數據規範,在glTF基礎上提供了LOD能力,定位就是Web環境下海量三維模型數據。雖然目前3D Tiles仍是Beta階段,有很多硬傷,但3D Tiles數據規範於2016年9月30日開始了OGC標準化進程,積極成分仍是很大。 數組
以前的glTF時分享了我的對二進制格式的一些想法和謹慎的態度。3D Tiles簡單說就是具有LOD能力的glTF。有了數據首先是提供API能夠渲染,保證用起來,下一步就要了解該數據規範的具體特色,好比傾斜,矢量,點雲,OSM等支持狀況,項目實施和風險評估等。最後,做爲一個數據規範,從數據生產到深層次應用,須要時間沉澱出完善豐富的解決方案。 併發
本文主要集中在渲染調度層面。看完本文可能會以爲思路很簡單。在實際應用中有不少細節,好比瀏覽時各類操做的差別,併發量,內存和顯存管理,異步傳輸和Workers線程等等各類調優。思路簡單,但要把這些小細節打磨好就不容易了。本文只講詩和遠方,鞋裏的沙子本身來處理吧。 異步
先看看如何加載3D Tiles數據,如上所示,Cesium提供了Cesium3DTileset類來管理,主要負責Tile的調度。在Cesium中,3DTiles就至關於一個Primitive的位置。 函數
3D Tile表述 工具
當咱們建立一個Cesium3DTileset後,每個Tile對應一個Cesium3DTile。如上根節點是root,content是根節點對應的文件名,這裏是parent.b3dm,四個子節點,子節點對應的文件名分別爲ll.b3dm……。 性能
如上,在獲取JSON對象後,首先建立rootTile根節點,而後在while循環中,以廣度優先的方式遍歷這個樹,每一個節點都有一個parentTile屬性綁定父節點(根節點除外),同時有一個children數組,保存該節點對應的全部子節點。 學習
這樣,在初始化階段,Cesium3DTileset中就保存了該3DTiles樹上的全部節點及關聯,固然此時只是屬性信息,並無加載數據內容,因此內存上仍是能夠接受。這就至關於咱們讀書,都會先看這本書的目錄,瞭解一個大概。但我的認爲,第一,不必,實際上只須要找到根節點,下面按需順藤摸瓜就能夠(JSON在搜索節點上很麻煩);第二,若是數據量很大的狀況下,初次加載所有節點是一個性能瓶頸。這是3D Tiles目前設計上的不足。 測試
Cesium3DTile中經過一個簡單的Cesium3DTileContentFactory工廠模式,目前主要提供四種類型。根據當前數據的具體類型(Type)來建立對應的內容(Content),本篇不涉及這塊。初始化結束後,和以前glTF或primitive同樣,基於狀態的驅動流程: 大數據
如上是調度管理的邏輯,四個函數的做用大概以下: 優化
processTiles
處理Tile對應的DrawCommand狀態,判斷一些半透明等渲染順序
selectTiles
請求具體的b3dm數據,不一樣Type根據對應的類來完成數據的下載,根據LOD策略決定哪些Tile進入渲染隊列。
updateTiles
當前幀狀態下遍歷這棵樹,調用該Tile對應的Model::update,完成數據的解析最終構造出DrawCommand
unloadTiles
判斷當前Tiles數目是否超過上限,卸載多餘的Tile
在selectTiles函數中,首先是下載Tile對應的數據內容(b3dm後綴),經過contentUnloaded標識來判斷,若是根節點的數據尚未下載,則request,而後返回。
一個簡單的request,裏面的信息量其實也不小,調用對應Cesium3DTile和Content對應的request來下載數據,這這裏Cesium專門封裝了一個RequestScheduler類來管理併發,咱們最後在介紹這個。這裏注意,當該數據下載完成後,則添加到兩個隊列:processQueue和removeQueue。
在Key2中,就是一個LOD策略的實現,上圖給出了追加的邏輯註釋。Cesium目前支持兩種方式Add追加和Replace替換兩種方式。Add方式較爲簡單,是Tiles求並的思路,而Replace是覆蓋的思路,較爲複雜,由於要控制父子節點直接的可見不可見,從代碼來看,Cesium在這一塊處理的比較簡單,應該會出現閃爍的效果,不知道是否有人能夠證明這個推測是否正確?
UpdateTiles看上去就比較簡單了,指定具體的Content..update,這個過程就是以前Pimitive和Model對應的update。
對於能夠卸載的Tile,則知足條件後調用unloadContent,但我的以爲這塊設計的仍是有些疑慮。首先,設計的很不錯,從Content到BatchTable,到Model,以及Texture都提供了destory方法,但紋理仍是應該提供紋理管理器的概念,解決重用紋理的釋放。
讓我學到的一點就是RequestScheduler類,大概思路是規定每次併發的最大請求數,每一幀收集下載請求但並不發送該請求,在下一幀對請求隊列排序(相機遠近),而後再發送。實現的很巧妙,方便管理。畢竟在海量數據下,有這樣一個Manager來控制是頗有必要的。
問題比較大的地方是刪除上(由於沒有大數據測試,僅從代碼邏輯猜想)。第一,update和select兩個都是異步或者workers線程機制,在數據量比較大的狀況下會有內存泄漏。第二,Replace隊列無腦刪除,並非根據當前的範圍和LOD,這個在設計上是一個很大的缺陷,只考慮了可見不可見,但沒有優化刪除策略。
整體來講,做爲一個開源項目,3D Tiles邁出了很堅實的一步,數據規範設計的很優雅,基於glTF也下降了學習成本。同時Cesium提供了渲染3D Tiles的接口,稍顯不足的就是尚未成熟的,免費的數據生成工具,能夠從osg轉爲3d tiles,這是目前最大的瓶頸。簡單說,Cesium目前提供了基本技術和規範,但並無提供完整的解決方案,同時還缺乏基於3D Tiles的豐富的擴展和應用。固然,咱們不能對一個開源項目要求苛刻,並且我相信,也但願Cesium後續後慢慢完善,前面把路走踏實了,慢一點均可以接受,路遙知馬力,踏踏實實作事情方能立本,本立而道生,在這個物慾橫流的世界,這麼簡單的道理,其實並不簡單。