首页 前端知识 【Cesium】Vue天气(雨、雪、雾)效果(完整代码)

【Cesium】Vue天气(雨、雪、雾)效果(完整代码)

2024-09-18 02:09:50 前端知识 前端哥 925 114 我要收藏

文章目录

  • 前言
  • 一、雨
  • 二、雪
  • 三、雾
  • 调用
  • 总结


前言

展示了如何在Cesium中使用Shader来模拟真实世界的天气效果,包括不受视角变化影响的雪、雨和雾。通过PostProcessStage创建全屏后处理效果,实现了粒子系统的替代方法,以确保天气效果在场景中始终可见。
在这里插入图片描述


一、雨

WeatherRain.js

class RainEffect {
  constructor(viewer, options) {
    if (!viewer) throw new Error("no viewer object!");
    options = options || {};
 
    this.tiltAngle = Cesium.defaultValue(options.tiltAngle, -0.6); //倾斜角度,负数向右,正数向左
    this.rainSize = Cesium.defaultValue(options.rainSize, 0.1); //雨大小
    this.rainSpeed = Cesium.defaultValue(options.rainSpeed, 1000.0); //雨速
    this.viewer = viewer;
    this.init();
  }
 
  init() {
    this.rainStage = new Cesium.PostProcessStage({
      name: "czml_rain",
      fragmentShader: this.rain(),
      uniforms: {
        tiltAngle: () => {
          return this.tiltAngle;
        },
        rainSize: () => {
          return this.rainSize;
        },
        rainSpeed: () => {
          return this.rainSpeed;
        },
      },
    });
    this.viewer.scene.postProcessStages.add(this.rainStage);
  }
  //销毁对象
  destroy() {
    if (!this.viewer || !this.rainStage) return;
    this.viewer.scene.postProcessStages.remove(this.rainStage);
    delete this.tiltAngle;
    delete this.rainSize;
    delete this.rainSpeed;
  }
  //控制显示
  show(visible) {
    this.rainStage.enabled = visible;
  }
  //CLML对象,方便导出使用
  rain() {
    return "uniform sampler2D colorTexture;\n\
                varying vec2 v_textureCoordinates;\n\
                uniform float tiltAngle;\n\
                uniform float rainSize;\n\
                uniform float rainSpeed;\n\
                float hash(float x) {\n\
                    return fract(sin(x * 133.3) * 13.13);\n\
                }\n\
                void main(void) {\n\
                    float time = czm_frameNumber / rainSpeed;\n\
                    vec2 resolution = czm_viewport.zw;\n\
                    vec2 uv = (gl_FragCoord.xy * 2. - resolution.xy) / min(resolution.x, resolution.y);\n\
                    vec3 c = vec3(.6, .7, .8);\n\
                    float a = tiltAngle;\n\
                    float si = sin(a), co = cos(a);\n\
                    uv *= mat2(co, -si, si, co);\n\
                    uv *= length(uv + vec2(0, 4.9)) * rainSize + 1.;\n\
                    float v = 1. - sin(hash(floor(uv.x * 100.)) * 2.);\n\
                    float b = clamp(abs(sin(20. * time * v + uv.y * (5. / (2. + v)))) - .95, 0., 1.) * 20.;\n\
                    c *= v * b;\n\
                    gl_FragColor = mix(texture2D(colorTexture, v_textureCoordinates), vec4(c, 1), .5);\n\
                }\n\
                ";
  }
}
export default RainEffect;

二、雪

WeatherSnow.js

