一、简介
离屏渲染 顾名思义就是离开屏幕的渲染,就是说场景的渲染结果不直接显示到屏幕上,而是作为纹理使用或者需要经过一些加工后再显示到屏幕上。WebGL编程指南可查详细解释(帧缓冲区对象 可以用来代替颜色缓冲区或深度缓冲区。绘制在帧缓冲区的对象并不会直接显示在canvas上,你可以先对帧缓冲区的内容进行一些处理再显示,或者直接用其中的内容作为纹理图像。在帧缓冲区中进行绘制的过程又称为离屏绘制。)
二、Cesium中的离屏渲染示例
Cesium是基于WebGL封装的,所以Cesium的离屏渲染也就是WebGL的离屏渲染,即通过帧缓冲区对象来实现,webgl中通过gl.createFramebuffer()来创建帧缓冲区对象,Cesium的渲染模块将对原生webgl的帧缓冲区相关的操作封装到了FrameBuffer类中。
如果您了解Ceisum的渲染流程或者观看过前一章节“Cesium绘制渲染流程”您就会知道Cesium默认的绘制就是使用的离屏渲染,先将场景渲染到到合适的FrameBuffer中,然后交交给后处理程序,最后才会显示到屏幕上。
Scene.prototype.resolveFramebuffers = function (passState) {
...
if (usePostProcess) {
view.sceneFramebuffer.prepareColorTextures(context);
let inputFramebuffer = sceneFramebuffer;
if (useGlobeDepthFramebuffer && !useOIT) {
inputFramebuffer = globeFramebuffer;
}
const postProcess = this.postProcessStages;
const colorTexture = inputFramebuffer.getColorTexture(0);
const idTexture = idFramebuffer.getColorTexture(0);
const depthTexture = defaultValue(
globeFramebuffer,
sceneFramebuffer
).getDepthStencilTexture();
postProcess.execute(context, colorTexture, depthTexture, idTexture);
postProcess.copy(context, defaultFramebuffer);
}
...
}
1、Cesium中离屏渲染应用之Picking类:要使用Cesium的离屏渲染,我们还可以先参考Cesium对场景拾取类Picking的封装,Picking类主要封装了场景中拾取的相关方法,比如鼠标点击拾取位置、鼠标点击拾取对象,我们在使用时是通过scene.pickPosition()、scene.pick(),但其实内部都是通过Picking类来实现的。
/**
* Returns an object with a <code>primitive</code> property that contains the first (top) primitive in the scene
* at a particular window coordinate or undefined if nothing is at the location. Other properties may
* potentially be set depending on the type of primitive and may be used to further identify the picked object.
* <p>
* When a feature of a 3D Tiles tileset is picked, <code>pick</code> returns a {@link Cesium3DTileFeature} object.
* </p>
* @param {Scene} scene
* @param {Cartesian2} windowPosition Window coordinates to perform picking on.
* @param {number} [width=3] Width of the pick rectangle.
* @param {number} [height=3] Height of the pick rectangle.
* @returns {object} Object containing the picked primitive.
*/
Picking.prototype.pick = function (scene, windowPosition, width, height) {
...
};
/**
* Returns an object with information about the voxel sample rendered at
* a particular window coordinate. Returns <code>undefined</code> if there is no
* voxel at that position.
*
* @param {Scene} scene
* @param {Cartesian2} windowPosition Window coordinates to perform picking on.
* @param {number} [width=3] Width of the pick rectangle.
* @param {number} [height=3] Height of the pick rectangle.
* @returns {object|undefined} Object containing the picked primitive.
*/
Picking.prototype.pickVoxelCoordinate = function (
scene,
windowPosition,
width,
height
) {
...
};
Picking.prototype.pickPositionWorldCoordinates = function (
scene,
windowPosition,
result
) {
...
};
Picking.prototype.pickPosition = function (scene, windowPosition, result) {
...
};
2、我们可以重点看一下pick方法的实现
Picking.prototype.pick = function (scene, windowPosition, width, height) {
//>>includeStart('debug', pragmas.debug);
Check.defined("windowPosition", windowPosition);
//>>includeEnd('debug');
scratchRectangleWidth = defaultValue(width, 3.0);
scratchRectangleHeight = defaultValue(height, scratchRectangleWidth);
const {
context, frameState, defaultView } = scene;
const {
viewport, pickFramebuffer } = defaultView;
scene.view = defaultView;
viewport.x = 0;
viewport.y = 0;
viewport.width = context.drawingBufferWidth;
viewport.height = context.drawingBufferHeight;
let passState = defaultView.passState;
passState.viewport = BoundingRectangle.clone(viewport, passState.viewport);
const drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(
scene,
windowPosition,
scratchPosition
)