ceisum学习之3dtiles
3dtiles加载
var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
url : 'http://localhost:8002/tilesets/Seattle/tileset.json',//获取tileset 的资产对象属性,其中包含有关tileset 的元数据。
}));
3dtiles通过primitive
方式加载
3dtiles样式
tileset.style = new Cesium.Cesium3DTileStyle({
color : {
conditions : [
['${Height} >= 100', 'color("purple", 0.5)'],
['${Height} >= 50', 'color("red")'],
['true', 'color("blue")']
]
},
show : '${Height} > 0',
meta : {
description : '"Building id ${id} has height ${Height}."'
}
});
设置样式可以改变3dtiles颜色,如果想要实现渐变色,需要用到shader
3dtiles渲染
以上是函数调用的大致流程图和时序图。具体源码分析如下:
Scene.js
Scene.prototype.render = function (time) {
......
this._preUpdate.raiseEvent(this, time);
......
//更新前
tryAndCatchError(this, prePassesUpdate);
......
//判断primitives是否呈现
if (this.primitives.show) {
tryAndCatchError(this, updateMostDetailedRayPicks);
//预加载
tryAndCatchError(this, updatePreloadPass);
//飞行预加载
tryAndCatchError(this, updatePreloadFlightPass);
//判断不应渲染
if (!shouldRender) {
//请求渲染模式延迟检查
tryAndCatchError(this, updateRequestRenderModeDeferCheckPass);
}
}
......
this._postUpdate.raiseEvent(this, time);
......
//判断应渲染
if (shouldRender) {
this._preRender.raiseEvent(this, time);
//将creditDisplay重置为帧开始状态,清除当前creditDisplay
frameState.creditDisplay.beginFrame();
tryAndCatchError(this, render);
}
......
//第二次预更新错误显示画面
updateDebugShowFramesPerSecond(this, shouldRender);
//更新后卸载操作
tryAndCatchError(this, postPassesUpdate);
callAfterRenderFunctions(this);
if (shouldRender) {
this._postRender.raiseEvent(this, time);
//将creditDisplay重置为帧结束状态,显示creditDisplay中最后一帧的creditDisplay
frameState.creditDisplay.endFrame();
}
}
从Scene
上的render
原型方法开始渲染3dtiles,首先调用prePassesUpdate
方法,包含processTiles
方法,主要处理tile状态;然后判断primitives
上的show
属性,若是调用updateMostDetailedRayPicks
、updatePreloadPass
、updatePreloadPass
方法,如果shouldRender
为false
则调用updateRequestRenderModeDeferCheckPass
方法,包含selectTiles
、requestTiles
、updateTiles
方法,根据LOD策略更新优先级决定哪些Tile进入渲染队列,根据优先级请求已请求队列中tile的具体内容,更新平铺集中被挑选和为空的tile;最后调用postPassesUpdate
方法,包含unloadTiles
方法,卸载tile
prePassesUpdate
Scene.js
function prePassesUpdate(scene){
......
//调用PrimitiveCollection的prePassesUpdate方法
primitives.prePassesUpdate(frameState);
......
}
PrimitiveCollection.js
PrimitiveCollection.prototype.prePassesUpdate = function (frameState) {
......
//for循环,调用每个primitive的prePassesUpdate方法
for (var i = 0; i < primitives.length; ++i) {
var primitive = primitives[i];
if (defined(primitive.prePassesUpdate)) {
primitive.prePassesUpdate(frameState);
}
}
......
}
Cesium3DTileset.js
Cesium3DTileset.prototype.prePassesUpdate = function (frameState) {
......
//处理Tile对应的DrawCommand状态,判断一些半透明等渲染顺序
processTiles(this, frameState);
......
}
prePassesUpdate
方法中调用PrimitiveCollection
的prePassesUpdate
方法,再由PrimitiveCollection
循环调用其中Primitive
的prePassesUpdate
方法。3dtiles对应的原型方法prePassesUpdate
被调用,prePassesUpdate
方法中首先判断ready
是否为false
,若是则直接return
;然后调用processTiles
方法,对处理队列进行过滤,对tile状态进行处理
processTiles
Cesium3DTileset.js
function processTiles(tileset, frameState) {
filterProcessingQueue(tileset);
var tiles = tileset._processingQueue;
var length = tiles.length;
//for循环,调用每个tileset中processingQueue的process方法
for (var i = 0; i < length; ++i) {
tiles[i].process(tileset, frameState);
}
}
通过filterProcessingQueue
方法对处理队列进行过滤,移出状态不为Cesium3DTileContentState.PROCESSING
的tile;然后通过调用tile自身的process
方法,在PROCESSING
状态下处理tile状态,以便它们最终移动到就绪状态
updatePreloadPass
Scene.js
function updatePreloadPass(scene){
......
//调用PrimitiveCollection的updateForPass方法
primitives.updateForPass(frameState, preloadTilesetPassState);
......
}
PrimitiveCollection.js
PrimitiveCollection.prototype.updateForPass = function (frameState, passState) {
......
//for循环,调用每个primitive的updateForPass方法
for (var i = 0; i < primitives.length; ++i) {
var primitive = primitives[i];
if (defined(primitive.updateForPass)) {
primitive.updateForPass(frameState, passState);
}
}
......
}
Cesium3DTileset.js
Cesium3DTileset.prototype.updateForPass = function (frameState, tilesetPassState) {
......
if (pass === Cesium3DTilePass.PRELOAD &&
(!this.preloadWhenHidden || this.show)) {
return;
}
......
if (this.show || ignoreCommands) {
......
//tilesetPassState.ready由update()方法返回值决定
tilesetPassState.ready = update(this, frameState, passStatistics, passOptions);
......
}
......
}
function update(tileset, frameState, passStatistics, passOptions) {
......
//调用Cesium3DTilesetTraversal的selectTiles方法
var ready = passOptions.traversal.selectTiles(tileset, frameState);
if (passOptions.requestTiles) {
requestTiles(tileset);
}
updateTiles(tileset, frameState, passOptions);
......
return ready;
}
updatePreloadPass
方法中调用PrimitiveCollection
的updateForPass
方法,再由PrimitiveCollection
循环调用其中Primitive
的updateForPass
方法,同时将preloadTilesetPassState
传入。
3dtiles对应的原型方法updateForPass
被调用,updateForPass
方法中首先取到tilesetPassState.pass
值为Cesium3DTilePass.PRELOAD
,然后判断!this.preloadWhenHidden || this.show
是否为true
,即判断是否当隐藏是不需预加载或是否显示tileset,若是则直接return
;然后判断passOptions.ignoreCommands
是否为true
,若是则调用update
方法,传入this
、frameState
、passStatistics
、passOptions
。
在update
方法中,调用selectTiles
方法,根据LOD策略更新优先级决定哪些Tile进入渲染队列,并将其返回值ready
作为该方法返回值;判断passOptions.requestTiles
,若有则调用requestTiles
方法,根据优先级请求已请求队列中tile的具体内容;调用updateTiles
方法,更新平铺集中被挑选和为空的tile
preloadTilesetPassState
:Cesium3DTilePassState
类型,其中pass
属性值为Cesium3DTilePass.PRELOAD
,表示当前进展
var preloadTilesetPassState = new Cesium3DTilePassState({
pass: Cesium3DTilePass.PRELOAD,
});
this.preloadWhenHidden
:当tileset.show=false
时,预加载tile。加载平铺tile但不渲染,默认值为false
this.preloadWhenHidden = defaultValue(options.preloadWhenHidden, false);
this.show
:确定是否显示平铺集tileset,默认值为true
this.show = defaultValue(options.show, true);
passOptions
:传入值为Cesium3DTilePass.PRELOAD
调用getPassOptions
方法得到类型为passOptions[Cesium3DTilePass.PRELOAD]
的对象,作为通过选项
var passOptions = Cesium3DTilePass.getPassOptions(Cesium3DTilePass.PRELOAD);
passStatistics
:Cesium3DTilePass.PRELOAD
值添加给统计预通过变量_statisticsPerPass
然后赋值给passStatistics
,以此来统计
this._statisticsPerPass = new Array(Cesium3DTilePass.NUMBER_OF_PASSES);
var passStatistics = this._statisticsPerPass[pass];
selectTiles
Cesium3DTileset.js
var passOptions = Cesium3DTilePass.getPassOptions(pass);
Cesium3DTilePass.js
passOptions[Cesium3DTilePass] = Object.freeze({
traversal: Cesium3DTilesetTraversal,
isRender: Boolean,
requestTiles: Boolean,
ignoreCommands: Boolean,
});
//Cesium3DTilePass.PRELOAD
passOptions[Cesium3DTilePass.PRELOAD] = Object.freeze({
traversal: Cesium3DTilesetTraversal,
isRender: false,
requestTiles: true,
ignoreCommands: true,
});
Cesium3DTilesetTraversal.js
Cesium3DTilesetTraversal.selectTiles = function (tileset, frameState) {
......
updateTile(tileset, root, frameState);
......
//for循环更新请求tile的优先级
for (var i = 0; i < length; ++i) {
requestedTiles[i].updatePriority();
}
}
function updateTile(tileset, tile, frameState) {
//重置部分tile的标志并重新评估可见性
updateTileVisibility(tileset, tile, frameState);
tile.updateExpiration();
......
//更新最小最大优先级
updateMinimumMaximumPriority(tileset, tile);
......
//根据LOD策略决定哪些Tile进入渲染队列
......
}
首先调用updateTile
方法,调用updateTileVisibility
和tile.updateExpiration
方法重置部分tile的标志并重新评估可见性,调用updateMinimumMaximumPriority
方法,根据LOD策略决定哪些Tile进入渲染队列,并更新优先级;然后循环已请求的tiles,更新它们的优先级
requestTiles
Cesium3DTileset.js
function requestTiles(tileset, isAsync) {
......
//通过比较两者的priority进行排序
requestedTiles.sort(sortRequestByPriority);
//for循环请求tiles内容
for (var i = 0; i < length; ++i) {
requestContent(tileset, requestedTiles[i]);
}
......
}
通过requestedTiles
的sort
方法对请求tiles进行排序,按照优先级顺序,依次调用requestContent
方法,请求tile的具体内容
updateTiles
Cesium3DTileset.js
function updateTiles(tileset, frameState, passOptions) {
......
//for循环更新tileset.selectedTiles内容
for (i = 0; i < selectedLength; ++i) {
tile = selectedTiles[i];
// 在提升tileVisible事件前进行更新
if (isRender) {
tileVisible.raiseEvent(tile);
}
//更新tile
tile.update(tileset, frameState, passOptions);
statistics.incrementSelectionCounts(tile.content);
++statistics.selected;
}
//for循环更新tileset.emptyTiles内容
for (i = 0; i < emptyLength; ++i) {
tile = emptyTiles[i];
//更新tile
tile.update(tileset, frameState, passOptions);
}
}
Cesium3DTileset.prototype.update = function (frameState) {
this.updateForPass(frameState, frameState.tilesetPassState);
};
首先循环平铺集tileset上被挑选的tile,调用update
更新;然后循环平铺集tileset上为空的tile,调用update
更新;
updatePreloadFlightPass
Scene.js
function updatePreloadFlightPass(scene){
......
primitives.updateForPass(frameState, preloadFlightTilesetPassState);
......
}
Cesium3DTileset.js
Cesium3DTileset.prototype.updateForPass = function (frameState, tilesetPassState) {
......
if (pass === Cesium3DTilePass.PRELOAD_FLIGHT &&
(!this.preloadFlightDestinations ||
(!this.show && !this.preloadWhenHidden))) {
return;
}
......
}
updatePreloadFlightPass
方法中调用PrimitiveCollection
的updateForPass
方法,再由PrimitiveCollection
循环调用其中Primitive
的updateForPass
方法,同时将preloadFlightTilesetPassState
传入。
3dtiles对应的原型方法updateForPass
被调用,updateForPass
方法中首先取到tilesetPassState.pass
值为Cesium3DTilePass.PRELOAD_FLIGHT
,然后判断!this.preloadFlightDestinations || (!this.show && !this.preloadWhenHidden)
是否为true
,即判断是否不优化选项或者不需当隐藏时预加载并且不显示tileset,若是则直接return
;下面流程同上updatePreloadPass
preloadFlightTilesetPassState
:Cesium3DTilePassState
类型,其中pass
属性值为Cesium3DTilePass.PRELOAD_FLIGHT
,表示当前进展
var preloadFlightTilesetPassState = new Cesium3DTilePassState({
pass: Cesium3DTilePass.PRELOAD_FLIGHT,
});
this.preloadFlightDestinations
:优化选项。当相机在飞行中时,在相机的飞行目的地取回瓷砖,默认值为true
this.preloadFlightDestinations = defaultValue(options.preloadFlightDestinations, true);
updateRequestRenderModeDeferCheckPass
Scene.js
function updateRequestRenderModeDeferCheckPass(scene){
......
primitives.updateForPass(frameState, requestRenderModeDeferCheckPassState);
......
}
Cesium3DTileset.js
Cesium3DTileset.prototype.updateForPass = function (frameState, tilesetPassState) {
......
if (pass === Cesium3DTilePass.REQUEST_RENDER_MODE_DEFER_CHECK &&
((!this._cullRequestsWhileMoving && this.foveatedTimeDelay <= 0) ||
!this.show))) {
return;
}
......
}
updateRequestRenderModeDeferCheckPass
方法中调用PrimitiveCollection
的updateForPass
方法,再由PrimitiveCollection
循环调用其中Primitive
的updateForPass
方法,同时将requestRenderModeDeferCheckPassState
传入。
3dtiles对应的原型方法updateForPass
被调用,updateForPass
方法中首先取到tilesetPassState.pass
值为Cesium3DTilePass.REQUEST_RENDER_MODE_DEFER_CHECK
,然后判断(!this._cullRequestsWhileMoving && this.foveatedTimeDelay <= 0) ||!this.show
是否为true
,即判断是否不需再相机移动时挑选请求并且相机停止移动后不等待或者不显示tileset,若是则直接return
;下面流程同上updatePreloadPass
requestRenderModeDeferCheckPassState
:Cesium3DTilePassState
类型,其中pass
属性值为Cesium3DTilePass.REQUEST_RENDER_MODE_DEFER_CHECK
,表示当前进展
var requestRenderModeDeferCheckPassState = new Cesium3DTilePassState({
pass: Cesium3DTilePass.REQUEST_RENDER_MODE_DEFER_CHECK,
});
this._cullRequestsWhileMoving
:当相机移动的时候是否挑选请求,默认值为false
this._cullRequestsWhileMoving = false;
this.foveatedTimeDelay
:相机停止移动后等待多长时间(以秒为单位)才能开始加载延迟的磁贴。此时间延迟可防止在相机移动时请求屏幕边缘的平铺,将此设置为0.0将立即请求任何给定视图中的所有平铺,默认值为true
this.foveatedTimeDelay = defaultValue(options.foveatedTimeDelay, 0.2)
postPassesUpdate
Scene.js
function postPassesUpdate(scene) {
......
//调用PrimitiveCollection的postPassesUpdate方法
primitives.postPassesUpdate(frameState);
......
//并发管理更新
RequestScheduler.update();
......
}
PrimitiveCollection.js
PrimitiveCollection.prototype.postPassesUpdate = function (frameState) {
......
//for循环,调用每个primitive的postPassesUpdate方法
for (var i = 0; i < primitives.length; ++i) {
var primitive = primitives[i];
if (defined(primitive.postPassesUpdate)) {
primitive.postPassesUpdate(frameState);
}
}
......
}
Cesium3DTileset.js
Cesium3DTileset.prototype.postPassesUpdate = function (frameState) {
......
//取消脱离视图范围请求
cancelOutOfViewRequests(this, frameState);
......
//对缓存中tiles进行卸载操作
this._cache.unloadTiles(this, unloadTile);
......
}
postPassesUpdate
方法调用PrimitiveCollection
的postPassesUpdate
方法,再由PrimitiveCollection
循环调用其中Primitive
的postPassesUpdate
方法,并且更新RequestScheduler,更新并发管理
在postPassesUpdate
方法中,调用cancelOutOfViewRequests
方法,取消脱离视图范围的tile请求;调用this._cache.unloadTiles
方法,对缓存中tiles进行卸载操作
unloadTiles
Cesium3DTileset.js
this._cache = new Cesium3DTilesetCache();
Cesium3DTilesetCache.js
Cesium3DTilesetCache.prototype.unloadTiles = function (tileset, unloadCallback) {
......
this.unloadTile(tileset, tile, unloadCallback);
......
}
Cesium3DTilesetCache.prototype.unloadTile = function (tileset, tile, unloadCallback) {
......
var node = tile.cacheNode;
......
//卸载tile缓存节点
this._list.remove(node);
tile.cacheNode = undefined;
unloadCallback(tileset, tile);
......
}
this._cache
是一个Cesium3DTilesetCache
类型的对象,拥有原型方法unloadTile
,渲染完后卸载缓存中的tile
调用unloadTile
方法,将缓存节点卸载
转载自:https://juejin.cn/post/7037402687733760030