Cesium 模拟气象之下雨天

1,248 阅读3分钟

前言

人生一迹,谨以此记录地图相关系列知识

问题背景:解决Cesium中气象环境模拟模型!

在许多应用场景中,气象环境模拟是极其关键的一部分。Cesium提供了强大的三维地球渲染和可视化工具,但在气象环境模拟方面却相对较弱。如何在Cesium中构建一个真实可靠的气象环境模型,以满足更复杂的场景需求,是当前的挑战。这种模型需要考虑到各种各样的气候和环境因素,比如热量传递、湿度变化、风向风速、云层移动等。因此,我们需要深入研究如何在Cesium中开发一个强大、准确且动态的气象环境模拟模型,以便为更广泛的应用场景提供强大的支持。

recording.gif

一、雨着色器代码(GLSL)

雨着色器代码是用于模拟下雨效果的图形渲染代码,通常使用OpenGL Shading Language (GLSL)来实现。GLSL是一种高级着色语言,专门用于编写可在GPU上并行执行的小程序,称为"着色器"。

	uniform sampler2D colorTexture;
	varying vec2 v_textureCoordinates;

	float hash(float x){
		return fract(sin(x*133.3)*13.13);
	}

	void main(void){ 
		float time = czm_frameNumber / 60.0;
		vec2 resolution = czm_viewport.zw;

		vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);
		vec3 c=vec3(.6,.7,.8);

		float a= -.4;
		float si=sin(a),co=cos(a);
		uv*=mat2(co,-si,si,co);
		uv*=length(uv+vec2(0,4.9))*.3+1.;

		float v=1.-sin(hash(floor(uv.x*100.))*2.);
		float b=clamp(abs(sin(20.*time*v+uv.y*(5./(2.+v))))-.95,0.,1.)*20.;
		c*=v*b; 

		gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(c,1), 0.5);  
	} 

二、Cesium加载着色器代码

在Cesium中,PostProcessStage类用于执行后处理操作,这些操作在场景已经被渲染到帧缓冲区之后进行,如镜头效果、边缘检测等。一般来说,后处理可以用来改变最终呈现图像的整体外观。

其中,我们常见的着色器通常应用于单个模型或者特定的几何体上,而后处理着色器则是直接作用于整个场景的渲染结果上。因此,后处理着色器通常用于实现全局的视觉效果,比如雾、深度感、暗角、对比度增强等。

let rain = new Cesium.PostProcessStage({
		fragmentShader: rainFS
	});
<!-- 加载雨着色器代码 -->
viewer.scene.postProcessStages.add(rain);
<!-- 卸载雨着色器代码 -->
viewer.scene.postProcessStages.remove(rain);

三、全部代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Cesium 气象状态 下雨天</title>
    <!-- <link rel="stylesheet" href="./CesiumUnminified/Widgets/widgets.css">
    <script type="text/javascript" src="./CesiumUnminified/Cesium.js"></script> -->
    <link rel="stylesheet" href="./Cesium/Widgets/widgets.css">
    <script type="text/javascript" src="./Cesium/Cesium.js"></script>
  </head>
  <body>
    <div id="cesiumContainer"></div>
    <script type="text/javascript">
      let viewer = new Cesium.Viewer('cesiumContainer');
      // 更换底图
      let imageryLayers = viewer.imageryLayers;
      let map = new Cesium.UrlTemplateImageryProvider({
          url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}", //高德地图
          minimumLevel: 3,
          maximumLevel: 16,
      });
      imageryLayers.addImageryProvider(map); //添加地图贴图

      // 场景定位
      viewer.camera.flyTo({
          destination : Cesium.Cartesian3.fromDegrees(121.195,21.813,738947.02),
          orientation :{
              heading : Cesium.Math.toRadians(355.1),
              pitch : Cesium.Math.toRadians(-75.3),
              roll :0.0
          }
      });
	//   雨天---着色器
	let rainFS = 	`
	uniform sampler2D colorTexture;
	varying vec2 v_textureCoordinates;

	float hash(float x){
		return fract(sin(x*133.3)*13.13);
	}

	void main(void){ 
		float time = czm_frameNumber / 60.0;
		vec2 resolution = czm_viewport.zw;

		vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);
		vec3 c=vec3(.6,.7,.8);

		float a= -.4;
		float si=sin(a),co=cos(a);
		uv*=mat2(co,-si,si,co);
		uv*=length(uv+vec2(0,4.9))*.3+1.;

		float v=1.-sin(hash(floor(uv.x*100.))*2.);
		float b=clamp(abs(sin(20.*time*v+uv.y*(5./(2.+v))))-.95,0.,1.)*20.;
		c*=v*b; 

		gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(c,1), 0.5);  
	}                
	`
	let rain = new Cesium.PostProcessStage({
		fragmentShader: rainFS
	});
	viewer.scene.postProcessStages.add(rain);
    </script>
  </body>
</html>