From 2eeaa4693e7389df008b6763074c48e9ffa367ca Mon Sep 17 00:00:00 2001
From: guonan <guonan201020@163.com>
Date: 星期四, 17 四月 2025 15:23:57 +0800
Subject: [PATCH] 更新雨

---
 src/utils/rain.js                      |   82 +++++++++++++
 src/utils/snow.js                      |   82 +++++++++++++
 src/components/tools/Rain.vue          |   55 +++++++++
 src/assets/css/global.css              |    8 +
 src/utils/tools.js                     |   35 ++++-
 src/components/tools/SlopeAnalysis.vue |    9 -
 src/components/tools/Tools.vue         |   31 +++-
 7 files changed, 277 insertions(+), 25 deletions(-)

diff --git a/src/assets/css/global.css b/src/assets/css/global.css
index 103df06..4291542 100644
--- a/src/assets/css/global.css
+++ b/src/assets/css/global.css
@@ -62,3 +62,11 @@
 .el-input__inner {
   color: #fff !important;
 }
+.el-slider__bar {
+  background-color: #009688 !important;
+  border-color: #009688 !important;
+}
+
+.el-slider__button {
+  border-color: rgb(0, 150, 136) !important;
+}
diff --git a/src/components/tools/Rain.vue b/src/components/tools/Rain.vue
new file mode 100644
index 0000000..f87598b
--- /dev/null
+++ b/src/components/tools/Rain.vue
@@ -0,0 +1,55 @@
+<template>
+  <el-form :model="form" label-width="80px" class="terrain-settings">
+    <el-form-item label="澶у皬">
+      <el-slider
+        :step="0.1"
+        v-model="form.rainSize"
+        :min="0"
+        :max="1"
+      ></el-slider>
+    </el-form-item>
+    <el-form-item label="閫熷害">
+      <el-slider v-model="form.rainSpeed" :min="0" :max="150"></el-slider>
+    </el-form-item>
+    <el-form-item label="棰滆壊">
+      <el-color-picker v-model="form.rainColor" />
+    </el-form-item>
+  </el-form>
+</template>
+
+<script setup>
+import { reactive, watch } from "vue";
+const form = reactive({
+  rainSize: 0.5,
+  rainSpeed: 50,
+  rainColor: "#99B3CC",
+});
+
+// 瀹氫箟 props 鍜� emit
+const props = defineProps({
+  modelValue: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(["update-rain"]);
+
+// 鐩戝惉 form 鐨勫彉鍖栵紝骞跺皢鏈�鏂板�间紶閫掔粰鐖剁粍浠�
+watch(
+  () => ({ ...form }), // 娣辨嫹璐濅互纭繚鍝嶅簲寮忚Е鍙�
+  (newVal) => {
+    emit("update-rain", newVal);
+  },
+  { deep: true } // 娣卞害鐩戝惉
+);
+</script>
+<style lang="less" scoped>
+.terrain-settings {
+  padding: 20px;
+  width: 290px;
+  background: url("@/assets/img/tools/plotting_new.png") no-repeat;
+  filter: opacity(83%);
+  background-size: 100% 100%;
+  box-sizing: border-box;
+}
+</style>
diff --git a/src/components/tools/SlopeAnalysis.vue b/src/components/tools/SlopeAnalysis.vue
index 23b690d..7609ef4 100644
--- a/src/components/tools/SlopeAnalysis.vue
+++ b/src/components/tools/SlopeAnalysis.vue
@@ -48,7 +48,7 @@
 const form = reactive({
   terrainRender: 0,
   contourLines: false,
-  color: "",
+  color: "red",
   spacing: 50,
   lineWidth: 5,
 });
@@ -78,14 +78,7 @@
   display: flex;
 }
 
-/deep/ .el-slider__bar {
-  background-color: #009688;
-  border-color: #009688;
-}
 
-/deep/ .el-slider__button {
-  border-color: rgb(0, 150, 136);
-}
 
 /deep/ .el-switch.is-checked .el-switch__core {
   background-color: #009688;
diff --git a/src/components/tools/Tools.vue b/src/components/tools/Tools.vue
index 79bda9b..53139b3 100644
--- a/src/components/tools/Tools.vue
+++ b/src/components/tools/Tools.vue
@@ -54,6 +54,12 @@
         class="popup-menu-see"
         @update-slope="onUpdateSlope"
       />
+      <!-- 闆� -->
+      <Rain
+        v-show="showRain"
+        class="popup-menu-see"
+        @update-rain="onUpdateRain"
+      />
     </div>
 
     <!-- 宸ュ叿鏍忓唴瀹� -->
@@ -85,12 +91,12 @@
 import Aspect from "@/components/tools/Aspect.vue";
 import SlopeAnalysis from "@/components/tools/SlopeAnalysis.vue";
 import mapUtils from "@/utils/tools.js";
+import Rain from "@/components/tools/Rain.vue";
 
 // 鍒囨崲灞曞紑/鏀剁缉鐘舵��
 function toggleCollapse() {
   // isCollapsed.value = !isCollapsed.value;
 }
-
 
 const showLayerTree = ref(false);
 
@@ -101,7 +107,7 @@
 const isflfx = ref(false);
 const isFlood = ref(false);
 const isContourLabel = ref(false);
-const isRain = ref(false);
+const showRain = ref(false);
 const isSnow = ref(false);
 
 // 鍓栭潰鍒嗘瀽寮圭獥
@@ -197,6 +203,7 @@
     echartsShow.value = false; //鍓栭潰echarts
     showAspect.value = false; //鍧″悜绠ご
     showSlope.value = false; //鍧″悜绠ご
+    showRain.value = false; //闆ㄥぉ
     return;
   }
 
@@ -209,6 +216,7 @@
   echartsShow.value = false; //鍓栭潰echarts
   showAspect.value = false; //鍧″悜绠ご
   showSlope.value = false; //鍧″悜绠ご
+  showRain.value = false; //闆ㄥぉ
 }
 
 // 澶勭悊寮圭獥閫夐」鐐瑰嚮浜嬩欢