class SnowEffect {
  constructor(viewer, options) {
    if (!viewer) throw new Error("no viewer object!");
    options = options || {};
    this.snowSize = Cesium.defaultValue(options.snowSize, 0.02); //最好小于0.02
    this.snowSpeed = Cesium.defaultValue(options.snowSpeed, 60.0);
    this.viewer = viewer;
    this.init();
  }
  init() {
    this.snowStage = new Cesium.PostProcessStage({
      name: "czml_snow",
      fragmentShader: this.snow(),
      uniforms: {
        snowSize: () => {
          return this.snowSize;
        },
        snowSpeed: () => {
          return this.snowSpeed;
        },
      },
    });
    this.viewer.scene.postProcessStages.add(this.snowStage);
  }
  //销毁对象
  destroy() {
    if (!this.viewer || !this.snowStage) return;
    this.viewer.scene.postProcessStages.remove(this.snowStage);
    this.snowStage.destroy();
    delete this.snowSize;
    delete this.snowSpeed;
  }
  //控制显示
  show(visible) {
    this.snowStage.enabled = visible;
  }
  //CLML对象,方便导出使用
  snow() {
    return "uniform sampler2D colorTexture;\n\
          varying vec2 v_textureCoordinates;\n\
          uniform float snowSpeed;\n\
                  uniform float snowSize;\n\
          float snow(vec2 uv,float scale)\n\
          {\n\
              float time=czm_frameNumber/snowSpeed;\n\
              float w=smoothstep(1.,0.,-uv.y*(scale/10.));if(w<.1)return 0.;\n\
              uv+=time/scale;uv.y+=time*2./scale;uv.x+=sin(uv.y+time*.5)/scale;\n\
              uv*=scale;vec2 s=floor(uv),f=fract(uv),p;float k=3.,d;\n\
              p=.5+.35*sin(11.*fract(sin((s+p+scale)*mat2(7,3,6,5))*5.))-f;d=length(p);k=min(d,k);\n\
              k=smoothstep(0.,k,sin(f.x+f.y)*snowSize);\n\
              return k*w;\n\
          }\n\
          void main(void){\n\
              vec2 resolution=czm_viewport.zw;\n\
              vec2 uv=(gl_FragCoord.xy*2.-resolution.xy)/min(resolution.x,resolution.y);\n\
              vec3 finalColor=vec3(0);\n\
              //float c=smoothstep(1.,0.3,clamp(uv.y*.3+.8,0.,.75));\n\
              float c=0.;\n\
              c+=snow(uv,30.)*.0;\n\
              c+=snow(uv,20.)*.0;\n\
              c+=snow(uv,15.)*.0;\n\
              c+=snow(uv,10.);\n\
              c+=snow(uv,8.);\n\
              c+=snow(uv,6.);\n\
              c+=snow(uv,5.);\n\
              finalColor=(vec3(c));\n\
              gl_FragColor=mix(texture2D(colorTexture,v_textureCoordinates),vec4(finalColor,1),.5);\n\
              }\n\
              ";
  }
}
export default SnowEffect;

三、雾

//雾气效果
class FogEffect {
  constructor(viewer, options) {
    if (!viewer) throw new Error("no viewer object!");
    options = options || {};
    this.visibility = Cesium.defaultValue(options.visibility, 0.1);
    this.color = Cesium.defaultValue(
      options.color,
      new Cesium.Color(0.8, 0.8, 0.8, 0.5)
    );
    this._show = Cesium.defaultValue(options.show, !0);
    this.viewer = viewer;
    this.init();
  }
  init() {
    this.fogStage = new Cesium.PostProcessStage({
      name: "czml_fog",
      fragmentShader: this.fog(),
      uniforms: {
        visibility: () => {
          return this.visibility;
        },
        fogColor: () => {
          return this.color;
        },
      },
    });
    this.viewer.scene.postProcessStages.add(this.fogStage);
  }
  //销毁对象
  destroy() {
    if (!this.viewer || !this.fogStage) return;
    this.viewer.scene.postProcessStages.remove(this.fogStage);
    this.fogStage.destroy();
    delete this.visibility;
    delete this.color;
  }
  //控制显示
  show(visible) {
    this._show = visible;
    this.fogStage.enabled = this._show;
  }
  //CLML对象,方便导出使用
  fog() {
    return "uniform sampler2D colorTexture;\n\
      uniform sampler2D depthTexture;\n\
      uniform float visibility;\n\
      uniform vec4 fogColor;\n\
      varying vec2 v_textureCoordinates; \n\
      void main(void) \n\
      { \n\
          vec4 origcolor = texture2D(colorTexture, v_textureCoordinates); \n\
          float depth = czm_readDepth(depthTexture, v_textureCoordinates); \n\
          vec4 depthcolor = texture2D(depthTexture, v_textureCoordinates); \n\
          float f = visibility * (depthcolor.r - 0.3) / 0.2; \n\
          if (f < 0.0) f = 0.0; \n\
          else if (f > 1.0) f = 1.0; \n\
          gl_FragColor = mix(origcolor, fogColor, f); \n\
      }\n";
  }
}
export default FogEffect;

调用

<template>
  <div id="cesiumContainer">
    <div class="weather-tools">
      <el-select
        v-model="weatherVal"
        placeholder="请选择天气"
        @change="weatherChange"
      >
        <el-option
          v-for="item in weatherOpts"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        >
        </el-option>
      </el-select>
      <el-button size="mini" @click="weatherClose" class="close-btn"
        >关闭</el-button
      >
    </div>
  </div>
