一直 觉得人家都有自己的博客好酷啊
自己也想写一个
那就从CESIUM的离屏渲染开始吧
其实这个功能一直想做了 对于测试深度图的正确性来说应该是很有用的
而且也很酷嘛 查了很久网上好像也没有什么公开的代码 我来试试吧
首先在html界面设置一个固定在右下角的canvas用来显示渲染结果
我前端基础不是很好 目前就是主打一个凑合着用
<style>
#outputCanvas {
position: absolute;
width: 20%;
height: 20%;
bottom: 0;
right: 0;
z-index: 999;
background: black;
border: solid blue 1px;
}
</style>
<canvas id="outputCanvas"></canvas>
初始化Cesium 加载3Dtiles模型这些步骤就略过吧
直接进入到渲染阶段
首先是深度图的获取问题 后处理阶段会自己有一个深度图 但是不知道到底是怎么获取的
一直很好奇 网上很多关于CESIUM获取当前场景深度图的问题都是没有答案
Cesium好像也没有什么公开的接口让人拿到他的深度图
只能自己想办法拿 感觉从后处理渲染结果拿是一个方法 但总感觉很蠢
明明已经有深度图了 想办法拿到就行
获取深度图的代码某些原因不能分享 说一下大概思路吧
直接拿cesium底层的DrawCommand命令 自己新建一个FBO缓存区
执行这个渲染命令 把结果存到FBO中
就拿到了当前场景的深度图
不过这个深度图 和当前视椎体挂钩 很多时候并不是那么的直观 还需要研究
拿到的深度图是存在FBO中的 要把这个FBO输出到Canvas中
function saveTextureToImage(framebuffer,texture) {
const context = viewer.scene.context;
// Create a framebuffer to read texture
// Create a canvas
const canvas = document.getElementById('outputCanvas');
canvas.width = texture.width;
canvas.height = texture.height;
const width=texture.width;
const height=texture.height;
const context2d = canvas.getContext('2d');
const imageData = context2d.createImageData(texture.width, texture.height);
// Read pixels from framebuffer
var pixels = viewer.scene.context.readPixels({
x: 0,
y: 0,
width: width,
height: height,
framebuffer: framebuffer,
});
let imgData = new ImageData(new Uint8ClampedArray(pixels), width, height);
let flippedImgData = new ImageData(width, height);
// 遍历原始图像数据,按照上下翻转的方式将像素值填充到新的 ImageData 对象中
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
// 计算原始图像数据和翻转后图像数据的索引
let originalIndex = (y * width + x) * 4;
let flippedIndex = ((height - 1 - y) * width + x) * 4;
// 将原始图像数据的像素值填充到翻转后图像数据中
flippedImgData.data[flippedIndex] = imgData.data[originalIndex];
flippedImgData.data[flippedIndex + 1] = imgData.data[originalIndex + 1];
flippedImgData.data[flippedIndex + 2] = imgData.data[originalIndex + 2];
flippedImgData.data[flippedIndex + 3] = imgData.data[originalIndex + 3];
}
}
for (let i = 0; i < flippedImgData.data.length; i += 4) {
let gray = 0.299 * flippedImgData.data[i] + 0.587 * flippedImgData.data[i + 1] + 0.114 * flippedImgData.data[i + 2];
flippedImgData.data[i] = gray;
flippedImgData.data[i + 1] = gray;
flippedImgData.data[i + 2] = gray;
}
// 绘制翻转后的图像数据到画布上
context2d.putImageData(flippedImgData, 0, 0);
// Draw the image data to the canvas
// Export the canvas to an image
// Open a new window/tab and display the image
// Cleanup
framebuffer.destroy();
}
这样深度图就画在画布上了
下一步要考虑的是什么时候画的问题 首先想到的是放到渲染循环里 每渲染一帧 canvas对应更新
在3dtiles加载完成后的事件里增加渲染循环事件
success:function(data){
let mainJson= eval(data);//解析json对象
for(let i=0;i<mainJson.RECORDS.length;i++){
// for(let i=0;i<1;i++){
let m=addTileset(mainJson.RECORDS[i].ModelUrl);
viewer.zoomTo(m);
viewer.scene.preRender .addEventListener(() => {
//console.log('postRender')
let result=getDepth();
saveTextureToImage(result.framebuffer,result.Texture)
})
这样结果确实是出来了 但是帧数很低 展示一部分截图 帧数太低了 而且深度图不稳定
FPS=FPS+1
if(FPS%10==0)
{
let result=getDepth();
saveTextureToImage(result.framebuffer,result.Texture)
}
统计帧数并每十帧刷新一次 帧数提高很多 但感觉不是治本之策
既然他每一帧都会获取 我只是额外获取一下 为什么会这么影响帧数 难道没有办法直接拿到那个深度图吗 而且这个深度只有平视的时候能看见 俯视的时候就没了 很奇怪的
更改渲染命令中片元着色器的部分 不用cesium的打包 直接输出为rgb值
显示效果更好
`#version 300 es
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
precision highp int;
#else
precision mediump float;
precision mediump int;
#define highp mediump
#endif
#define OES_texture_float_linear
#define OES_texture_float
#line 0
layout(location = 0) out vec4 out_FragColor;
vec4 czm_packDepth(float depth)
{
vec4 enc = vec4(1.0, 255.0, 65025.0, 16581375.0) * depth;
enc = fract(enc);
enc -= enc.yzww * vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 0.0);
return enc;
}
#line 0
uniform highp sampler2D u_depthTexture;
in vec2 v_textureCoordinates;
void main()
{
float z=texture(u_depthTexture, v_textureCoordinates).r;
out_FragColor =vec4(z,z,z,1.0);
}`
另外 开启对数深度的情况下深度图的获取更加稳定 原因不知道
最终效果如下:
但是这里用的是同一个摄像机视角 我以为并不能叫真正的离屏渲染
后续要研究不同视角的离屏 渲染 已经cesium 的深度图 一些技术
先到这吧
第一篇博客 不清楚的地方请见谅
主要是我也查了很多 国内外论坛上关于这个的讨论很少
要不就是语焉不详的 不喜欢这样 写一篇 也算记录一下
看到很多大佬写的博客 很羡慕他们那么知识渊博 好像啥都懂
希望大家都早日能成为大牛
祝好