UE5 动态天气系统:雨、雪、雾的 Niagara 实现方案
上周在火星人教育的 UE5 特效进阶班上,一位学员小李拿着他刚做好的开放世界场景问我:“老师,为什么我用默认粒子系统做的雨,一下雨帧率就掉到 20 帧?而且雨丝看着像塑料条,完全没有真实感。”这个问题其实非常典型——很多开发者用传统 Cascade 做天气特效时,要么性能崩盘,要么视觉效果假到离谱。今天我们就用 UE5 的 Niagara 系统,从底层逻辑出发,手把手构建一套可商用的动态天气系统,涵盖雨、雪、雾三种核心天气。
一、为什么选择 Niagara 做天气系统?
在 UE5.3 及以上版本(本文基于 UE5.4.2 测试),Niagara 已经彻底取代了 Cascade。但很多人只是把 Niagara 当“更强的粒子系统”用,忽略了它的数据驱动架构和GPU 计算优势。
传统 Cascade 做雨:每个粒子独立模拟位置,CPU 计算碰撞,10000 个粒子就能让低端显卡喘气。而 Niagara 的 GPU 模拟模式(`GPUComputeSim`)允许我们同时处理 50 万+粒子,且通过 Emitter State 模块控制生命周期,配合 Spawn Rate 动态调整,性能开销反而更低。
核心工具准备:
- UE5.4.2(建议 5.3+,因为 Niagara Fluids 功能更稳定)
二、实操案例一:高性能真实雨滴系统
2.1 基础粒子设置
打开 Niagara 编辑器,创建 `NS_RainSystem`,选择 GPU Compute Sim 模板。关键参数如下:
Emitter 属性:
关键模块配置:
1. 在 `Particle Spawn` 阶段添加 `Set Random Seed`(避免重复模式)
2. 使用 `Add Velocity` 模块,给 X/Y 轴添加 0~50 cm/s 的随机偏移(模拟风力扰动)
3. 在 `Particle Update` 阶段,用 `Scale Color` 模块让雨滴透明度随生命值衰减(从 0.8 降到 0.2)
2.2 碰撞与地面效果
雨滴必须与场景碰撞才能真实。但 80K 粒子全部做碰撞检测会炸性能。这里用 Distance Culling 策略:
在 `Particle Update` 中添加 `Collision` 模块:
然后添加 `Spawn Burst Instantaneous` 模块,在碰撞位置生成��级粒子:
性能优化技巧: 在 `Emitter State` 中开启 `Use Max Particles` 设为 100000,并勾选 `Cull When Not Visible`。这样当雨滴离开相机视野时,Niagara 会自动暂停计算,节省 40% 以上性能。
2.3 材质与视觉增强
雨滴材质 `M_RainDrop` 需要半透明和折射效果:
// 自定义节点实现雨滴变形
float2 UV = GetDefaultTextureCoordinates();
float Distortion = sin(UV.x 50 + Time 10) * 0.02;
UV += Distortion;
return Texture2DSample(Tex, TexSampler, UV);
在材质中开启 `Translucent` 混合模式,`Lighting Mode` 选择 `Surface Translucency Volume`,配合 `Subsurface Color` 让雨滴有半透明感。
三、实操案例二:动态雪系统与雾效融合
3.1 雪花粒子的物理模拟
雪和雨的核心区别在于:雪有飘落轨迹、旋转和堆积效果。创建 `NS_SnowSystem`,使用 CPU Sim(因为需要每帧计算旋转和风力影响)。
粒子属性:
风力系统集成:
在场景中放置 `BP_WeatherManager`,暴露一个 `WindStrength` 变量(0~100)。在 Niagara 的 `Particle Update` 中,通过 `User Exposed` 参数绑定该变量:
// 风力影响公式
Velocity.X += WindStrength 0.5 sin(Time * 0.3);
Velocity.Y += WindStrength 0.3 cos(Time * 0.5);
Velocity.Z = -50 - WindStrength * 0.2; // 下落速度受风力影响
3.2 地面积雪的实时生成
用 Niagara 模拟雪堆积不现实(粒子数量爆炸)。这里用 Runtime Virtual Texture(RVT) 方案:
1. 在场景中放置 `RuntimeVirtualTextureVolume`,设置分辨率 2048×2048
2. 在雪材质 `M_SnowGround` 中,采样 RVT 的 Alpha 通道
3. 当雪花粒子碰撞地面时,通过 `Spawn Burst` 生成一个 `Decal` 组件,将雪纹理写入 RVT
蓝图控制逻辑:
// 在 BP_WeatherManager 的 Tick 中
if (SnowIntensity > 0.5f)
{
// 每帧更新 RVT 的雪覆盖范围
RVTVolume->SetWorldLocation(PlayerCamera->GetComponentLocation());
// 动态调整积雪厚度
SnowMaterial->SetScalarParameterValue("SnowDepth", SnowIntensity * 5.0f);
}
3.3 雾效的 Niagara 实现
传统雾效用 `ExponentialHeightFog` 即可,但动态雾(比如雾随海拔变化)需要 Niagara。创建 `NS_FogSystem`,使用 `Sprite Renderer` 模式。
关键技巧:
性能注意: 雾粒子不要超过 2000 个,否则 GPU 带宽会饱和。配合 `Cull Proxy Volume` 只在玩家周围 50 米内生成。
四、蓝图集成与动态天气切换
4.1 天气管理器蓝图
创建 `BP_WeatherManager`,包含三个 Niagara 系统引用:
UPROPERTY(EditAnywhere)
UNiagaraComponent* RainSystem;UPROPERTY(EditAnywhere)
UNiagaraComponent* SnowSystem;
UPROPERTY(EditAnywhere)
UNiagaraComponent* FogSystem;
在蓝图事件图表中,暴露 `SetWeatherType(WeatherType NewWeather)` 函数:
Switch on NewWeather:
- Rain: 激活 RainSystem,停用 SnowSystem,FogSystem 透明度设为 0.3
- Snow: 激活 SnowSystem,停用 RainSystem,FogSystem 透明度设为 0.6
- Fog: 停用 Rain 和 Snow,FogSystem 透明度设为 0.9
- Clear: 全部停用,透明度过渡 2 秒
4.2 过渡动画实现
直接��� Niagara 的 `SetFloatParameter` 做淡入淡出太生硬。建议用 `Timeline` 节点:
// 在蓝图 Tick 中
float TargetAlpha = (CurrentWeather == Rain) ? 1.0f : 0.0f;
float CurrentAlpha = FMath::FInterpTo(CurrentAlpha, TargetAlpha, DeltaTime, 3.0f);
RainSystem->SetFloatParameter("Opacity", CurrentAlpha);
这样切换天气时有 3 秒的平滑过渡,视觉上非常自然。
五、性能调优与常见坑
5.1 粒子数量与 LOD
不同平台需要不同粒子密度:
在 Niagara 的 `Emitter State` 中,通过 `LOD` 设置不同级别:
LOD 0: SpawnRate 80000
LOD 1: SpawnRate 40000
LOD 2: SpawnRate 15000
然后在项目设置中绑定 `Scalability` 的粒子 LOD 等级。
5.2 常见问题排查
问题1:雨滴闪烁
原因:粒子大小与屏幕分辨率不匹配。解决方案:将 `Particle Size` 的 Z 轴改为 `ScreenSize` 模式,让雨滴在屏幕上保持固定像素宽度。
问题2:雪粒子穿透地形
原因:碰撞检测精度不够。在 `Collision` 模块中,将 `Collision Trace Channel` 改为 `Visibility`,并勾选 `Complex Collision`。
问题3:雾效导致帧率骤降
原因:雾粒子渲染开销大。改用 `Mesh Renderer` 模式,用低多边形球体代替 Sprite,配合 `Instanced Static Mesh` 减少 Draw Call。
常见问题 FAQ
Q1:Niagara 系统在运行时动态调整粒子数量,会不会导致卡顿?
A:不会。Niagara 的 `SpawnRate` 参数支持运行时修改,引擎会自动调整粒子池大小。但注意不要频繁在每帧修改,建议用 Timeline 做渐变。
Q2:雨滴碰撞生成的水花效果,如何避免粒子重叠?
A:在次级粒子的 `Spawn Burst` 中,添加 `Random Position Offset` 模块,偏移范围设为 5~15cm。同时限制每个主粒子最多生成 1 个次级粒子。
Q3:雪景中如何让角色脚印显示在积雪上?
A:使用 `Decal Actor` 配合 `Material Parameter Collection`。当角色移动时,在脚底位置生成 Decal,材质中采样 `SnowDepth` 参数,脚印区域将雪纹理替换为泥土纹理。
Q4:动态天气系统支持多人联机吗?
A:支持。将 `BP_WeatherManager` 设为 `Replicated`,在 `Multicast` 事件中同步天气类型和强度参数。Niagara 组件本身不复制,但参数变化会通过 RPC 同步。
Q5:为什么我的雾效在室内场景显得很假?
A:因为雾粒子没有考虑遮挡。在 Niagara 中开启 `Use Depth Buffer`,让雾粒子的透明度根据与场景物体的距离衰减。或者使用 `Volumetric Fog` 配合 Lightmass 烘焙。
学习进阶建议
1. 掌握 Niagara 的三种模拟模式:GPU 用于大批量粒子(雨),CPU 用于复杂逻辑(雪),Fluid 用于体积效果(雾)。不要混用模式,否则性能会打折扣。
2. 深入理解材质中的 World Position Offset:天气特效的视觉质感 70% 靠材质。建议在材质中多用 `Sine` 和 `Noise` 节点做动态变形,避免粒子看起来像平面贴图。
3. 结合 AIGC 生成天气纹理:尝试用 Stable Diffusion 生成雨滴法线贴图、雪花噪声图,再导入 UE5 作为 Niagara 的 `Texture` 输入。能大幅提升视觉独特性。
4. 关注 UE5.5 的 Niagara Fluids 更新:新版本将支持 GPU 流体模拟,可以直接生成动态水雾和雪花飘落轨迹,省去手动调噪波的痛苦。
最后,天气系统的核心不是“看起来很炫”,而是“让玩家感觉真实”。多观察现实中的雨雪形态——雨丝是倾斜的、雪花是旋转的、雾是流动的。把这些物理细节量化成参数,你的天气系统就成功了一半。

评论(0)