描述
Cesium在2016年3月份左右推出3D Tiles数据规范,在glTF基础上提供了LOD能力,定位就是Web环境下海量三维模型数据。使用概念上类似terrain
和imagery
的瓦片流技术。
3dtiles还允许我们使用3d Tiles Styling
语言来调整样式。
加载
tiles = scence.primitives.add(new Cesium.Cesium3DTileset({
url: ''
}))
如上所示,Cesium提供了Cesium3DTileset类来管理,主要负责Tile的调度。在Cesium中,3DTiles就相当于一个Primitive的位置.
当我们创建一个Cesium3DTileset后,每一个Tile对应一个Cesium3DTile。如上根节点是root,content是根节点对应的文件名,这里是parent.b3dm,四个子节点,子节点对应的文件名分别为ll.b3dm……
调度过程
3dTiles本质是一个JSON对象。
在获取JSON对象后,首先创建rootTile
根节点,然后在while循环中,以广度优先的方式遍历这个树
,每个节点都有一个parentTile
属性绑定父节点(根节点除外),同时有一个children
数组,保存该节点对应的所有子节点。
这样,在初始化阶段,Cesium3DTileset中就保存了该3DTiles树上的所有节点及关联
,当然此时只是属性信息,并没有加载数据内容,所以内存上还是可以接受。这就相当于我们读书,都会先看这本书的目录,了解一个大概。
但此时,如果数据量很大的情况下,初次加载全部节点是一个性能瓶颈。这是3D Tiles目前设计上的不足
以下为部分源码
调度管理的逻辑
四个函数的作用大概如下:
processTiles
处理Tile对应的DrawCommand状态,判断一些半透明等渲染顺序
selectTiles
请求具体的b3dm数据,不同Type根据对应的类来完成数据的下载,根据LOD策略决定哪些Tile进入渲染队列。
updateTiles
当前帧状态下遍历这棵树,调用该Tile对应的Model::update,完成数据的解析最终构造出DrawCommand
unloadTiles
判断当前Tiles数目是否超过上限,卸载多余的Tile
在selectTiles函数中,首先是下载Tile对应的数据内容(b3dm后缀),通过contentUnloaded标识来判断,如果根节点的数据还没有下载,则request,然后返回
UpdateTiles看上去就比较简单了,指定具体的Content..update,这个过程就是之前Pimitive和Model对应的update。
总结
让我学到的一点就是RequestScheduler类,大概思路是规定每次并发的最大请求数,每一帧收集下载请求但并不发送该请求,在下一帧对请求队列排序(相机远近),然后再发送。实现的很巧妙,方便管理。毕竟在海量数据下,有这样一个Manager来控制是很有必要的。
问题比较大的地方是删除上(因为没有大数据测试,仅从代码逻辑猜测)。
第一,update
和select
两个都是异步或者workers线程机制,在数据量比较大的情况下会有内存泄漏。
第二,Replace
队列无脑删除,并不是根据当前的范围和LOD
,这个在设计上是一个很大的缺陷,只考虑了可见不可见,但没有优化删除策略。
借鉴‘法克鸡丝’大佬的源码分析 原文地址