@@ -219,12 +227,7 @@
     鏄剧ず鍥惧眰: () => (showLayerTree.value = true),
     闅愯棌鍥惧眰: () => (showLayerTree.value = false),
     闆ㄥぉ妯″紡: () => {
-      isRain.value = !isRain.value;
-      if (isRain.value === false) {
-        mapUtils.toggleRain("rain", false);
-      } else {
-        mapUtils.toggleRain("rain", true);
-      }
+      showRain.value = true;
     },
     闆ぉ妯″紡: () => {
       isSnow.value = !isSnow.value;
@@ -402,6 +405,18 @@
   Object.assign(formData, newOption);
   mapUtils.pdfx(formData);
 };
+
+// 闆�
+const rainForm = reactive({
+  rainSize: 0.5,
+  rainSpeed: 50,
+  rainColor: "#99B3CC",
+});
+const onUpdateRain = (newOption) => {
+  console.log(newOption, "new");
+  Object.assign(rainForm, newOption);
+  mapUtils.toggleRain(rainForm, true);
+};
 </script>
 
 <style lang="less" scoped>
diff --git a/src/utils/rain.js b/src/utils/rain.js
new file mode 100644
index 0000000..a7499e5
--- /dev/null
+++ b/src/utils/rain.js
@@ -0,0 +1,82 @@
+class RainEffect {
+  constructor(viewer, options) {
+    if (!viewer) throw new Error("no viewer object!");
+    options = options || {};
+    //鍊炬枩瑙掑害锛岃礋鏁板悜鍙筹紝姝f暟鍚戝乏
+    this.tiltAngle = Cesium.defaultValue(options.tiltAngle, -0.6);
+    this.rainSize = Cesium.defaultValue(options.rainSize, 0.3);
+    this.rainSpeed = Cesium.defaultValue(options.rainSpeed, 60.0);
+    this.color = Cesium.defaultValue(options.color, new Cesium.Color(0.6, 0.7, 0.8, 1.0));
+    this.viewer = viewer;
+    this.init();
+  }
+
+  init() {
+    this.rainStage = new Cesium.PostProcessStage({
+      name: "czm_rain",
+      fragmentShader: this.rain(),
+      uniforms: {
+        tiltAngle: () => {
+          return this.tiltAngle;
+        },
+        rainSize: () => {
+          return this.rainSize;
+        },
+        rainColor: () => {
+          return this.color;
+        },
+        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);
+    const isDestroyed = this.rainStage.isDestroyed();
+    // 鍏堟鏌ユ槸鍚﹁閿�姣佽繃锛屽鏋滃凡缁忚閿�姣佽繃鍐嶈皟鐢╠estroy浼氭姤閿�
+    if (!isDestroyed) {
+      this.rainStage.destroy();
+    }
+    delete this.tiltAngle;
+    delete this.rainSize;
+    delete this.rainSpeed;
+  }
+
+  show(visible) {
+    this.rainStage.enabled = visible;
+  }
+
+  rain() {
+    return "uniform sampler2D colorTexture;\n\
+              in vec2 v_textureCoordinates;\n\
+              uniform float tiltAngle;\n\
+              uniform vec4 rainColor;\n\
+              uniform float rainSize;\n\
+              uniform float rainSpeed;\n\
+              float hash(float x) {\n\
+                  return fract(sin(x * 133.3) * 13.13);\n\
+              }\n\
+              out vec4 fragColor;\n\
+              void main(void) {\n\
+                 float time = czm_frameNumber * (rainSpeed / 10000.0);\n\
+                  vec2 resolution = czm_viewport.zw;\n\
+                  vec2 uv = (gl_FragCoord.xy * 2. - resolution.xy) / min(resolution.x, resolution.y);\n\
+                  vec3 c = rainColor.rgb;\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 * 3.0 + 0.1) + 0.5;\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\
+                  fragColor = mix(texture(colorTexture, v_textureCoordinates), vec4(c, 1), .5);\n\
+              }\n\
+              ";
+  }
+}
+
+export default RainEffect;
diff --git a/src/utils/snow.js b/src/utils/snow.js
new file mode 100644
index 0000000..2c8eeaa
--- /dev/null
+++ b/src/utils/snow.js
@@ -0,0 +1,82 @@
+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, 100.0); // 閫熷害
+    this.snowColor = Cesium.defaultValue(options.snowColor, new Cesium.Color(1.0, 1.0, 1.0, 1.0)); // 棰滆壊
+    this.viewer = viewer;
+    this.init();
+  }
+
+  init() {
+    this.snowStage = new Cesium.PostProcessStage({
+      name: "czm_snow",
+      fragmentShader: this.snow(),
+      uniforms: {
+        snowSize: () => {
+          return this.snowSize;
+        },
+        snowSpeed: () => {
+          return this.snowSpeed;
+        },
+        snowColor: () => {
+          return this.snowColor;
+        },
+      },
+    });
+    this.viewer.scene.postProcessStages.add(this.snowStage);
+  }
+
+  destroy() {
+    if (!this.viewer || !this.snowStage) return;
+    this.viewer.scene.postProcessStages.remove(this.snowStage);
+    const isDestroyed = this.snowStage.isDestroyed();
+    // 鍏堟鏌ユ槸鍚﹁閿�姣佽繃锛屽鏋滃凡缁忚閿�姣佽繃鍐嶈皟鐢╠estroy浼氭姤閿�
+    if (!isDestroyed) {
+      this.snowStage.destroy();
+    }
+    delete this.snowSize;
+    delete this.snowSpeed;
+  }
+  show(visible) {
+    this.snowStage.enabled = visible;
+  }
+
+  snow() {
+    return "uniform sampler2D colorTexture;\n\
+          in vec2 v_textureCoordinates;\n\
+          uniform float snowSpeed;\n\
+          uniform float snowSize;\n\
+          uniform vec4 snowColor;\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\
+          out vec4 fragColor;\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) * snowColor.rgb);\n\
+              fragColor=mix(texture(colorTexture,v_textureCoordinates),vec4(finalColor,1),.5);\n\
+              }\n\
+              ";
+  }
+}
+export default SnowEffect;
diff --git a/src/utils/tools.js b/src/utils/tools.js
index 9b23612..6604c70 100644
--- a/src/utils/tools.js
+++ b/src/utils/tools.js
@@ -2,6 +2,7 @@
 // import cameraIcon from "../assets/images/base/瑙嗛娴嬬偣.png"
 // import cameraIconSel from "../assets/images/base/瑙嗛娴嬬偣sel.png"
 import { ElLoading, ElMessage } from "element-plus";
