Cesium进阶教程(3)后处理绘制图形

Cesium后处理绘制图形技术解析

 免费领取更多GIS开发学习资料点击这里

往期内容:

Cesium进阶教程(1)customShader的使用

Cesium进阶教程(2)线性高度雾

基础理论

后期处理Post Processing

概念

在计算机图形学和图像处理领域,后期处理(Post Processing)是指对生成的图像或视频进行进一步处理、增强或修改的过程,以改善视觉效果或实现特定的艺术目标。

它通常发生在图像或视频生成后的阶段。

包含哪些操作

  • 视觉增强 (调整颜色、对比度、饱和度)
  • 错误修正(P 图,去除噪点、减少图像模糊或消除色彩偏差来纠正图像中的问题)
  • 特效添加 (模糊、景深、光晕、色调映射)
  • 艺术创作(滤镜、调整色彩和形态)
  • 细节增强(锐化、增加局部对比度)
  • 格式转换 (将图像或视频转换为不同的格式或尺寸,以适应不同的应用和平台要求)

cesium中使用后处理

cesium中封装了几个核心类,专门用于后处理的效果,其中我们着重需要了解PostProcessStage和

PostProcessStageLibary这两个类
PostProcessStage

根据当前场景渲染输出的纹理(或者紧随上一个 Post Processing 后期处理阶段),来进行一个(新)的 Post Processing 后期处理。

可以将整个cesium场景想象为一块大的画布,后处理允许我们在这个大画布上使用shader去自己完成一些效果

比如,我们可以让整个场景变得更亮一些

我们使用PostProcessStage这个api,可以自定义后处理效果

简单介绍一下cesium中对于glsl的编译环境

在后处理中,cesium会为我们提供colorTexture,当前视图的图片资源

v_textureCoordinates,当前渲染的像素坐标

iTime,一个随帧数不断增大的值

// Simple stage to change the color
const fs =`
    uniform sampler2D colorTexture;
		uniform sampler2D depthTexture;
    varying vec2 v_textureCoordinates;
    uniform float scale;
    uniform vec3 offset;
    void main() {
        vec4 color = texture2D(colorTexture, v_textureCoordinates);
        gl_FragColor = vec4(color.rgb * scale + offset, 1.0);
    }`;
  1. colorTexture

颜色纹理图,即场景渲染的结果,或者上一个后处理的结果(如果使用postProcessStageComposite的话)。

  1. depthTexture

深度纹理图,即场景深度图,存储了每个像素的深度(可以还原为像素到相机的距离)

  1. v_textureCoordinates

纹理坐标,纹理坐标的范围为(0,0)-(1,1)

一般会使用颜色采样器,从颜色纹理中获取到当前场景的颜色

texture2D(colorTexture, v_textureCoordinates);

还可以通过深度纹理,获取到像素到相机的距离

float getDistance(sampler2D depthTexture, vec2 texCoords)
{
	float depth = czm_unpackDepth(texture(depthTexture, texCoords));
	vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
	return -eyeCoordinate.z / eyeCoordinate.w;
}

现在分析一下Cesium中获取片元到相机距离的思路

  1. 使用czm_unpackDepth将打包的深度值转为原始的浮点深度值
  2. czm_windowToEyeCoordinates能够将屏幕像素坐标结合深度值转为相机坐标系下的坐标
  3. 由于相机坐标系是左手坐标系,最终结果需要取反,其中w是齐次坐标,在透视投影中,w分量通常表示深度信息,w分量越大,看起来越小,所以这里为了得到准确的坐标值,需要使用齐次坐标到笛卡尔坐标的转换公式,这样得到的坐标信息能够正确反映深度和位置
eyeCoordinate.xyz / eyeCoordinate.w

上一节中我们知道如何通过深度图获取深度值,并且将其转为了眼睛坐标,Cesium还提供了czm_inverseView这个内置函数,将眼睛坐标转到世界坐标

vec3 getWorldCoordinate(sampler2D depthTexture, vec2 texCoords)
{
	  float depth =czm_unpackDepth(texture(depthTexture, v_textureCoordinates));
    vec4 eyeCoordinate4 = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
    vec3 eyeCoordinate3 = eyeCoordinate4.xyz/eyeCoordinate4.w;
    vec4 worldCoordinate4 = czm_inverseView * vec4(eyeCoordinate3,1.) ;
    vec3 worldCoordinate = worldCoordinate4.xyz / worldCoordinate4.w;
	  return worldCoordinate;
}

我们可以用代码验证一下

限制后处理范围为地球

深度值如果>1的话,说明片元不在地球上

uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
varying vec2 v_textureCoordinates;
void main(void) {
    gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
    float depth = czm_unpackDepth(texture2D(depthTexture, v_textureCoordinates));
    vec4 eyeCoordinate4 = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
    vec3 eyeCoordinate3 = eyeCoordinate4.xyz / eyeCoordinate4.w;
    vec4 worldCoordinate4 = czm_inverseView * vec4(eyeCoordinate3, 1.);
    vec3 worldCoordinate = worldCoordinate4.xyz / worldCoordinate4.w;
    if(depth>=1.0){
        return;
    }
    if(worldCoordinate.z < 0.) {
        gl_FragColor.r = 1.;
    } else {
        gl_FragColor.g = 1.;
    }
}

我们可以通过shader中的一个概念,有向距离场SDF来规定后处理的范围

