Cesium高级教程-反射水面-使用反射相机进行离屏渲染
应用反射相机
前面一节我们验证了创建的反射相机,这一节我们使用反射相机进行离屏渲染
,关于离屏渲染
的知识可以参见离屏渲染
相关章节。我们将离屏渲染封装成一个方法renderToFboByReflectCamera
。
function renderToFboByReflectCamera(fbo, scene, reflectCamera) {
...
const us = context.uniformState;
const view = scene._defaultView;
scene._view = view;
scene.updateFrameState();
frameState.passes.render = true;
frameState.passes.postProcess = scene.postProcessStages.hasSelected;
frameState.tilesetPassState = renderTilesetPassState;
let backgroundColor = Cesium.defaultValue(scene.backgroundColor, Cesium.Color.BLACK);
if (scene._hdr) {
backgroundColor = Cesium.Color.clone(backgroundColor, scratchBackgroundColor);
backgroundColor.red = Cesium.Math.pow(backgroundColor.red, scene.gamma);
backgroundColor.green = Cesium.Math.pow(backgroundColor.green, scene.gamma);
backgroundColor.blue = Cesium.Math.pow(backgroundColor.blue, scene.gamma);
}
frameState.backgroundColor = backgroundColor;
frameState.atmosphere = scene.atmosphere;
//scene.fog.update(frameState);
us.update(frameState);
// const shadowMap = scene.shadowMap;
// if (Cesium.defined(shadowMap) && shadowMap.enabled) {
// if (!Cesium.defined(scene.light) || scene.light instanceof SunLight) {
// // Negate the sun direction so that it is from the Sun, not to the Sun
// Cesium.Cartesian3.negate(us.sunDirectionWC, scene._shadowMapCamera.direction);
// } else {
// Cesium.Cartesian3.clone(scene.light.direction, scene._shadowMapCamera.direction);
// }
// frameState.shadowMaps.push(shadowMap);
// }
scene._computeCommandList.length = 0;
scene._overlayCommandList.length = 0;
const viewport = view.viewport;
viewport.x = 0;
viewport.y = 0;
viewport.width = context.drawingBufferWidth;
viewport.height = context.drawingBufferHeight;
const passState = view.passState;
passState.framebuffer = fbo;
passState.blendingEnabled = undefined;
passState.scissorTest = undefined;
passState.viewport = Cesium.BoundingRectangle.clone(viewport, passState.viewport);
// if (Cesium.defined(scene.globe)) {
// scene.globe.beginFrame(frameState);
// }
scene.updateEnvironment();
scene.updateAndExecuteCommands(passState, backgroundColor);
scene.resolveFramebuffers(passState);
passState.framebuffer = undefined;
//executeOverlayCommands(scene, passState);
// if (Cesium.defined(scene.globe)) {
// scene.globe.endFrame(frameState);
// if (!scene.globe.tilesLoaded) {
// scene._renderRequested = true;
// }
// }
context.endFrame();
scene.globe.show = true;
scene._defaultView.camera = camera;
}
离屏渲染的方法中,我们隐藏了地球,并注释了一些不需要的渲染。
创建FBO
离屏渲染
方法需要传入对应的FBO
,所以我们先创建一个FBO
function createFrameBuffer(context) {
let width = context.drawingBufferWidth;
let height = context.drawingBufferHeight;
let framebuffer = new Cesium.Framebuffer({
context: context,
colorTextures: [
new Cesium.Texture({
context: context,
width: width,
height: height,
pixelFormat: Cesium.PixelFormat.RGBA,
}),
],
});
return framebuffer;
}
创建FBO
并调用封装的离屏渲染
方法,将FBO
对象作为参数传入方法中
let fbo = createFrameBuffer(viewer.scene.context);
renderToFboByReflectCamera(fbo, viewer.scene, reflectCamera);
此时渲染结果已经存储到FBO
对象中,我们可以按照离屏渲染
章节中的方法将其可视化出来
let width = viewer.scene.context.drawingBufferWidth;
let height = viewer.scene.context.drawingBufferHeight;
let pixels = viewer.scene.context.readPixels({
x: 0,
y: 0,
width: width,
height: height,
framebuffer: fbo,
});
let cavs = document.getElementById("canvas");
cavs.width = width;
cavs.height = height;
let imgData = new ImageData(new Uint8ClampedArray(pixels), width, height);
let ctx = cavs.getContext("2d");
ctx.putImageData(imgData, 0, 0, 0, 0, width, height);
ctx.translate(0, height);
ctx.scale(1, -1);
ctx.drawImage(cavs, 0, 0);
cavs.style.height = (height * 0.3) + "px";
cavs.style.width = (width * 0.3) + "px";
示例效果可到 xt3d 官网 运行查看
结果如上图所示,抛开细节不谈,我们可以看到结果大概是正确的,不过好像左右是反的,这是正常的,因为反射是从底下往上看那肯定是反的。
更多内容见 Cesium高级教程-教程简介