有机猴灬残暴SamaLife · Code · Explore
返回文章
ARTICLE

Cesium 全局特效:雨、雪、雾与日照

把旧博客中 Cesium 全屏天气模拟的实现重新整理,记录后处理阶段、参数组织与着色器接入方式。

为什么使用后处理阶段

旧项目里已经实现了雨、雪、雾和日照效果。它们并不是给每一个模型单独加材质,而是在 Cesium 完成场景渲染后,通过 postProcessStages 对整张画面再处理一次。这样接入简单,也方便统一切换强、中、弱三个等级。

公共调用方式

核心入口只负责两件事:根据场景类型找到对应着色器,再把创建出的后处理阶段返回,方便调用方销毁。

CODE
import { PostProcessStage, PostProcessStageLibrary } from "cesium"

export function setSceneEffect(viewer, options) {
  if (["RAIN", "SNOW", "FOG"].includes(options.scene)) {
    return viewer.scene.postProcessStages.add(new PostProcessStage({
      name: options.scene + "_effect",
      fragmentShader: shaderMap[options.scene][options.level],
    }))
  }

  if (options.scene === "BEAM") {
    const stage = viewer.scene.postProcessStages.add(
      PostProcessStageLibrary.createBrightnessStage(),
    )
    stage.uniforms.brightness = brightnessMap[options.level]
    return stage
  }
}

雨景着色器的思路

雨滴来自屏幕坐标、时间和随机函数的组合。先把坐标旋转形成倾斜方向,再根据帧数推进雨滴,最后将计算出的颜色与场景原色混合。雨量大小不需要换算法,只要调整雨滴尺寸和混合比例。

CODE
float time = czm_frameNumber / 60.0;
vec2 resolution = czm_viewport.zw;
vec2 uv = (gl_FragCoord.xy * 2.0 - resolution.xy)
  / min(resolution.x, resolution.y);
float rain = clamp(abs(sin(20.0 * time + uv.y * 4.0)) - 0.95, 0.0, 1.0);
vec3 color = vec3(0.6, 0.7, 0.8) * rain * 35.0;
out_FragColor = mix(texture(colorTexture, v_textureCoordinates), vec4(color, 1.0), 0.42);

工程化建议

不要把所有 GLSL 塞进组件。把场景枚举、等级参数和 shader 源码拆成独立模块;切换前先移除上一个 stage;低性能设备默认使用较弱等级。这样天气效果才是一项可维护的能力,而不只是一次演示。