UE5 动态天气系统:雨、雪、雾的 Niagara 实现方案

上个月,一位参与开放世界项目学员找到我,说他们团队卡在天气系统上整整两周——雨滴穿透屋顶、雪花像塑料片、雾气让场景帧率直接腰斩。这是很多UE5开发者都会踩的坑:用传统粒子系统做天气,要么性能爆炸,要么效果假得离谱。今天,我们就用Niagara 5.3版本,从零搭建一套可动态切换的雨雪雾系统,重点解决“穿透问题”和“性能优化”两个硬骨头。

一、雨滴系统:从“穿模”到“真实碰撞”

1.1 问题复现与解决方案

大多数开发者直接用Niagara的“Sprite Renderer”发射粒子,结果雨滴会直接穿过建筑和地形。核心原因在于:UE5默认粒子不参与碰撞检测。我们需要为雨滴添加“场景查询”和“物理碰撞”两个模块。

1.2 操作步骤:构建防穿透雨滴

Step 1:创建Niagara发射器

  • 打开Content Browser,右键选择 `FX -> Niagara Emitter`,命名为 `Rain_Droplet`
  • 在Emitter属性面板,将 `Emitter Update` 的 `Spawn Rate` 设为 `5000`(每秒5000粒子,根据场景调整)
  • 修改 `Particle Spawn` 模块:添加 `Initialize Particle`,设置 `Lifetime` 为 `2.0`秒,`Sprite Size` 随机范围 `(0.5, 1.5)`
  • Step 2:启用碰撞

  • 在Particle Update中添加 `Collision` 模块
  • 选择 `Collision Mode` 为 `Scene Query`(场景查询模式)
  • 设置 `Collision Channel` 为 `WorldStatic`(仅碰撞静态物体)
  • 关键参数:`Friction` 设为 `0.0`(让雨滴沿表面滑落),`Bounce Restitution` 设为 `0.1`(微小弹跳模拟溅射)
  • Step 3:添加风力影响

  • 添加 `Force` 模块,选择 `Wind` 类型
  • 在 `Wind` 参数中,将 `Wind Speed` 绑定到场景中的 `BP_WindController`(自定义蓝图)
  • 设置 `Turbulence` 为 `0.3`,让雨滴产生随机飘移
  • Step 4:材质优化

  • 创建材质 `M_RainDrop`,使用 `Translucent` 混合模式
  • 核心节点:将 `Particle Color` 的Alpha通道设为 `0.3`,并添加 `Sine` 函数让透明度周期性变化,模拟雨滴下落时的视觉模糊
  • 注意:禁用 `Receive Decals` 和 `Cast Shadow`,减少渲染开销
  • 雨滴碰撞效果示意图

    二、雪花系统:解决“塑料感”和堆积效果

    2.1 雪花的核心痛点

    学员反馈“雪花像碎纸片”,问题出在两方面:粒子旋转不自然、没有堆积效果。我们需要用Niagara的 `Mesh Renderer` 替代Sprite,并添加 `Depth Fade` 模拟积雪。

    2.2 操作步骤:构建真实雪花

    Step 1:创建雪花发射器

  • 复制 `Rain_Droplet` 发射器,重命名为 `Snow_Flake`
  • 修改 `Spawn Rate` 为 `2000`(雪量较少)
  • 将 `Sprite Renderer` 替换为 `Mesh Renderer`,选择 `SM_Flake`(六边形雪花模型)
  • Step 2:旋转与浮力

  • 在Particle Update中添加 `Rotate` 模块,设置 `Rotation Rate` 随机范围 `(-180, 180)` 度/秒
  • 添加 `Drag` 模块,设置 `Linear Drag` 为 `0.5`,模拟空气阻力
  • 关键:添加 `Buoyancy` 模块(需启用 `Physics` 功能),设置 `Buoyancy` 值为 `0.8`,让雪花下落更缓慢
  • Step 3:地表积雪模拟

  • 创建 `BP_SnowAccumulation` 蓝图,使用 `Decal Actor` 接收雪花碰撞
  • 在雪花粒子的 `Collision` 模块中,勾选 `Generate Hit Events`
  • 在蓝图中用 `Spawn Decal at Location` 生成半透明雪斑,逐渐叠加形成积雪
  • Step 4:性能优化技巧

  • 使用 `LOD` 模块:当粒子距离相机 > 50米时,切换为Sprite渲染
  • 设置 `Max Particles` 为 `5000`,超出部分自动剔除
  • 雪花堆积效果演示

    三、雾气系统:性能与视觉的平衡

    3.1 传统雾气的缺陷

    UE5自带的 `Exponential Height Fog` 虽然简单,但无法实现动态流动和局部浓度变化。我们需要用Niagara的 `Volume Renderer` 构建体素雾。

    3.2 操作步骤:构建动态体积雾

    Step 1:创建体积雾发射器

  • 新建Niagara发射器,选择 `Volume` 类型
  • 设置 `Emitter Update` 的 `Spawn Rate` 为 `100`(粒子数少,但每个粒子代表一个雾块)
  • 使用 `Mesh Renderer`,模型选择 `SM_Sphere`,缩放 `(100, 100, 100)`
  • Step 2:流动动画

  • 在Particle Update中添加 `Noise` 模块,设置 `Noise Mode` 为 `3D`
  • 绑定 `Position` 到噪声输出,让雾块缓慢漂移
  • 设置 `Speed` 为 `0.5`,`Frequency` 为 `0.1`,产生自然流动
  • Step 3:透明度控制

  • 在材质中,将 `Opacity` 与粒子 `Age` 关联:`Opacity = 1 – (Age / Lifetime)`,实现渐隐效果
  • 添加 `Depth Fade` 节点,设置 `Fade Distance` 为 `500`,让雾与物体交界处柔和过渡
  • Step 4:性能杀手:剔除与LOD

  • 启用 `Cull by View Frustum` 模块
  • 设置 `Min Screen Size` 为 `0.01`,当雾块在屏幕上小于1%时自动剔除
  • 使用 `Fixed Bounds` 限制雾的范围,避免覆盖整个关卡
  • 体积雾流动效果

    四、系统整合:动态天气切换

    4.1 蓝图控制逻辑

    创建 `BP_WeatherManager` 蓝图,包含三个Niagara组件:

  • `RainSystem`、`SnowSystem`、`FogSystem`
  • 核心逻辑:
    1. 暴露 `WeatherType` 枚举(Rain/Snow/Fog)
    2. 切换时,先 `Deactivate` 当前系统,再 `Activate` 目标系统
    3. 添加 `Blend Time` 参数(0-5秒),通过 `Set Float Parameter` 平滑过渡粒子密度

    4.2 性能监控建议

  • 使用 `Niagara Debugger`(Ctrl+Shift+W)查看粒子数
  • 保持总粒子数不超过20000(高端显卡可放宽至50000)
  • 对移动端:将 `Spawn Rate` 降低至30%,并禁用体积雾
  • 五、总结与进阶建议

    这套系统的核心在于:用Niagara的碰撞模块解决穿透问题,用体积渲染实现动态雾效,用蓝图控制实现平滑切换。建议学员先完成雨滴系统,再逐步添加雪和雾,每次只优化一个性能瓶颈。

    进阶方向
    1. 结合 `Environment Query System (EQS)` 让天气影响AI行为(如雨天敌人视野缩短)
    2. 使用 `Chaos Physics` 模拟雨水对物体的物理冲击
    3. 将天气数据写入 `Substrate Output`,实现材质表面湿润效果

    常见问题 FAQ

    Q1:雨滴碰撞后出现“卡在墙上”的情况,如何解决?
    A:检查 `Collision` 模块的 `Friction` 参数是否过高,建议设为0.0。同时确保场景物体使用 `Complex Collision`(而非Simple Collision),避免粒子卡在网格缝隙中。

    Q2:雪花堆积效果导致帧率骤降,怎么优化?
    A:限制雪斑Decal数量(建议≤50个),并使用 `Pooling` 系统复用Decal。另外,在 `BP_SnowAccumulation` 中设置 `Life Span` 为10秒,超时自动销毁。

    Q3:雾气穿透物体,看起来不真实?
    A:在雾气材质中添加 `Scene Depth` 节点,计算雾与物体的距离,实现“雾中物体可见”效果。具体做法:`Opacity = saturate( (Depth – ObjectDepth) / FadeDistance )`。

    Q4:如何让雨滴产生溅射效果?
    A:在雨滴碰撞事件中,Spawn一个子发射器 `Rain_Splash`。子发射器使用 `Sprite Renderer`,粒子大小 `0.2-0.5`,生命周期 `0.1秒`,并添加 `Scale` 动画(从0到1再归零)。

    Q5:天气切换时出现“闪烁”现象?
    A:这是 `Activate/Deactivate` 的时序问题。建议使用 `Set Paused` 代替 `Deactivate`,并在切换前先 `Set Visibility` 为隐藏,完成后再显示。

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。