+import RainEffect from './rain'
 let layerIsOpen = false;
 const Cesium = SmartEarth.Cesium;
 const colorAll = {
@@ -19,10 +20,33 @@
   analysisDXPMRes: [],
   slopeArrow: null,
   elevationTool: null,
+  rainEffect: null,
 
   init(earthCtrl) {
     this.earthCtrl = earthCtrl;
     return this;
+  },
+  hexToColor(hexColor) {
+    const hex = hexColor.replace('#', '');
+    const r = parseInt(hex.substring(0, 2), 16) / 255;
+    const g = parseInt(hex.substring(2, 4), 16) / 255;
+    const b = parseInt(hex.substring(4, 6), 16) / 255;
+    return new Cesium.Color(r, g, b, 1.0);
+  },
+  // 澶╂皵
+  toggleRain(option, show) {
+    console.log(option, 'option')
+    // 鍏堥攢姣佹棫瀹炰緥
+    if (this.rainEffect) {
+      this.rainEffect.destroy()
+      this.rainEffect = null
+    }
+    this.rainEffect = new RainEffect(earthCtrl.viewer, {
+      tiltAngle: -0.2, //鍊炬枩瑙掑害
+      rainSize: option.rainSize, // 闆ㄧ殑澶у皬
+      rainSpeed: option.rainSpeed, // 闆ㄧ殑閫熷害
+      color: this.hexToColor(option.rainColor)  // 闆ㄧ殑棰滆壊
+    })
   },
   // 鍧″害鍒嗘瀽
   pdfx(option) {
@@ -69,7 +93,7 @@
       this.slopeArrow.setPositions(polygonPosition);
       this.slopeArrow.setSlopeType(1);
       this.slopeArrow.setRegionEnabled(true);
-      console.log(this.slopeArrow,'slope')
+      console.log(this.slopeArrow, 'slope')
     });
   },
   // 鍏抽棴鍧″悜绠ご
@@ -79,14 +103,7 @@
     }
   },
 
-  // 澶╂皵
-  toggleRain(weather = "rain", show) {
-    if (show) {
-      earthCtrl.environment.showEffect(weather);
-    } else {
-      earthCtrl.environment.disableEffect(weather);
-    }
-  },
+
   toggleSnow(weather = "snow", show) {
     if (show) {
       earthCtrl.environment.showEffect(weather);

--
Gitblit v1.9.3