|
|
@@ -0,0 +1,337 @@
|
|
|
+// 天气效果实现
|
|
|
+class WeatherEffect {
|
|
|
+ constructor(viewer) {
|
|
|
+ this.viewer = viewer;
|
|
|
+ this.scene = viewer.scene;
|
|
|
+ this.currentWeather = 'sunny'; // 默认晴天
|
|
|
+ this.rainParticleSystem = null;
|
|
|
+ this.snowParticleSystem = null;
|
|
|
+ this.rainEffect = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置天气类型
|
|
|
+ setWeather(weatherType) {
|
|
|
+ this.currentWeather = weatherType;
|
|
|
+ this.clearWeatherEffects();
|
|
|
+
|
|
|
+ switch (weatherType) {
|
|
|
+ case 'sunny':
|
|
|
+ this.setSunnyWeather();
|
|
|
+ break;
|
|
|
+ case 'cloudy':
|
|
|
+ this.setCloudyWeather();
|
|
|
+ break;
|
|
|
+ case 'rain':
|
|
|
+ this.setRainWeather();
|
|
|
+ break;
|
|
|
+ case 'snow':
|
|
|
+ this.setSnowWeather();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除所有天气效果
|
|
|
+ clearWeatherEffects() {
|
|
|
+ // 清除粒子系统
|
|
|
+ if (this.rainParticleSystem) {
|
|
|
+ this.scene.primitives.remove(this.rainParticleSystem);
|
|
|
+ this.rainParticleSystem = null;
|
|
|
+ }
|
|
|
+ if (this.snowParticleSystem) {
|
|
|
+ this.scene.primitives.remove(this.snowParticleSystem);
|
|
|
+ this.snowParticleSystem = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除后处理效果
|
|
|
+ if (this.rainEffect) {
|
|
|
+ this.rainEffect.destroy();
|
|
|
+ this.rainEffect = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置大气效果
|
|
|
+ this.scene.skyAtmosphere.hueShift = 0.0;
|
|
|
+ this.scene.skyAtmosphere.saturationShift = 0.0;
|
|
|
+ this.scene.skyAtmosphere.brightnessShift = 0.0;
|
|
|
+
|
|
|
+ // 重置光照
|
|
|
+ this.scene.globe.enableLighting = true;
|
|
|
+ if (this.scene.sun) {
|
|
|
+ this.scene.sun.show = true;
|
|
|
+ }
|
|
|
+ if (this.scene.moon) {
|
|
|
+ this.scene.moon.show = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置晴天效果
|
|
|
+ setSunnyWeather() {
|
|
|
+ this.scene.skyAtmosphere.hueShift = 0.0;
|
|
|
+ this.scene.skyAtmosphere.saturationShift = 0.1;
|
|
|
+ this.scene.skyAtmosphere.brightnessShift = 0.2;
|
|
|
+ this.scene.globe.enableLighting = true;
|
|
|
+ if (this.scene.sun) {
|
|
|
+ this.scene.sun.show = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置阴天效果
|
|
|
+ setCloudyWeather() {
|
|
|
+ this.scene.skyAtmosphere.hueShift = 0.1;
|
|
|
+ this.scene.skyAtmosphere.saturationShift = -0.3;
|
|
|
+ this.scene.skyAtmosphere.brightnessShift = -0.4;
|
|
|
+ this.scene.globe.enableLighting = true;
|
|
|
+ if (this.scene.sun) {
|
|
|
+ this.scene.sun.show = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置雨天效果
|
|
|
+ setRainWeather() {
|
|
|
+ this.setCloudyWeather();
|
|
|
+ this.createRainEffect();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置雪天效果
|
|
|
+ setSnowWeather() {
|
|
|
+ this.setCloudyWeather();
|
|
|
+ this.createSnowEffect();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建下雨效果
|
|
|
+ createRainEffect() {
|
|
|
+ console.log('创建雨天效果');
|
|
|
+
|
|
|
+ // 尝试使用粒子系统实现雨天效果
|
|
|
+ const rainParticleSize = this.scene.drawingBufferWidth / 500.0; // 进一步减小雨滴宽度
|
|
|
+ const rainRadius = 4000.0;
|
|
|
+ const rainImageSize = new Cesium.Cartesian2(rainParticleSize, rainParticleSize * 10.0); // 调整雨滴形状,更加细长
|
|
|
+ const rainGravityScratch = new Cesium.Cartesian3();
|
|
|
+
|
|
|
+ const rainUpdate = (particle, dt) => {
|
|
|
+ Cesium.Cartesian3.normalize(particle.position, rainGravityScratch);
|
|
|
+ Cesium.Cartesian3.multiplyByScalar(rainGravityScratch, -40, rainGravityScratch); // 增加下落速度,使雨滴更自然
|
|
|
+ Cesium.Cartesian3.add(particle.position, rainGravityScratch, particle.position);
|
|
|
+ const distance = Cesium.Cartesian3.distance(this.scene.camera.position, particle.position);
|
|
|
+ if (distance > rainRadius) {
|
|
|
+ particle.endColor.alpha = 0.0;
|
|
|
+ } else {
|
|
|
+ particle.endColor.alpha = this.rainParticleSystem.endColor.alpha / (distance / rainRadius + 0.1);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 创建雨滴粒子系统
|
|
|
+ const rainColor = new Cesium.Color(0.5, 0.6, 0.7, 0.4); // 调整为更暗的雨水颜色,增加透明度
|
|
|
+ console.log('雨滴颜色:', rainColor);
|
|
|
+
|
|
|
+ // 使用与雪天相同的纹理,确保显示
|
|
|
+ const rainTexture = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBjeD0iNSIgY3k9IjUiIHI9IjUiIGZpbGw9IiNmZmYiIGZpbGwtb3BhY2l0eT0iMC43Ii8+PC9zdmc+';
|
|
|
+
|
|
|
+ this.rainParticleSystem = new Cesium.ParticleSystem({
|
|
|
+ modelMatrix: new Cesium.Matrix4.fromTranslation(this.scene.camera.position),
|
|
|
+ speed: -1.0,
|
|
|
+ lifetime: 10.0, // 减少生命周期,使雨滴更密集
|
|
|
+ emitter: new Cesium.SphereEmitter(rainRadius),
|
|
|
+ startScale: 1.0,
|
|
|
+ endScale: 1.0,
|
|
|
+ image: rainTexture,
|
|
|
+ emissionRate: 5000.0, // 增加粒子数量,使雨更密集
|
|
|
+ startColor: rainColor,
|
|
|
+ endColor: rainColor,
|
|
|
+ imageSize: rainImageSize,
|
|
|
+ updateCallback: rainUpdate,
|
|
|
+ performance: false,
|
|
|
+ });
|
|
|
+
|
|
|
+ this.scene.primitives.add(this.rainParticleSystem);
|
|
|
+ this.rainParticleSystem.lodRangeScale = 10000;
|
|
|
+
|
|
|
+ // 参考示例,添加相机位置监听,确保粒子系统跟随相机移动
|
|
|
+ this.scene.camera.changed.addEventListener(() => {
|
|
|
+ if (this.rainParticleSystem) {
|
|
|
+ const modelMatrix = new Cesium.Matrix4.fromTranslation(this.scene.camera.position);
|
|
|
+ this.rainParticleSystem.modelMatrix = modelMatrix;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('雨天效果创建完成,粒子系统数量:', this.scene.primitives.length);
|
|
|
+ console.log('粒子系统颜色设置:', {
|
|
|
+ startColor: this.rainParticleSystem.startColor,
|
|
|
+ endColor: this.rainParticleSystem.endColor
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建下雪效果
|
|
|
+ createSnowEffect() {
|
|
|
+ const snowParticleSize = this.scene.drawingBufferWidth / 150.0; // 减小雪花大小
|
|
|
+ const snowRadius = 4000.0;
|
|
|
+ const snowImageSize = new Cesium.Cartesian2(snowParticleSize, snowParticleSize);
|
|
|
+ const snowGravityScratch = new Cesium.Cartesian3();
|
|
|
+
|
|
|
+ const snowUpdate = (particle, dt) => {
|
|
|
+ Cesium.Cartesian3.normalize(particle.position, snowGravityScratch);
|
|
|
+ Cesium.Cartesian3.multiplyByScalar(snowGravityScratch, -15, snowGravityScratch); // 减慢下落速度
|
|
|
+ Cesium.Cartesian3.add(particle.position, snowGravityScratch, particle.position);
|
|
|
+ const distance = Cesium.Cartesian3.distance(this.scene.camera.position, particle.position);
|
|
|
+ if (distance > snowRadius) {
|
|
|
+ particle.endColor.alpha = 0.0;
|
|
|
+ } else {
|
|
|
+ particle.endColor.alpha = this.snowParticleSystem.endColor.alpha / (distance / snowRadius + 0.1);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 创建雪花粒子系统
|
|
|
+ const snowColor = Cesium.Color.WHITE.withAlpha(0.7); // 按照用户要求设置
|
|
|
+ console.log('雪花颜色:', snowColor);
|
|
|
+
|
|
|
+ // 使用更适合的雪花纹理
|
|
|
+ const snowTexture = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBjeD0iNSIgY3k9IjUiIHI9IjUiIGZpbGw9IiNmZmYiIGZpbGwtb3BhY2l0eT0iMC43Ii8+PC9zdmc+';
|
|
|
+
|
|
|
+ this.snowParticleSystem = new Cesium.ParticleSystem({
|
|
|
+ modelMatrix: new Cesium.Matrix4.fromTranslation(this.scene.camera.position),
|
|
|
+ speed: -1.0,
|
|
|
+ lifetime: 20.0, // 增加生命周期,使雪花飘落更自然
|
|
|
+ emitter: new Cesium.SphereEmitter(snowRadius),
|
|
|
+ startScale: 0.8,
|
|
|
+ endScale: 1.2, // 增加大小变化,使雪花更自然
|
|
|
+ image: snowTexture,
|
|
|
+ emissionRate: 3000.0, // 增加粒子数量,使雪更密集
|
|
|
+ startColor: snowColor,
|
|
|
+ endColor: snowColor,
|
|
|
+ imageSize: snowImageSize,
|
|
|
+ updateCallback: snowUpdate,
|
|
|
+ performance: false,
|
|
|
+ });
|
|
|
+
|
|
|
+ this.scene.primitives.add(this.snowParticleSystem);
|
|
|
+ this.snowParticleSystem.lodRangeScale = 10000;
|
|
|
+
|
|
|
+ // 参考示例,添加相机位置监听,确保粒子系统跟随相机移动
|
|
|
+ this.scene.camera.changed.addEventListener(() => {
|
|
|
+ if (this.snowParticleSystem) {
|
|
|
+ const modelMatrix = new Cesium.Matrix4.fromTranslation(this.scene.camera.position);
|
|
|
+ this.snowParticleSystem.modelMatrix = modelMatrix;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('雪天效果创建完成,粒子系统数量:', this.scene.primitives.length);
|
|
|
+ console.log('粒子系统颜色设置:', {
|
|
|
+ startColor: this.snowParticleSystem.startColor,
|
|
|
+ endColor: this.snowParticleSystem.endColor
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取当前天气类型
|
|
|
+ getCurrentWeather() {
|
|
|
+ return this.currentWeather;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 后处理阶段实现的雨天效果
|
|
|
+class RainEffect {
|
|
|
+ constructor(viewer, options) {
|
|
|
+ console.log('初始化 RainEffect');
|
|
|
+ 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.rainIntensity = Cesium.defaultValue(options.rainIntensity, 1.0); // 雨的强度
|
|
|
+ this.viewer = viewer;
|
|
|
+ console.log('RainEffect 初始化参数:', { tiltAngle: this.tiltAngle, rainSize: this.rainSize, rainSpeed: this.rainSpeed, rainIntensity: this.rainIntensity });
|
|
|
+ this.init();
|
|
|
+ }
|
|
|
+
|
|
|
+ init() {
|
|
|
+ console.log('创建后处理阶段');
|
|
|
+ this.rainStage = new Cesium.PostProcessStage({
|
|
|
+ name: "czml_rain",
|
|
|
+ fragmentShader: this.rain(),
|
|
|
+ uniforms: {
|
|
|
+ tiltAngle: () => this.tiltAngle,
|
|
|
+ rainSize: () => this.rainSize,
|
|
|
+ rainSpeed: () => this.rainSpeed,
|
|
|
+ rainIntensity: () => this.rainIntensity,
|
|
|
+ time: () => performance.now() * 0.001
|
|
|
+ },
|
|
|
+ });
|
|
|
+ console.log('后处理阶段创建完成:', this.rainStage);
|
|
|
+ this.viewer.scene.postProcessStages.add(this.rainStage);
|
|
|
+ console.log('后处理阶段添加到场景:', this.viewer.scene.postProcessStages.length);
|
|
|
+ }
|
|
|
+
|
|
|
+ rain() {
|
|
|
+ return `
|
|
|
+ uniform sampler2D colorTexture;
|
|
|
+ varying vec2 v_textureCoordinates;
|
|
|
+ uniform float tiltAngle;
|
|
|
+ uniform float rainSize;
|
|
|
+ uniform float rainSpeed;
|
|
|
+ uniform float rainIntensity;
|
|
|
+ uniform float time;
|
|
|
+
|
|
|
+ // 随机函数
|
|
|
+ float random(vec2 st) {
|
|
|
+ return fract(sin(dot(st, vec2(12.9898, 78.233))) * 43758.5453123);
|
|
|
+ }
|
|
|
+
|
|
|
+ void main(void) {
|
|
|
+ vec4 color = texture2D(colorTexture, v_textureCoordinates);
|
|
|
+
|
|
|
+ // 计算雨滴位置
|
|
|
+ float t = time * rainSpeed;
|
|
|
+ float rainDensity = 0.02 * rainIntensity;
|
|
|
+
|
|
|
+ // 倾斜角度
|
|
|
+ float angle = tiltAngle;
|
|
|
+ mat2 rotation = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
|
|
|
+
|
|
|
+ // 雨滴效果
|
|
|
+ vec2 uv = v_textureCoordinates * 10.0;
|
|
|
+ uv = rotation * uv;
|
|
|
+ uv.y += t * 0.01;
|
|
|
+
|
|
|
+ // 创建雨滴
|
|
|
+ float rain = 0.0;
|
|
|
+ for (int i = 0; i < 4; i++) {
|
|
|
+ vec2 grid = fract(uv * vec2(1.0, 20.0)) - 0.5;
|
|
|
+ float d = length(grid);
|
|
|
+ float size = rainSize * (1.0 + float(i) * 0.5);
|
|
|
+ float fade = smoothstep(size, size * 0.5, d);
|
|
|
+ rain += fade;
|
|
|
+ uv *= 1.5;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 应用雨滴效果
|
|
|
+ rain *= rainDensity;
|
|
|
+ color.rgb *= (1.0 - rain * 0.5);
|
|
|
+ color.rgb += rain * vec3(0.5, 0.6, 0.7); // 雨滴的颜色
|
|
|
+
|
|
|
+ gl_FragColor = color;
|
|
|
+ }
|
|
|
+ `;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示雨天效果
|
|
|
+ show() {
|
|
|
+ if (this.rainStage) {
|
|
|
+ this.rainStage.enabled = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 隐藏雨天效果
|
|
|
+ hide() {
|
|
|
+ if (this.rainStage) {
|
|
|
+ this.rainStage.enabled = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 销毁雨天效果
|
|
|
+ destroy() {
|
|
|
+ if (this.rainStage) {
|
|
|
+ this.viewer.scene.postProcessStages.remove(this.rainStage);
|
|
|
+ this.rainStage = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export default WeatherEffect;
|