本文以分析QuadtreePrimitive及相关影像内容,讨论一些流程和方法。影像和地形是Cesium的基础内容,但是有时候感觉这部分的加载和渲染效率并不高。
TileReplacementQueue是一个非常神奇的类,我自己研究了小半天。虽然结构简单,但是它可以呈现比较丰富的形态。可以学习学习。
TileReplacementQueue这个队列是瓦片可以被替换的队列,越在后面的,越是价值不高的。
对了,本文可以结合源码阅读。本文如果直接读,可以看懂,但可能感受不到源码的威力(复杂性或者说莫名其妙的设计)。
添加队列
- markTileRendered(item)方法,它会把这个瓦片作为当前最宝贝的(最前面)的。这个item来自要加载的队列。及来自当前的渲染队列。
- 来自渲染队列的情况,越是顶层(Level越小的)优先级越低。反之依然。也就是顶层的瓦片被替换的优先级比较高。当然需要被渲染的优先级大于不需要被渲染的。
- 来自更新队列的情况,其整体优先级大于渲染队列的。更新队列包括tileLoadQueueHigh、tileLoadQueueMedium、tileLoadQueueLow,如果有tileLoadQueueHigh,那么就不会把tileLoadQueueMedium放到队列中。
循环队列
- 每一轮帧循环,如果没有更新,没有移动视角的情况下,指针会从Tail走向Head。队列会向手里的扑克一样从下面一张张抽到上面。
- 每一轮帧循环,如果有更新,有移动视角的情况下,那么队列中必然会出现有些Tile不可见,因此他们并没有像前面那样被抽到前面,而是放到了后面。
队列分组
- _lastBeforeStartOfFrame这个上次队列的第一个(head)。而head一般是当前渲染的众多叶子节点的一个。
- 如果_lastBeforeStartOfFrame是可见的,在本轮检查后,_lastBeforeStartOfFrame会是空的。因为_lastBeforeStartOfFrame被从底层抽到最前面的时候,_lastBeforeStartOfFrame被指向它的Next。在最底的时候Next为空,因此_lastBeforeStartOfFrame就变空了。
- _lastBeforeStartOfFrame为空,则说明上次渲染的叶子节点可见。
- 如果_lastBeforeStartOfFrame不为空,则说明上次渲染的叶子节点不可见。
- 如果_lastBeforeStartOfFrame不为空,那么它后面不可见的Tile一般都是不可见的。
移除不可见的
- trimTiles方法就是移除队列的后面不可见的瓦片。
- _lastBeforeStartOfFrame可以保证在trimTiles方法中不要清除_lastBeforeStartOfFrame之前的瓦片。因为_lastBeforeStartOfFrame之前的瓦片是要被渲染或者更新加载的瓦片。而_lastBeforeStartOfFrame之后的瓦片是当下不可见的瓦片。
总结
简简单单的一个类,内部隐含了非常多的策略逻辑,不得不佩服设计者的巧妙之处。虽然分析起来比较头疼。
但_lastBeforeStartOfFrame的设计总感觉莫名其妙。因为_lastBeforeStartOfFrame只能指向其中一个叶子瓦片节点。而当前渲染场景有很多叶子节点。仅当此叶子节点不可见才能被移除,实属“点兵点将,点到谁就是谁”,有点随意或不全面。
另外,TileReplacementQueue是每帧都进行分析,一般可见域有120个左右的瓦片,计算量还是有的。这种密集式计算是否得当也是需要深度分析的。