在上一篇博文中,我们模拟了绘制太阳的方法,为地球添加了赤道平面, 美中不足的是,轨道平面常会被地球给挡住。下面我们详细分析scene的调度机制。
先看一下这个结构,Cesium把绘制命令(DrawCommand)分成不同的PASS, 处在不同PASS的对象,他们的绘制循序也不相同,这个跟osg里面的RenderBin的概念非常类似。
var Pass = {
// If you add/modify/remove Pass constants, also change the automatic GLSL constants
// that start with 'czm_pass'
//
// Commands are executed in order by pass up to the translucent pass.
// Translucent geometry needs special handling (sorting/OIT). The compute pass
// is executed first and the overlay pass is executed last. Both are not sorted
// by frustum.
ENVIRONMENT: 0,
COMPUTE: 1,
GLOBE: 2,
TERRAIN_CLASSIFICATION: 3,
CESIUM_3D_TILE: 4,
CESIUM_3D_TILE_CLASSIFICATION: 5,
CESIUM_3D_TILE_CLASSIFICATION_IGNORE_SHOW: 6,
OPAQUE: 7,
TRANSLUCENT: 8,
OVERLAY: 9,
NUMBER_OF_PASSES: 10,
};
function executeCommands(scene, passState) {
var camera = scene.camera;
var context = scene.context;
var frameState = scene.frameState;
var us = context.uniformState;
us.updateCamera(camera);
executeCommand是场景调度的核心函数, 对所有的commands进行管理和调度。
// Create a working frustum from the original camera frustum.
var frustum;
if (defined(camera.frustum.fov)) {
frustum = camera.frustum.clone(scratchPerspectiveFrustum);
} else if (defined(camera.frustum.infiniteProjectionMatrix)) {
frustum = camera.frustum.clone(scratchPerspectiveOffCenterFrustum);
} else if (defined(camera.frustum.width)) {
frustum = camera.frustum.clone(scratchOrthographicFrustum);
} else {
frustum = camera.frustum.clone(scratchOrthographicOffCenterFrustum);
}
上面的代码中对视锥进行赋值,为什么会有三种类型的视锥?他们有何区别? 这里我们先留下这个疑问。继续往下走代码
for (var i = 0; i < numFrustums; ++i) {
var index = numFrustums - i - 1;
var frustumCommands = frustumCommandsList[index];
if (scene.mode === SceneMode.SCENE2D) {
// To avoid z-fighting in 2D, move the camera to just before the frustum
// and scale the frustum depth to be in [1.0, nearToFarDistance2D].
camera.position.z = height2D - frustumCommands.near + 1.0;
frustum.far = Math.max(1.0, frustumCommands.far - frustumCommands.near);
frustum.near = 1.0;
us.update(frameState);
us.updateFrustum(frustum);
} else {
// Avoid tearing artifacts between adjacent frustums in the opaque passes
frustum.near =
index !== 0 ?
frustumCommands.near * scene.opaqueFrustumNearOffset :
frustumCommands.near;
frustum.far = frustumCommands.far;
us.updateFrustum(frustum);
}
...
}
主要的内容都在这个大循环里面,针对每个视锥体做绘制。总体的流程
Frustum|------pass0|---- command0
| |-----command1
| |-----command 2
|------pass1|-----command0
| |-----command1
| |-----command2
下面开始分析这个大循环里面的东西:
clearDepth.execute(context, passState);
if (context.stencilBuffer) {
clearStencil.execute(context, passState);
}
us.updatePass(Pass.GLOBE);
var commands = frustumCommands.commands[Pass.GLOBE];
var length = frustumCommands.indices[Pass.GLOBE];
......
for (j = 0; j < length; ++j) {
executeCommand(commands[j], scene, context, passState);
}
开始Pass.GLOBE的绘制,在这之前,先执行了clearDepth, clearStencil命令。然后执行了所有的属于改Pass的绘制命令。