SDF函数,中文译作“符号距离函数”,它用于描述这么一个函数:它将空间里的一个位置作为输入,并返回该位置到给定形状的距离,它的前面还有个“符号”,是因为在形状外的距离为正数(“+”号),在形状内的距离为负数(“-”号),边界处的值恰好为 0。

图形学大咖 Inigo Quilez(后文简称 iq)的博客上有篇文章把常用的2D图形的SDF函数都列了出来,如果有需要可以随时查阅,点我直达文章

也就是说,想要在shader中绘制图形,我们只需要得到一个sdf函数,然后通过片元到中心点的距离,就可以判断哪些片元是在图形内的,哪些片元是不在的

可以看一下这个shaderToy案例,理解sdf函数的意义:https://www.shadertoy.com/view/XsjGDt

在本例中,和shaderToy中的区别就在于坐标,shaderToy中是平面的,所以通过uv坐标结合center来判断图形

本例中,我们可以通过uniform传入一个center(笛卡尔坐标),然后结合sdf函数,确定绘制范围

uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
uniform vec3 center;
uniform float radius;
varying vec2 v_textureCoordinates;

float sdCircle(vec3 center, vec3 worldCoordinate, float r) {
    // distance可以判断两个点之间的距离
    return distance(center, worldCoordinate) - r;
}

void main(void) {
    gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
    float depth = czm_unpackDepth(texture2D(depthTexture, v_textureCoordinates));
    vec4 eyeCoordinate4 = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
    vec3 eyeCoordinate3 = eyeCoordinate4.xyz / eyeCoordinate4.w;
    vec4 worldCoordinate4 = czm_inverseView * vec4(eyeCoordinate3, 1.);
    vec3 worldCoordinate = worldCoordinate4.xyz / worldCoordinate4.w;
    float d = sdCircle(center, worldCoordinate, radius);
    if(d < 0.0) {
        gl_FragColor.r = 1.;
    }
}

限制后处理范围为矩形

同理,我们可以从iq大神的博客中找到矩形的sdf函数

float sdBox(in vec2 p,in vec2 b)
{
    vec2 d=abs(p)-b;
    return length(max(d,0.))+min(max(d.x,d.y),0.);
}

这里注意,sdf函数传入的p是当前片元的二维坐标,但是我们这里只有世界坐标,所以我们需要基于中心点,将三维的笛卡尔坐标转到模型坐标系下,再将模型坐标进行俯视,转为二维平面坐标

// ------------------------画矩形------------------------
let m = Cesium.Transforms.eastNorthUpToFixedFrame(destination);
let inverse = Cesium.Matrix4.inverse(m, new Cesium.Matrix4());

将逆矩阵*世界坐标=模型坐标,取模型坐标的xy,得到平面坐标,调用sdf函数,判断距离,显示图形

uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
uniform vec3 center;
uniform float radius;
uniform mat4 inverse;
varying vec2 v_textureCoordinates;

float sdBox(in vec2 p,in vec2 b)
{
    vec2 d=abs(p)-b;
    return length(max(d,0.))+min(max(d.x,d.y),0.);
}

void main(void) {
    gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
    float depth = czm_unpackDepth(texture2D(depthTexture, v_textureCoordinates));
    vec4 eyeCoordinate4 = czm_windowToEyeCoordinates(gl_FragCoord.xy, depth);
    vec3 eyeCoordinate3 = eyeCoordinate4.xyz / eyeCoordinate4.w;
    vec4 worldCoordinate4 = czm_inverseView * vec4(eyeCoordinate3, 1.);
    vec3 worldCoordinate = worldCoordinate4.xyz / worldCoordinate4.w;
    // 由于shaderToy中的sdf都是二维基于uv坐标的,所以我们需要将世界坐标转到模型坐标,再转二维
    vec3 modelCoordinate = (inverse * vec4(worldCoordinate, 1.)).xyz;
    float d=sdBox(modelCoordinate.xy,vec2(1000.,1000.));
    if(d<0.){
        gl_FragColor.r=1.;
    }
}

看不明白没关系,需要上述视频教程+源码

+下方↓↓小助手【cesium进阶】无偿获取

内容概要:本文介绍了基于贝叶斯优化的CNN-LSTM混合神经网络在时间序列预测中的应用,并提供了完整的Matlab代码实现。该模型结合了卷积神经网络(CNN)在特征提取方面的优势与长短期记忆网络(LSTM)在处理时序依赖问题上的强大能力,形成一种高效的混合预测架构。通过贝叶斯优化算法自动调参,提升了模型的预测精度与泛化能力,适用于风电、光伏、负荷、交通流等多种复杂非线性系统的预测任务。文中还展示了模型训练流程、参数优化机制及实际预测效果分析,突出其在科研与工程应用中的实用性。; 适合人群:具备一定机器学习基基于贝叶斯优化CNN-LSTM混合神经网络预测(Matlab代码实现)础和Matlab编程经验的高校研究生、科研人员及从事预测建模的工程技术人员,尤其适合关注深度学习与智能优化算法结合应用的研究者。; 使用场景及目标:①解决各类时间序列预测问题,如能源出力预测、电力负荷预测、环境数据预测等;②学习如何将CNN-LSTM模型与贝叶斯优化相结合,提升模型性能;③掌握Matlab环境下深度学习模型搭建与超参数自动优化的技术路线。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,重点关注贝叶斯优化模块与混合神经网络结构的设计逻辑,通过调整数据集和参数加深对模型工作机制的理解,同时可将其框架迁移至其他预测场景中验证效果。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值