From eef0209e582b66d4686ecfa3d5b23499d7646ef1 Mon Sep 17 00:00:00 2001 From: zhangquan <2523589960@qq.com> Date: Thu, 31 Jul 2025 18:11:52 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=B8=8B=E9=9B=AA=E7=B2=92=E5=AD=90=E6=95=88?= =?UTF-8?q?=E6=9E=9C=E5=90=AF=E5=8A=A8=E5=90=8E=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=9C=A8=E6=A8=A1=E5=9E=8B=E4=B8=8A=E6=B7=BB=E5=8A=A0=E7=A7=AF?= =?UTF-8?q?=E9=9B=AA=E6=95=88=E6=9E=9C=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mixins/useWeatherParticle/index.js | 2 + .../mixins/useWeatherParticle/snow.js | 103 ++++++++++++++++++ src/views/systemTemplate/forestFire/index.vue | 4 + 3 files changed, 109 insertions(+) diff --git a/src/components/CesiumMap/mixins/useWeatherParticle/index.js b/src/components/CesiumMap/mixins/useWeatherParticle/index.js index c7141cc..0e5037a 100644 --- a/src/components/CesiumMap/mixins/useWeatherParticle/index.js +++ b/src/components/CesiumMap/mixins/useWeatherParticle/index.js @@ -31,6 +31,8 @@ export const useWeatherParticle = (viewer) => { weather = new SnowEffect(_viewer, { snowSize: 0.02, // ❄️大小,最好小于0.02 snowSpeed: 60.0, // 速度 + isCover: true, // 是否显示积雪覆盖效果 + coverage: 0.3, // 积雪覆盖(混色)占比 }); weather.show(true); }; diff --git a/src/components/CesiumMap/mixins/useWeatherParticle/snow.js b/src/components/CesiumMap/mixins/useWeatherParticle/snow.js index 36b9ffc..4617603 100644 --- a/src/components/CesiumMap/mixins/useWeatherParticle/snow.js +++ b/src/components/CesiumMap/mixins/useWeatherParticle/snow.js @@ -13,6 +13,9 @@ class SnowEffect { options = options || {}; this.snowSize = Cesium.defaultValue(options.snowSize, 0.02); // ❄️大小,最好小于0.02 this.snowSpeed = Cesium.defaultValue(options.snowSpeed, 60.0); // 速度 + // 积雪效果 + this.isCover = Cesium.defaultValue(options.isCover, false); // 是否显示积雪覆盖效果 + this.coverage = Cesium.defaultValue(options.coverage, 0.3); // 积雪覆盖(混色)占比 this.viewer = viewer; this.init(); } @@ -31,6 +34,27 @@ class SnowEffect { }, }); this.viewer.scene.postProcessStages.add(this.snowStage); + if(this.isCover) { + const coverShader = new Cesium.CustomShader({ + uniforms: { + u_lightColor: { + type: Cesium.UniformType.VEC3, + value: new Cesium.Cartesian3(1, 1, 1), + }, + u_snowAlpha: { + type: Cesium.UniformType.FLOAT, + value: this.coverage, + }, + }, + fragmentShaderText: this.cover() + }) + for (let index = 0; index < this.viewer.scene.primitives.length; index++) { + const primitive = this.viewer.scene.primitives.get(index); + if(primitive instanceof Cesium.Cesium3DTileset) { + primitive.customShader = coverShader; + } + } + } } destroy() { @@ -43,6 +67,19 @@ class SnowEffect { } delete this.snowSize; delete this.snowSpeed; + + // 销毁积雪效果 + if(this.isCover === undefined) return; + if(this.isCover) { + for (let index = 0; index < this.viewer.scene.primitives.length; index++) { + const primitive = this.viewer.scene.primitives.get(index); + if(primitive instanceof Cesium.Cesium3DTileset) { + primitive.customShader = undefined; + } + } + delete this.isCover; + delete this.coverStage; + } } show(visible) { this.snowStage.enabled = visible; @@ -82,5 +119,71 @@ class SnowEffect { }\n\ "; } + + cover() { + return ` + #define MAX_RADIUS 2 + // Set to 1 to hash twice. Slower, but less patterns. + #define DOUBLE_HASH 0 + // Hash functions shamefully stolen from: + // https://www.shadertoy.com/view/4djSRW + #define HASHSCALE1 .1031 + #define HASHSCALE3 vec3(.1031, .1030, .0973) + float hash12(vec2 p) + { + vec3 p3 = fract(vec3(p.xyx) * HASHSCALE1); + p3 += dot(p3, p3.yzx + 19.19); + return fract((p3.x + p3.y) * p3.z); + } + vec2 hash22(vec2 p) + { + vec3 p3 = fract(vec3(p.xyx) * HASHSCALE3); + p3 += dot(p3, p3.yzx+19.19); + return fract((p3.xx+p3.yz)*p3.zy); + + } + void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) { + vec3 positionEC = fsInput.attributes.positionEC; + vec3 positionMC = fsInput.attributes.positionMC; + vec2 uv = fsInput.attributes.texCoord_0 * 500.; + vec3 pos_dx = dFdx(positionEC); + vec3 pos_dy = dFdy(positionEC); + vec3 normalEC = normalize(cross(pos_dx, pos_dy)); + vec4 positionWC = normalize(czm_inverseView * vec4(positionEC,1.0)); + vec3 normalWC = normalize(czm_inverseViewRotation * normalEC); + float time = czm_frameNumber / 60.0; + vec2 p0 = floor(uv); + vec2 circles = vec2(0.); + for (int j = -MAX_RADIUS; j <= MAX_RADIUS; ++j) + { + for (int i = -MAX_RADIUS; i <= MAX_RADIUS; ++i) + { + vec2 pi = p0 + vec2(i, j); + #if DOUBLE_HASH + vec2 hsh = hash22(pi); + #else + vec2 hsh = pi; + #endif + vec2 p = pi + hash22(hsh); + + float t = fract(0.3*time + hash12(hsh)); + vec2 v = p - uv; + float d = length(v) - (float(MAX_RADIUS) + 1.)*t; + + float h = 1e-3; + float d1 = d - h; + float d2 = d + h; + float p1 = sin(31.*d1) * smoothstep(-0.6, -0.3, d1) * smoothstep(0., -0.3, d1); + float p2 = sin(31.*d2) * smoothstep(-0.6, -0.3, d2) * smoothstep(0., -0.3, d2); + circles += 0.5 * normalize(v) * ((p2 - p1) / (2. * h) * (1. - t) * (1. - t)); + } + } + circles /= float((MAX_RADIUS*2+1)*(MAX_RADIUS*2+1)); + vec3 n = vec3(circles, sqrt(1. - dot(circles, circles))); + material.diffuse = mix(material.diffuse, vec3(1.0) , u_snowAlpha * smoothstep(0., .5, dot(positionWC.xyz, normalWC))); + material.diffuse *= min(max(0.0, dot(normalEC, czm_sunDirectionEC) * 1.0) + u_lightColor, 1.0); + } + `; + } } export default SnowEffect; \ No newline at end of file diff --git a/src/views/systemTemplate/forestFire/index.vue b/src/views/systemTemplate/forestFire/index.vue index fdc5c10..7b1171d 100644 --- a/src/views/systemTemplate/forestFire/index.vue +++ b/src/views/systemTemplate/forestFire/index.vue @@ -25,6 +25,10 @@ const options = ref({ }, ditu: 'tianditu', // 底图选择 isTerrainProvider: true, // 启用地形 + modelList: [ + '/model/hu_ma_shan/tileset.json', + '/model/yi_liu/tileset.json' + ], // 测试模型列表 }) const showProperty = ref(false); // 控制属性面板的显示与隐藏 const propertyData = ref([])