Cesium基於WebGL實現,所以渲染機制跟我們直接用WebGL的道理相同,但是內部功能強大,會更復雜些
目前不討論Cesium的實現原理,先了解下Cesium的大體渲染流程的機制,有個初步認識
HelloWorld
亙古不變的HelloWorld,一句代碼就可以繪製出來地球和很多小部件
var viewer = new Cesium.Viewer("cesiumContainer");
來一層一層看下地球是如何出來的
Viewer.js 相關代碼
function Viewer(container, options) {
container = getElement(container);
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
var viewerContainer = document.createElement("div");
viewerContainer.className = "cesium-viewer";
container.appendChild(viewerContainer);
// Cesium widget container
var cesiumWidgetContainer = document.createElement("div");
viewerContainer.appendChild(cesiumWidgetContainer);
// Bottom container
var bottomContainer = document.createElement("div");
viewerContainer.appendChild(bottomContainer);
// Cesium widget
var cesiumWidget = new CesiumWidget(cesiumWidgetContainer, {
imageryProvider: imageryProvider,
// ...
sceneMode: options.sceneMode,
});
// ...
// 初始化具體小部件、屬性、事件等
}
Viewer()方法作爲入口,構建必須的dom元素,初始化具體小部件、屬性、事件等,很重要的一個就是實例化了CesiumWidget
,而CesiumWidget
內部構建了定時器,用來不斷刷新並渲染頁面
CesiumWidget.js 相關代碼
// 定義定時器
function startRenderLoop(widget) {
var lastFrameTime = 0;
function render(frameTime) {
// ...
widget.resize();
widget.render();
requestAnimationFrame(render);
// ...
}
requestAnimationFrame(render);
}
function CesiumWidget(container, options) {
container = getElement(container);
//Configure the widget DOM elements
var element = document.createElement("div");
element.className = "cesium-widget";
container.appendChild(element);
var canvas = document.createElement("canvas");
canvas.addEventListener("mousedown", blurActiveElement);
canvas.addEventListener("pointerdown", blurActiveElement);
element.appendChild(canvas);
var scene = new Scene({
canvas: canvas,
// ...
});
this._scene = scene;
var ellipsoid = defaultValue(
scene.mapProjection.ellipsoid,
Ellipsoid.WGS84
);
var globe = options.globe;
if (!defined(globe)) {
globe = new Globe(ellipsoid);
}
if (globe !== false) {
scene.globe = globe;
scene.globe.shadows = defaultValue(
options.terrainShadows,
ShadowMode.RECEIVE_ONLY
);
}
var skyBox = options.skyBox;
var skyAtmosphere = options.skyAtmosphere;
var imageryProvider = createWorldImagery();
scene.terrainProvider = options.terrainProvider;
// 給 useDefaultRenderLoop 屬性賦值,觸發了
this._useDefaultRenderLoop = undefined;
this.useDefaultRenderLoop = defaultValue(
options.useDefaultRenderLoop,
true
);
}
Object.defineProperties(CesiumWidget.prototype, {
// ...
// 通過set設置在賦值時,觸發定時器
useDefaultRenderLoop: {
get: function () {
return this._useDefaultRenderLoop;
},
set: function (value) {
if (this._useDefaultRenderLoop !== value) {
this._useDefaultRenderLoop = value;
if (value && !this._renderLoopRunning) {
startRenderLoop(this);
}
}
},
}
})
// render方法
CesiumWidget.prototype.render = function () {
if (this._canRender) {
this._scene.initializeFrame();
var currentTime = this._clock.tick();
// 此時調用_scene的渲染方法
this._scene.render(currentTime);
} else {
this._clock.tick();
}
};
在this._scene.render(currentTime)
執行時,會調用scene
的渲染方法,來渲染場景中的各類要素
Scene.js 相關代碼
function render(scene) {
// ...
// globe地球渲染開始
scene.globe.beginFrame(frameState);
// 其它環境、覆蓋物渲染等
scene.updateEnvironment();
scene.updateAndExecuteCommands(passState, backgroundColor);
scene.resolveFramebuffers(passState);
executeOverlayCommands(scene, passState);
// globe地球渲染結束
scene.globe.endFrame(frameState);
}
Scene.prototype.render = function (time) {
tryAndCatchError(this, prePassesUpdate);
tryAndCatchError(this, updateMostDetailedRayPicks);
tryAndCatchError(this, updatePreloadPass);
tryAndCatchError(this, updatePreloadFlightPass);
// 調用render()
tryAndCatchError(this, render);
};
此處就可以看到globe
的渲染方法登場,地球的繪製是通過地形和地圖疊加到橢球體顯示而成
Globe.js 相關代碼
function Globe(ellipsoid) {
ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
var terrainProvider = new EllipsoidTerrainProvider({
ellipsoid: ellipsoid,
});
var imageryLayerCollection = new ImageryLayerCollection();
this._ellipsoid = ellipsoid;
this._imageryLayerCollection = imageryLayerCollection;
this._surfaceShaderSet = new GlobeSurfaceShaderSet();
this._material = undefined;
this._surface = new QuadtreePrimitive({
tileProvider: new GlobeSurfaceTileProvider({
terrainProvider: terrainProvider,
imageryLayers: imageryLayerCollection,
surfaceShaderSet: this._surfaceShaderSet,
}),
});
// ...
}
Globe.prototype.beginFrame = function (frameState) {
var surface = this._surface;
var tileProvider = surface.tileProvider;
var terrainProvider = this.terrainProvider;
var hasWaterMask = this.showWaterEffect
// ...
surface.tileCacheSize = this.tileCacheSize;
tileProvider.terrainProvider = this.terrainProvider;
tileProvider.hasWaterMask = hasWaterMask;
surface.beginFrame(frameState);
// ...
};
地球表面包含着地形、切片、水面等,統一由tileProvider
處理,通過surface.beginFrame(frameState)
執行
由此,能看到各級關係如下: