前面幾節的例子是將Cesium默認的相機渲染到紋理(RTT)或Canvas,這片文章講解如何將自定義的一個camera的畫面渲染到Canvas上,有了前面幾篇的基礎了,也能將自定義的畫面渲染紋理、也可以灰度處理,原理是一樣的。
一、效果
左上一是渲染到Canvas(灰度處理)的畫面,右上一是渲染到Canvas正常畫面,左下一是渲染到紋理的畫面,右下一是自定義的camera視錐體。
二、實現
實現的原理還是基于第一篇的闡述的原理,主要分為以下步驟:
1.創建FBO
2.創建相機
3.將相機內容渲染到FBO
4.將FBO繪制到Canvas
通過前面幾篇文章的講解,其中1、4環節我們已經很熟悉了,這里說明一下2和3。
1)創建相機
createFboCamera(scene) {let camera = new Cesium.Camera(scene);camera.setView({destination: Cesium.Cartesian3.fromDegrees(126.30158892175582, 35.02368795804565, 200000),orientation: {heading: Cesium.Math.toRadians(0.0), // 航向角,轉換為弧度pitch: Cesium.Math.toRadians(-45), // 俯仰角,轉換為弧度 roll: Cesium.Math.toRadians(0.0), // 翻滾角,轉換為弧度}})//這里采用透視投影camera.frustum = new Cesium.PerspectiveFrustum({fov: Cesium.Math.toRadians(60), // 視場角aspectRatio: 1, // 寬高比near: 1, // 近裁剪面far: 500000 // 遠裁剪面});let primitive = new Cesium.DebugCameraPrimitive({camera: camera,color: Cesium.Color.RED,show: true,});scene.primitives.add(primitive);return camera;}
2)將相機內容渲染到FBO
核心的思路是將場景默認的相機替換成自定義的相機,等渲染完成后再替換回來。主場景已經有一個事件循序在渲染了,我們再加一個勢必會影響到性能。
cameraRenderToFbo(fbo, scene, fboCamera) {// 保存原始相機,并將fbo相機設置為當前相機let camera = scene._defaultView.camera;scene._defaultView.camera = fboCamera;// 獲取場景的幀狀態、WebGL上下文和uniform狀態const frameState = scene._frameState;const context = scene.context;const us = context.uniformState;// 設置默認視圖const view = scene._defaultView;scene._view = view;// 更新場景幀狀態scene.updateFrameState();// 設置3DTiles渲染通道狀態const renderTilesetPassState = Cesium.Cesium3DTilePass.getPassOptions(Cesium.Cesium3DTilePass.RENDER);frameState.passes.render = true;frameState.passes.postProcess = scene.postProcessStages.hasSelected;frameState.tilesetPassState = renderTilesetPassState;// 設置背景顏色,如果不是HDR模式需要進行gamma校正let backgroundColor = Cesium.defaultValue(scene.backgroundColor, Cesium.Color.BLACK);let scratchBackgroundColor = new Cesium.Color();if (!scene._hdr) {backgroundColor = Cesium.Color.clone(backgroundColor, scratchBackgroundColor);backgroundColor.red = Math.pow(backgroundColor.red, scene.gamma);backgroundColor.green = Math.pow(backgroundColor.green, scene.gamma);backgroundColor.blue = Math.pow(backgroundColor.blue, scene.gamma);}frameState.backgroundColor = backgroundColor;// 更新大氣和霧效果frameState.atmosphere = scene.atmosphere;scene.fog.update(frameState);// 更新uniform狀態us.update(frameState);// 處理陰影貼圖const shadowMap = scene.shadowMap;if (Cesium.defined(shadowMap) && shadowMap.enabled) {if (!Cesium.defined(scene.light) || scene.light instanceof Cesium.SunLight) {// 將太陽方向取反,使其從太陽射向場景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);// 更新并執行渲染scene.updateEnvironment();scene.updateAndExecuteCommands(passState, backgroundColor);scene.resolveFramebuffers(passState);// 清理狀態passState.framebuffer = undefined;context.endFrame();// 恢復原始相機和地球顯示scene._defaultView.camera = camera;scene.globe.show = true;}
?好啦,關于Cesium的FBO的話題暫時搞一段了,請各位老鐵點個贊,評個論啥的,感謝。