</template>
<script>
import WeatherRain from "@src/api/Cesium/CesiumWeather/WeatherRain";
import WeatherSnow from "@src/api/Cesium/CesiumWeather/WeatherSnow";
import WeatherFog from "@src/api/Cesium/CesiumWeather/WeatherFog";
let viewer = undefined;
let rainObj = undefined;
let snowObj = undefined;
let fogObj = undefined;
export default {
  data() {
    return {
      weatherVal: "snow",
      weatherOpts: [
        {
          value: "rain",
          label: "雨",
        },
        {
          value: "snow",
          label: "雪",
        },
        {
          value: "fog",
          label: "雾",
        },
      ],
    };
  },
  mounted() {
    window.viewer = viewer = new Cesium.Viewer("cesiumContainer", {
       // 是否显示全屏控件
      fullscreenButton: false,
      // 是否显示图层选择控件
      baseLayerPicker: false,
      // 是否显示选择指示器(选择实体,模型等时的绿色小框)
      selectionIndicator: false,
      // 是否显示信息框
      infoBox: false,
      // 是否显示动画控件
      animation: false,
      // 是否显示Home控件
      homeButton: false,
      // 是否显示搜索地名控件
      geocoder: false,
      // 是否显示时间线控件
      timeline: false,
      // 是否显示场景模式转换控件
      sceneModePicker: false,
      // 是否显示导航控件
      navigationHelpButton: false,
      // vr模式
      vrButton: false,
      // 加载cesium本地图层
      imageryProvider: new Cesium.TileMapServiceImageryProvider({
        url: Cesium.buildModuleUrl("./Assets/Textures/NaturalEarthII"),
      }),
    });
    viewer._cesiumWidget._creditContainer.style.display = "none"; // 隐藏版权
    this.weatherChange('snow');
  },
  methods: {
    // 天气特效选择
    weatherChange(val) {
      switch (val) {
        case "rain":
          if (snowObj) {
            snowObj.show(false);
          }
          if (fogObj) {
            fogObj.show(false);
          }
          if (!rainObj) {
            rainObj = new WeatherRain(viewer, {
              tiltAngle: -0.2,
              rainSize: 0.6,
              rainSpeed: 350.0,
            });
          }
          rainObj.show(true);
          break;
        case "snow":
          if (rainObj) {
            rainObj.show(false);
          }
          if (fogObj) {
            fogObj.show(false);
          }
          if (!snowObj) {
            snowObj = new WeatherSnow(viewer, {
              snowSize: 0.02, //雪大小
              snowSpeed: 60.0, //雪速
            });
          }
          snowObj.show(true);
          break;
        case "fog":
          if (rainObj) {
            rainObj.show(false);
          }
          if (snowObj) {
            snowObj.show(false);
          }
          if (!fogObj) {
            fogObj = new WeatherFog(viewer, {
              visibility: 0.2,
              color: new Cesium.Color(0.8, 0.8, 0.8, 0.3),
            });
          }
          fogObj.show(true);
          break;
      }
    },
    // 关闭天气特效
    weatherClose() {
      if (rainObj) {
        rainObj.show(false);
      }
      if (snowObj) {
        snowObj.show(false);
      }
      if (fogObj) {
        fogObj.show(false);
      }
    },
    getLocation() {
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
      handler.setInputAction(function (event) {
        let earthPosition = viewer.scene.pickPosition(event.position);
        if (Cesium.defined(earthPosition)) {
          let cartographic = Cesium.Cartographic.fromCartesian(earthPosition);
          let lon = Cesium.Math.toDegrees(cartographic.longitude).toFixed(5);
          let lat = Cesium.Math.toDegrees(cartographic.latitude).toFixed(5);
          let height = cartographic.height.toFixed(2);
          console.log(earthPosition, {
            lon: lon,
            lat: lat,
            height: height,
          });
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    },
  },
};
</script>
<style lang="less" scoped>
#cesiumContainer {
  width: 100%;
  height: 100%;
  position: relative;
  .weather-tools {
    position: absolute;
    z-index: 10;
    margin: 10px;
    padding: 10px;
     :deep(.el-input) {
      .el-input__inner {
        height: 30px;
        width: 120px;
      }
      .el-input__suffix {
        top: 5px;
      }
    }
    .close-btn {
      margin-left: 15px;
      cursor: pointer;
    }
  }
}
</style>

总结

Cesium 提供了丰富的技术和工具,可以实现各种天气效果。通过将实时天气数据可视化在地球上,并结合粒子系统、着色器和光照效果,可以营造出逼真和生动的天气场景。这些天气效果可以用于气象领域的数据可视化、游戏开发等应用中。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/18412.html
标签
评论
发布的文章

关于HTML的知识

2024-09-18 23:09:36

js简单实现轮播图效果

2024-09-18 23:09:36

CSS3美化网页元素

2024-09-18 23:09:27

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!