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

11,255次阅读
没有评论

共计 6913 个字符,预计需要花费 18 分钟才能阅读完成。

文章目录

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

前言

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


一、雨

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;
  }
  
  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); 
    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;
  }
  
  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 uv 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" return void main vec2 resolution="czm_viewport.zw;n" vec3 finalcolor="vec3(0);n" c="smoothstep(1.,0.3,clamp(uv.y*.3+.8,0.,.75));n" float gl_fragcolor="mix(texture2D(colorTexture,v_textureCoordinates),vec4(finalColor,1),.5);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;
  }
  
  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  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,
      
      homeButton: false,
      
      geocoder: false,
      
      timeline: false,
      
      sceneModePicker: false,
      
      navigationHelpButton: false,
      
      vrButton: false,
      
      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 提供了丰富的技术和工具,可以实现各种天气效果。通过将实时天气数据可视化在地球上,并结合粒子系统、着色器和光照效果,可以营造出逼真和生动的天气场景。这些天气效果可以用于气象领域的数据可视化、游戏开发等应用中。

原文地址: 【Cesium】Vue 天气(雨、雪、雾)效果(完整代码)

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-28发表,共计6913字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)