likes
comments
collection
share

ceisum学习之3dtiles

作者站长头像
站长
· 阅读数 41

3dtiles加载

Cesium3DTileset

var tileset = scene.primitives.add(new Cesium.Cesium3DTileset({
     url : 'http://localhost:8002/tilesets/Seattle/tileset.json',//获取tileset 的资产对象属性,其中包含有关tileset 的元数据。
}));

3dtiles通过primitive方式加载

3dtiles样式

Cesium3DTileStyle

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渲染

prePassesUpdate
primitives.prePassesUpdate
primitive.prePassesUpdate
processTiles
updatePreloadPass
primitives.updateForPass
primitive.updateForPass
update
selectTiles
requestTiles
updateTiles
updatePreloadFlightPass
updateRequestRenderModeDeferCheckPass
postPassesUpdate
primitives.postPassesUpdate
primitive.postPassesUpdate
unloadTiles
ScenePrimitiveCollectionCesium3DTilesetCesium3DTilesetTraversalCesium3DTilesetCacheprePassesUpdateprePassesUpdateprePassesUpdateprocessTilesupdatePreloadPassupdateForPassupdateForPassupdateselectTilesrequestTilesupdateTilesupdatePreloadFlightPassupdateForPassupdateForPassupdateselectTilesrequestTilesupdateTilesupdateRequestRenderModeDeferCheckPassupdateForPassupdateForPassupdateselectTilesrequestTilesupdateTilespostPassesUpdatepostPassesUpdatepostPassesUpdatecancelOutOfViewRequestsraiseLoadProgressEventunloadTilesScenePrimitiveCollectionCesium3DTilesetCesium3DTilesetTraversalCesium3DTilesetCache

以上是函数调用的大致流程图和时序图。具体源码分析如下:

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属性,若是调用updateMostDetailedRayPicksupdatePreloadPassupdatePreloadPass方法,如果shouldRenderfalse则调用updateRequestRenderModeDeferCheckPass方法,包含selectTilesrequestTilesupdateTiles方法,根据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方法中调用PrimitiveCollectionprePassesUpdate方法,再由PrimitiveCollection循环调用其中PrimitiveprePassesUpdate方法。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方法中调用PrimitiveCollectionupdateForPass方法,再由PrimitiveCollection循环调用其中PrimitiveupdateForPass方法,同时将preloadTilesetPassState传入。 3dtiles对应的原型方法updateForPass被调用,updateForPass方法中首先取到tilesetPassState.pass值为Cesium3DTilePass.PRELOAD,然后判断!this.preloadWhenHidden || this.show是否为true,即判断是否当隐藏是不需预加载或是否显示tileset,若是则直接return;然后判断passOptions.ignoreCommands是否为true,若是则调用update方法,传入thisframeStatepassStatisticspassOptions。 在update方法中,调用selectTiles方法,根据LOD策略更新优先级决定哪些Tile进入渲染队列,并将其返回值ready作为该方法返回值;判断passOptions.requestTiles,若有则调用requestTiles方法,根据优先级请求已请求队列中tile的具体内容;调用updateTiles方法,更新平铺集中被挑选和为空的tile

  • preloadTilesetPassStateCesium3DTilePassState类型,其中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);
  • passStatisticsCesium3DTilePass.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方法,调用updateTileVisibilitytile.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]);
    }
    ......
}

通过requestedTilessort方法对请求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方法中调用PrimitiveCollectionupdateForPass方法,再由PrimitiveCollection循环调用其中PrimitiveupdateForPass方法,同时将preloadFlightTilesetPassState传入。 3dtiles对应的原型方法updateForPass被调用,updateForPass方法中首先取到tilesetPassState.pass值为Cesium3DTilePass.PRELOAD_FLIGHT,然后判断!this.preloadFlightDestinations || (!this.show && !this.preloadWhenHidden)是否为true,即判断是否不优化选项或者不需当隐藏时预加载并且不显示tileset,若是则直接return;下面流程同上updatePreloadPass

  • preloadFlightTilesetPassStateCesium3DTilePassState类型,其中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方法中调用PrimitiveCollectionupdateForPass方法,再由PrimitiveCollection循环调用其中PrimitiveupdateForPass方法,同时将requestRenderModeDeferCheckPassState传入。 3dtiles对应的原型方法updateForPass被调用,updateForPass方法中首先取到tilesetPassState.pass值为Cesium3DTilePass.REQUEST_RENDER_MODE_DEFER_CHECK,然后判断(!this._cullRequestsWhileMoving && this.foveatedTimeDelay <= 0) ||!this.show是否为true,即判断是否不需再相机移动时挑选请求并且相机停止移动后不等待或者不显示tileset,若是则直接return;下面流程同上updatePreloadPass

  • requestRenderModeDeferCheckPassStateCesium3DTilePassState类型,其中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方法调用PrimitiveCollectionpostPassesUpdate方法,再由PrimitiveCollection循环调用其中PrimitivepostPassesUpdate方法,并且更新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
评论
请登录