cesium 3dTiles渲染调度

3,174 阅读3分钟

描述

Cesium在2016年3月份左右推出3D Tiles数据规范,在glTF基础上提供了LOD能力,定位就是Web环境下海量三维模型数据。使用概念上类似terrainimagery的瓦片流技术。

3dtiles还允许我们使用3d Tiles Styling 语言来调整样式。

加载

tiles = scence.primitives.add(new Cesium.Cesium3DTileset({
    url: ''
}))

如上所示,Cesium提供了Cesium3DTileset类来管理,主要负责Tile的调度。在Cesium中,3DTiles就相当于一个Primitive的位置.

8.jpg

当我们创建一个Cesium3DTileset后,每一个Tile对应一个Cesium3DTile。如上根节点是root,content是根节点对应的文件名,这里是parent.b3dm,四个子节点,子节点对应的文件名分别为ll.b3dm……

调度过程

3dTiles本质是一个JSON对象。

在获取JSON对象后,首先创建rootTile根节点,然后在while循环中,以广度优先的方式遍历这个树,每个节点都有一个parentTile属性绑定父节点(根节点除外),同时有一个children数组,保存该节点对应的所有子节点。

这样,在初始化阶段,Cesium3DTileset中就保存了该3DTiles树上的所有节点及关联,当然此时只是属性信息,并没有加载数据内容,所以内存上还是可以接受。这就相当于我们读书,都会先看这本书的目录,了解一个大概。

但此时,如果数据量很大的情况下,初次加载全部节点是一个性能瓶颈。这是3D Tiles目前设计上的不足

以下为部分源码

80.jpg

调度管理的逻辑

四个函数的作用大概如下:

processTiles

处理Tile对应的DrawCommand状态,判断一些半透明等渲染顺序

selectTiles

请求具体的b3dm数据,不同Type根据对应的类来完成数据的下载,根据LOD策略决定哪些Tile进入渲染队列。

updateTiles

当前帧状态下遍历这棵树,调用该Tile对应的Model::update,完成数据的解析最终构造出DrawCommand

unloadTiles

判断当前Tiles数目是否超过上限,卸载多余的Tile

800.jpg

在selectTiles函数中,首先是下载Tile对应的数据内容(b3dm后缀),通过contentUnloaded标识来判断,如果根节点的数据还没有下载,则request,然后返回

8001.jpg

UpdateTiles看上去就比较简单了,指定具体的Content..update,这个过程就是之前Pimitive和Model对应的update。

80017.jpg

总结

让我学到的一点就是RequestScheduler类,大概思路是规定每次并发的最大请求数,每一帧收集下载请求但并不发送该请求,在下一帧对请求队列排序(相机远近),然后再发送。实现的很巧妙,方便管理。毕竟在海量数据下,有这样一个Manager来控制是很有必要的。

问题比较大的地方是删除上(因为没有大数据测试,仅从代码逻辑猜测)。

第一,updateselect两个都是异步或者workers线程机制,在数据量比较大的情况下会有内存泄漏。

第二,Replace队列无脑删除,并不是根据当前的范围和LOD,这个在设计上是一个很大的缺陷,只考虑了可见不可见,但没有优化删除策略。

借鉴‘法克鸡丝’大佬的源码分析 原文地址