From d89c6d9385c6574c7e72f15b2359ac3347b44d78 Mon Sep 17 00:00:00 2001 From: liaoboping <344114999@qq.com> Date: Sun, 21 Sep 2025 12:12:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B0=94=E8=B1=A1=E7=8E=AF=E5=A2=83=EF=BC=8C?= =?UTF-8?q?=E4=B8=8B=E9=9B=A8=E4=B8=8B=E9=9B=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Common/Cesium/index.js | 42 ++++++++++++++ src/components/Common/Cesium/rain.js | 84 +++++++++++++++++++++++++++ src/components/Common/Cesium/snow.js | 84 +++++++++++++++++++++++++++ src/views/subsystem/display/index.vue | 14 +++++ src/views/subsystem/model/index.vue | 14 +++++ src/views/subsystem/scene/index.vue | 14 +++++ 6 files changed, 252 insertions(+) create mode 100644 src/components/Common/Cesium/rain.js create mode 100644 src/components/Common/Cesium/snow.js diff --git a/src/components/Common/Cesium/index.js b/src/components/Common/Cesium/index.js index ecaf560..c273bcf 100644 --- a/src/components/Common/Cesium/index.js +++ b/src/components/Common/Cesium/index.js @@ -2,6 +2,9 @@ import * as Cesium from 'cesium' import CesiumNavigation from 'cesium-navigation-es6' import 'cesium/Build/Cesium/Widgets/widgets.css' +import RainEffect from './rain' +import SnowEffect from './snow' + const getCatesian3FromPX = (viewer, px) => { const picks = viewer.scene.drillPick(px) viewer.scene.render() @@ -361,4 +364,43 @@ export default class MyCesium { this.initPlotMoving(targetPlot, coordinates) } } + + /** + * @type {RainEffect} + */ + rainEffect = null + // 增加下雨特效 + addRain() { + this.cancelPreviousOperation() + this.removeRain() + this.rainEffect = new RainEffect(this.viewer, { + tiltAngle: -0.2, //倾斜角度 + rainSize: 1.0, // 雨大小 + rainSpeed: 200.0, // 雨速 + }) + this.rainEffect.show(true) + } + removeRain() { + this.rainEffect && this.rainEffect.destroy() + this.rainEffect = null + } + + /** + * @type {SnowEffect} + */ + snowEffect = null + // 增加下雪特效 + addSnow() { + this.cancelPreviousOperation() + this.removeSnow() + this.snowEffect = new SnowEffect(this.viewer, { + snowSize: 0.02, // 雪大小 + snowSpeed: 60.0, // 雪速 + }) + this.snowEffect.show(true) + } + removeSnow() { + this.snowEffect && this.snowEffect.destroy() + this.snowEffect = null + } } diff --git a/src/components/Common/Cesium/rain.js b/src/components/Common/Cesium/rain.js new file mode 100644 index 0000000..1766c15 --- /dev/null +++ b/src/components/Common/Cesium/rain.js @@ -0,0 +1,84 @@ +/* + * @Descripttion: 雨粒子效果 + * @Author: 笙痞 + * @Date: 2023-01-04 15:01:03 + * @LastEditors: 笙痞77 + * @LastEditTime: 2023-05-19 09:54:15 + */ +import * as Cesium from 'cesium' + +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.3) + this.rainSpeed = Cesium.defaultValue(options.rainSpeed, 120.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 + }, + 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() + // 先检查是否被销毁过,如果已经被销毁过再调用destroy会报错 + 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\ + 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 uv = (gl_FragCoord.xy - czm_viewport.xy) / czm_viewport.zw;\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 diff --git a/src/components/Common/Cesium/snow.js b/src/components/Common/Cesium/snow.js new file mode 100644 index 0000000..784dddf --- /dev/null +++ b/src/components/Common/Cesium/snow.js @@ -0,0 +1,84 @@ +/* + * @Descripttion: 雪花粒子类 + * @Author: 笙痞 + * @Date: 2023-01-04 14:01:07 + * @LastEditors: 笙痞77 + * @LastEditTime: 2023-05-19 09:52:52 + */ + +import * as Cesium from 'cesium' +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: 'czm_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) + const isDestroyed = this.snowStage.isDestroyed() + // 先检查是否被销毁过,如果已经被销毁过再调用destroy会报错 + if (!isDestroyed) { + 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)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=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 diff --git a/src/views/subsystem/display/index.vue b/src/views/subsystem/display/index.vue index 5f36d3c..3932998 100644 --- a/src/views/subsystem/display/index.vue +++ b/src/views/subsystem/display/index.vue @@ -128,6 +128,18 @@ export default { this.roomInfo.remainTime = response.data.remain_time this.roomInfo.duringTime = response.data.during_time break + case 'start_rain': + this.cesium.addRain() + break + case 'stop_rain': + this.cesium.removeRain() + break + case 'start_snow': + this.cesium.addSnow() + break + case 'stop_snow': + this.cesium.removeSnow() + break case 'path_init': this.cesium.drawRouteByCoordinates( response.data.points, @@ -163,6 +175,8 @@ export default { this.ws.send({ cmdType: 'get_init_path' }) // 初始化倍速、状态 this.ws.send({ cmdType: 'get_room_info' }) + // 初始化气象状态 + this.ws.send({ cmdType: 'get_weather' }) }, closeWebsocket() { this.ws && this.ws.close() diff --git a/src/views/subsystem/model/index.vue b/src/views/subsystem/model/index.vue index f73dcd5..936ee6c 100644 --- a/src/views/subsystem/model/index.vue +++ b/src/views/subsystem/model/index.vue @@ -322,6 +322,18 @@ export default { this.roomInfo.remainTime = response.data.remain_time this.roomInfo.duringTime = response.data.during_time break + case 'start_rain': + this.cesium.addRain() + break + case 'stop_rain': + this.cesium.removeRain() + break + case 'start_snow': + this.cesium.addSnow() + break + case 'stop_snow': + this.cesium.removeSnow() + break case 'path_init': this.cesium.drawRouteByCoordinates( response.data.points, @@ -357,6 +369,8 @@ export default { this.ws.send({ cmdType: 'get_init_path' }) // 初始化倍速、状态 this.ws.send({ cmdType: 'get_room_info' }) + // 初始化气象状态 + this.ws.send({ cmdType: 'get_weather' }) }, closeWebsocket() { this.ws && this.ws.close() diff --git a/src/views/subsystem/scene/index.vue b/src/views/subsystem/scene/index.vue index 972d6db..2fe6006 100644 --- a/src/views/subsystem/scene/index.vue +++ b/src/views/subsystem/scene/index.vue @@ -290,6 +290,18 @@ export default { this.roomInfo.remainTime = response.data.remain_time this.roomInfo.duringTime = response.data.during_time break + case 'start_rain': + this.cesium.addRain() + break + case 'stop_rain': + this.cesium.removeRain() + break + case 'start_snow': + this.cesium.addSnow() + break + case 'stop_snow': + this.cesium.removeSnow() + break case 'path_init': this.cesium.drawRouteByCoordinates( response.data.points, @@ -325,6 +337,8 @@ export default { this.ws.send({ cmdType: 'get_init_path' }) // 初始化倍速、状态 this.ws.send({ cmdType: 'get_room_info' }) + // 初始化气象状态 + this.ws.send({ cmdType: 'get_weather' }) }, closeWebsocket() { this.ws && this.ws.close()