Seek medical advice
- Do you want to know the source code of cesium?
- Have you ever lost your way in the huge source code?
- How does cesium render the scene step by step?
Go straight to the subject
1. The origin of all things - time
//Clock.js Clock.prototype.tick = function () { var currentSystemTime = getTimestamp(); var currentTime = JulianDate.clone(this._currentTime); ...//ellipsis this._currentTime = currentTime; this._lastSystemTime = currentSystemTime; this.onTick.raiseEvent(this); return currentTime; };
It can be seen from the code that when the tick function is executed, the subscribed actions in onTick will be executed synchronously.
2. Rendering frequency - frame rate
//requestAnimationFrame.js (function () { // look for vendor prefixed function if (!defined(implementation) && typeof window !== "undefined") { var vendors = ["webkit", "moz", "ms", "o"]; var i = 0; var len = vendors.length; while (i < len && !defined(implementation)) { implementation = window[vendors[i] + "RequestAnimationFrame"]; ++i; } } // build an implementation based on setTimeout if (!defined(implementation)) { var msPerFrame = 1000.0 / 60.0; var lastFrameTime = 0; implementation = function (callback) { var currentTime = getTimestamp(); // schedule the callback to target 60fps, 16.7ms per frame, // accounting for the time taken by the callback var delay = Math.max(msPerFrame - (currentTime - lastFrameTime), 0); lastFrameTime = currentTime + delay; return setTimeout(function () { callback(lastFrameTime); }, delay); }; } })();
It can be seen from the code that cesium handles the requestanimation frame of various browsers in a compatible manner.
3. Rendering -- scene
Scene.prototype.render = function (time) { this._preUpdate.raiseEvent(this, time); var frameState = this._frameState; frameState.newFrame = false; ...//ellipsis this._postUpdate.raiseEvent(this, time); if (shouldRender) { this._preRender.raiseEvent(this, time); frameState.creditDisplay.beginFrame(); tryAndCatchError(this, render); } if (shouldRender) { this._postRender.raiseEvent(this, time); frameState.creditDisplay.endFrame(); } };
From the code, we can see that this function is responsible for updating the status of all primitive data in the scene, and then the data is generated by itself to decide whether to render according to the status. By the way, we also see the trigger mechanism of two important callback events, preRender and postUpdate.
Call -- from top to bottom
- We can see the whole calling process through the above three source code fragments. Let's connect the code logic step by step
- 1. Initialize scene
var viewer = new Viewer("cesiumContainer", { imageryProvider: imageryProvider, baseLayerPicker: hasBaseLayerPicker, scene3DOnly: endUserOptions.scene3DOnly, requestRenderMode: true, });
- 2. What does the new Viewer() do?
function Viewer(container, options) { ...//ellipsis // Cesium widget var cesiumWidget = new CesiumWidget();
- 3. It can be seen that its core is to initialize the CesiumWidget. What does new CesiumWidget() do?
function CesiumWidget(container, options) { ...//ellipsis var scene = new Scene(); this._scene = scene; this._screenSpaceEventHandler = new ScreenSpaceEventHandler(canvas); this._useDefaultRenderLoop = undefined; this.useDefaultRenderLoop = defaultValue( options.useDefaultRenderLoop, true ); ...//ellipsis }
- 4. You can see that it also the new Scene() object, and then set the useDefaultRenderLoop property to true. This simple sentence is very important because it is the beginning of the whole call loop. This operation will trigger the following code
useDefaultRenderLoop: { get: function () { return this._useDefaultRenderLoop; }, set: function (value) { if (this._useDefaultRenderLoop !== value) { this._useDefaultRenderLoop = value; if (value && !this._renderLoopRunning) { startRenderLoop(this); } } }, }, }
- 5. The code of the startRenderLoop function is as follows
function startRenderLoop(widget) { widget._renderLoopRunning = true; var lastFrameTime = 0; function render(frameTime) { ...//ellipsis widget.resize(); widget.render(); requestAnimationFrame(render); } requestAnimationFrame(render); }
- 6. From this code, we can see that it calls the requestAnimationFrame function, and then executes the widget.render() function again and again. The code is as follows
CesiumWidget.prototype.render = function () { if (this._canRender) { this._scene.initializeFrame(); var currentTime = this._clock.tick(); this._scene.render(currentTime); } else { this._clock.tick(); } };
- 7. It can be seen from this code that it calls the scene.render() function to render the whole scene primitive, and also calls the clock.tick() function to execute all the subscribed functions of onTick.
Review -- Summary and sorting
- Initialize the Viewer object first
- Reinitialize the CesiumWidget object
- Trigger the requestAnimationFrame function through the useDefaultRenderLoop property
- Trigger the widget.render() function through the requestAnimationFrame function
- Trigger the scene.render and clock.tick() functions through the widget.render() function
- After completion, repeat 4 and 5 steps
More - join us
- Here is a place to explain. Due to the limited space and time, I didn't write all the code. Here are the main implementation ideas
- If there's anything else you don't know
- If you still need cesium communication
- Let's study together
- You can join our base. The address of our base is 450342630 (QQ group number)