从”一张贴图”到”活着的天气”:UE5 动态天气系统的 Niagara 实现方案
上周刚结束的 UE5 特效进阶班上,有个学员小王拿着他的作品集来找我。他的场景里下着雨,雨丝是用静态贴图加 UV 滚动做的,地面反光用的是 Cube Map,整体氛围感还行。但当我让他把镜头拉近,或者让角色在雨中跑动时,问题就全暴露了——雨丝穿模、没有溅射、没有风场扰动、雾效更是死板得像一层塑料膜。
他问我:”老师,为什么我做的雨看起来’假’?”
我告诉他,因为你还在用”贴图思维”做”动态系统”。真正的雨、雪、雾,是粒子系统的事,是 Niagara 的事。今天,我就把 UE5 里用 Niagara 实现动态天气系统的核心方案拆开揉碎讲给你听。这篇文章不聊虚的,直接上参数、上节点、上流程。
一、为什么你的雨是”贴图动画”,而我的雨是”物理交互”?
先说结论:UE5 的 Niagara 系统(5.0+ 版本)彻底改变了粒子特效的架构。它不再是 Cascade 时代那种”发射器+材质”的简单堆叠,而是基于 Data Interface 和 Simulation Stage 的 GPU 并行计算框架。
这意味着什么?意味着你可以让每滴雨滴拥有独立的 位置、速度、生命周期、碰撞反馈,甚至让它们相互影响。
核心痛点拆解:
1. 雨丝不真实:因为没做”拉伸”和”速度模糊”。真正的雨滴在视觉上是连续的线,而不是一个点。
2. 地面无反馈:雨滴落地必须产生涟漪或溅射,这需要 Collision Query(碰撞查询)和 Spawn Burst(爆发式生成)配合。
3. 风场是死的:真实的风是紊乱的,需要用 Noise Field(噪声场)或 Curl Noise(旋度噪声)来扰动粒子速度。
4. 雾效是平的:体积雾必须基于深度或高度渐变,而不是一张半透明贴图。
下面我们直接进入实操。
二、实操案例 1:从零搭建”暴雨”系统(含风场扰动与地面溅射)
目标:生成 15000 个雨滴粒子,每个粒子有独立速度,受噪声风场影响,落地后生成次级溅射粒子。
步骤 1:创建 Niagara 系统
打开 UE5.3,在 Content Browser 右键 → FX → Niagara System,选择 New system from a blank template。在 Emitter 添加里,选择 Empty,然后手动添加 GPU Emitter(注意:粒子数量大,必须用 GPU 模拟,CPU 会爆)。
步骤 2:设置粒子初始化参数
进入 Niagara Editor,找到 Emitter Update 选项卡,添加 Spawn Rate,设置为 15000。
在 Initialize Particle 模块中,设置:
- Lifetime:0.8~1.5(随机范围)
关键一步:速度设置
在 Initialize Particle 里添加 Set Velocity。这里不要用固定值,要用 Distribution 中的 Random Range。X 和 Y 轴速度设为 -50~50(受风影响),Z 轴设为 -1500~-2000(重力加速度)。
> 注意:真实雨滴的终端速度约为 9m/s,但 UE 单位是厘米,所以 -1500 到 -2000 是合理的。如果太小,雨会飘;如果太大,会穿透地面。
步骤 3:风场扰动(Curl Noise)
这是让雨”活”起来的关键。
在 Particle Update 中添加 Curl Noise Force 模块(需要启用 Niagara 的 Noise 插件,默认开启)。
此时���播放,会看到雨丝开始有了”倾斜”和”飘动”。
步骤 4:地面溅射(Collision + Sub-Spawn)
这是区分新手和老手的分水岭。
1. 在 Particle Update 添加 Collision 模块。
– Collision Type:DOP(Depth of Particle,深度缓冲碰撞)
– Collision Response:Halt(停止运动)
– Restitution:0.0(无弹跳)
– Friction:0.0
2. 在 Particle Update 中添加 Event Handler(事件处理器)。
– 事件类型:Collision
– 添加 Generate Location Event(生成位置事件)
3. 在 Niagara System 层级(不是 Emitter 层级)添加第二个 Emitter,命名为 `Splash`(溅射)。
– 这个 Emitter 的 Spawn Trigger 设置为 Event,绑定第一个 Emitter 的碰撞事件。
– 溅射粒子数量:每个事件生成 5~8 个粒子。
– 溅射粒子生命周期:0.2~0.4 秒,速度方向为 半球形随机(Z 轴向上 100~300)。
步骤 5:材质制作(拉伸雨丝)
创建材质,Shader Model 选 Unlit,Blend Mode 选 Translucent。
核心节点:
> 技巧:雨丝长度 = 速度 生命周期 0.1。在材质里用 Particle Size 的 Y 轴乘以速度的模长(Length),即可实现”下得越快,丝越长”。
三、实操案例 2:体积雾与飘雪——如何让雾”有深度”,让雪”有旋转”
雪和雾的难点不同。雪需要旋转和六角形晶体的视觉表现,雾需要深度渐晕和多层叠加。
步骤 1:飘雪系统(六角形晶体 + 旋转)
1. 创建新的 Niagara 系统,GPU Emitter,Spawn Rate = 5000(雪比雨少)。
2. 在 Initialize Particle 中:
– Shape Location:Sphere,半径 500(限制在场景范围内)
– Velocity:X/Y = -50~50,Z = -100~-200(雪花下落慢)
3. 在 Particle Update 中:
– 添加 Drag(阻力):值为 0.5,让雪花减速。
– 添加 Curl Noise Force:强度 100,频率 0.3,让雪花有”翻飞”感。
4. 关键:旋转。添加 Orient Mesh to Velocity 或 Set Rotation。
– 如果用 Sprite(面片),在材质里用 Particle Rotation 节点,并设置 Rotation Rate 为 -1~1 随机(每帧旋转角度)。
– 如果用 Mesh(模型),导入一个六角形冰晶��型,用 Add Velocity 模块的 Torque 添加随机扭矩。
步骤 2:体积雾(深度渐变 + 噪声扰动)
UE5 自带 Exponential Height Fog,但那是”全局雾”。要做出”一团一团的雾”或”贴着地皮的雾”,需要 Niagara 配合 Scene Depth。
1. 创建 Niagra 系统,Sprite 渲染,但材质使用 Volume 概念。
2. 在材质中:
– 获取 Scene Depth(场景深度)和 Pixel Depth(像素深度)。
– 计算 Fog Density = 1 – (SceneDepth / MaxDistance)。
– 用 Noise Texture 采样,乘以密度,得到”块状”雾。
3. 在 Niagara 中,使用 Scale Sprite 模块,让雾粒子大小随机(半径 200~800),并缓慢上浮(Z 轴速度 10~20)。
> 进阶:使用 Niagara Volume Renderer(5.2+ 支持)可以渲染真正的 3D 体积雾,但性能开销大,适合远景。近景推荐用 Sprite 加深度雾化。
四、性能优化与踩坑指南
很多同学做完系统一运行,帧率直接掉到 20。这里给几个硬性指标:
| 参数 | 数值建议 | 说明 |
|——|———-|——|
| 雨滴粒子数 | ≤ 20000 | 超过这个数,GPU 模拟���会吃力 |
| 溅射粒子数 | ≤ 5000 | 事件生成,瞬时量大,注意生命周期 |
| 雪花粒子数 | ≤ 10000 | 因为雪花需要旋转,计算量大 |
| 雾粒子数 | ≤ 2000 | 雾粒子大,覆盖广,不需要太多 |
| 碰撞查询类型 | DOP | 比 Raycast 快 10 倍 |
| 渲染器类型 | GPU Sprite | 不要用 CPU 渲染粒子 |
常见坑:
1. 雨丝穿模:Collision 的 DOP 模式只检测深度缓冲,如果地面是半透明材质(如水面),会直接穿过。解决方案:在水面上加一个 Invisible Collision Box。
2. 风场太乱:Curl Noise 的 Frequency 不要超过 0.5,否则粒子会像苍蝇一样乱飞。
3. 溅射方向不对:Event Handler 里要设置 Spawn Direction 为 Surface Normal,否则溅射是随机方向。
4. 雾太”实”:雾材质里一定要做 Depth Fade(深度淡出),否则雾会遮住角色。
五、总结与进阶建议
今天讲的两个案例,一个是”雨+风+溅射”,一个是”雪+体积雾”,基本覆盖了动态天气系统的 80% 需求。核心逻辑就三句话:
1. 粒子数量不是越多越好,关键在于用 Noise 和 Event 让粒子之间产生关联。
2. 材质决定视觉上限,Niagara 只负责”动”,”像不像”全靠材质里的 Scene Depth、Particle Velocity 这些节点。
3. 性能是设计出来的,不是优化出来的。一开始就规划好粒子数量、碰撞类型和渲染方式。
进阶方向:
最后给个学习路径建议:先把我上面两个案例做出来(每个 2 小时),然后去研究 Niagara 的 Data Interface(特别是 Collision Query 和 Neighbor Grid),最后再看 UE5 官方的 Niagara Fluids 插件(5.1+)——那是做雨幕、水坑的高级玩法。
做动态天气,本质是用计算换真实。当你不再执着于”画”雨,而是开始”算”雨的时候,你的特效就真正”活”了。
—
常见问题 FAQ
Q1:为什么我的雨滴在高速运动时会出现”拖影”或”断裂”?
A:这是 GPU 粒子在高速运动时常见的”瞬移”问题。解决方案:在粒子 Update 中启用 Motion Blur,或者在材质里用 Particle Velocity 做”速度拉伸”(Velocity Stretch),而不是依赖渲染器的 TAA。另外,确保你的 Max Tick Delta Time 不超过 0.05,否则物理步长太大会导致碰撞穿透。
Q2:Niagara 的 Curl Noise 和普通 Noise 有什么区别?为什么我用普通 Noise 风场会”乱”?
A:Curl Noise(旋度噪声)是矢量场,其散度为零,意味着粒子不会向某个方向聚集或发散,运动轨迹是”涡旋”状的,更自然。普通 Noise 是标量场,如果直接用于力,会产生”推挤”效果,导致粒子向某一侧漂移。做风场、水流,务必选 Curl。
Q3:我想让雨滴打在角色身上产生水花,但角色是 Skeletal Mesh,DOP 碰撞检测不到,怎么办?
A:DOP 碰撞是基于深度缓冲的,骨骼网格体如果材质是半透明或没有写入深度,就无法检测。解决方案:使用 Async Collision Query(异步碰撞查询),指定一个 Collision Channel(如 Pawn),用 Sphere Overlap 检测。但这比较耗性能,建议只对靠近摄像机的少量粒子开启。
Q4:体积雾用 Sprite 渲染,怎么避免”十字交叉”的视觉穿帮?
A:这是老问题了。解决方案有三种:1. 将 Sprite ��� Alignment 改为 Velocity(速度对齐),让雾片方向与运动方向一致;2. 使用 Flipbook(序列图动画)代替静态贴图;3. 最推荐——使用 Mesh Renderer,用低模的球体或云朵模型,配合 Custom Sorting,避免半透明穿插。
Q5:UE5.4 的 Niagara 和 5.0 相比,做天气系统有什么新特性?
A:5.4 引入了 Niagara Fluids(2D/3D 流体模拟)的正式版,可以直接做雨幕的水面涟漪,而不用自己写 RT 逻辑。另外 Neighbor Grid 3D 网格支持更高效,可以做出”雨滴互相碰撞反弹”的效果。如果你还在用 5.0,建议升级到 5.3+,性能提升明显(尤其是 GPU 粒子编译速度)。


评论(0)