在 Godot 中用粒子系统搭出可信的雨天:效果分层、参数思路与避坑清单
【免费下载链接】godotGodot Engine – Multi-platform 2D and 3D game engine项目地址: https://gitcode.com/GitHub_Trending/go/godot
这篇基于 Godot 引擎(4.x)源码与类文档,讲如何用 Godot 粒子系统做出下雨、雾等天气效果。你会看到效果该拆成哪三层、该选哪个节点、关键参数怎么调,以及落地反馈和性能适配的具体做法,读完可以直接在自己的场景里落地一套雨天表现。
雨天效果应该做到哪三层
把"下雨"当一整坨去调,往往调到最后雨还是假的。建议按表现优先级拆成三层,逐层验收:
第一层:雨幕。画面里要能看出"正在下雨"这件事——一片从屏幕上方持续落下的雨点,带轻微倾斜和速度差。这一层靠发射形状和初速度就能完成,成本最低。
第二层:落地反馈。雨点接近地面时要"消失得有交代":淡出、缩放收小,或者在地面位置冒出一小簇水花。没有这一层的雨天,雨滴会直接穿过角色脚下的地板,穿帮感很强。
第三层:氛围。远景的雾、地面湿润的反光感、雨声音效的响度随雨势变化。这一层粒子数量可以很少,主要靠渲染层(雾、泛光)和音频层配合。
三层里第一层占 80% 的工作量,第三层占 80% 的"像不像真雨"评分。
资源与节点:GPUParticles2D 还是 CPUParticles2D
场景里粒子节点的实现位于 scene/2d/,类文档在 doc/classes/ 下,两个 2D 节点值得对比:
| 维度 | GPUParticles2D | CPUParticles2D |
|---|---|---|
| 更新位置 | GPU 侧,按帧推进 | CPU 主循环逐个计算 |
| 大数量表现 | 500+ 粒子仍稳定 | 数量上去后帧率明显波动 |
| 碰撞支持 | 仅能与 LightOccluder2D 碰撞,不与刚体交互 | 同左,不能与物理体直接交互 |
| 适用场景 | 全屏雨幕、持续天气 | 少量、需要精确手动控制的粒子 |
结论比较直接:雨天这种"数量大、行为简单"的效果,优先用 GPUParticles2D,让粒子在 GPU 侧更新,把 CPU 留给游戏逻辑。CPUParticles2D 更适合小范围、需要逐粒子写脚本的场景。
两个节点的粒子外观和行为都挂在 ParticleProcessMaterial 上(见 doc/classes/ParticleProcessMaterial.xml),天气效果常用的几组配置:
amount = 400 # 同时存活的粒子数,先给保守值 lifetime = 1.2 # 单颗雨滴的存活时长,决定"雨速观感" emission_shape = RECTANGLE emission_rect_extents = Vector2(640, 4) # 顶部一条窄带,宽度对齐视口 direction = Vector2(0.15, 1) # 略倾斜,避免雨丝完全垂直 spread = 6 # 角度抖动,制造快慢差异 gravity = Vector2(0, 900) # 2D 里用重力模拟雨势 scale_amount_min / scale_amount_max # 近大远小的粗细变化贴图用一张细长的软边白色竖条(PNG 即可),比圆形粒子更像雨丝;颜色加一点蓝灰,雨天观感立刻出来。
让雨滴落地更可信
拿一个具体场景说思路:角色站在平台上,雨点从头顶落下。
第一步,算下落距离。发射带放在视口顶部、地面在视口底部,假设距离 540px,重力 900px/s²,可以反推出生存时长大约 1 秒上下。把 lifetime 设成略大于这个值,雨点就能"走完全程"再消失,而不是在半空莫名蒸发。
第二步,处理"消失"。2D 粒子无法直接和 StaticBody2D 交互(类文档里明确写了只支持 LightOccluder2D 碰撞),所以更稳的做法是:在地面位置放一个one_shot的小型水花发射器,触发时机用两条路——要么雨滴系统配合区域检测,按雨势周期性触发;要么更省事,用粒子年龄驱动 scale/alpha 曲线,让雨滴在最后 10% 寿命里快速缩小淡出。玩家对"贴地消失"的敏感度,远高于对"精确水花"的敏感度。
第三步,加一点随机。水花发射器的amount给区间而不是定值,初速方向在 ±30° 内抖动,水花就不会每次都长得一模一样。
第四步,雨幕分层。远景再放一层粒子:数量减半、scale 更小、alpha 更低、速度更慢,放在更低的渲染层。近锐远糊的层次感,比单层的数量更有说服力。
性能与平台适配清单
| 项目 | 做法 | 说明 |
|---|---|---|
| 粒子总量 | 桌面 400~800,移动端压到 150~300 | 2D 粒子瓶颈多在 draw call 与混合,不在计算 |
| 距离衰减 | 远景层用更小贴图 + 更低 alpha | 远处用简化表现,省混合开销 |
| 纹理 | 一张 64×64 以内的雨丝贴图,避免大尺寸 | 粒子贴图会被 GPU 反复采样 |
| 雾 | 用一张全屏半透明雾图或 WorldEnvironment 的雾参数 | 不要试图用粒子模拟体积雾 |
| 音效 | AudioStreamPlayer 播放雨声,雨势变化时调音量/切换采样 | 音效是氛围层的大头,成本极低 |
| 动态开关 | 按 OS 信息或用户设置切换发射量 | 比硬编码一套参数更友好 |
常见问题排查
雨根本看不见。检查 process material 的 color 是不是被设成透明、scale_amount 是不是小到接近 0;另外确认 GPUParticles2D 所在节点的 z_index 没有被场景里的大面积半透明节点盖住。
雨速忽快忽慢、帧率低时乱飘。这是帧时间不稳把粒子推进时间带偏了。先别急着加粒子,确认主循环里没有每帧分配内存的脚本;天气粒子应该是最先被保护、而不是最先被牺牲的对象。
雨滴穿过地面/角色。再次提醒:2D 粒子不与物理体碰撞,这是引擎设计而非 bug。落地反馈要走"触发式水花 + 年龄驱动淡出"这条路,别在 2D 粒子身上找物理碰撞开关。
切到 Web 导出后效果变差。Web 端 GPU 能力参差,把发射量砍一半、雾层改静态图,体验下降远小于掉帧带来的卡顿。
下一步可以练什么
- 做一条"晴 → 小雨 → 暴雨"的曲线,把发射量、雾浓度、雨声音量挂到同一个进度值上,练习天气过渡的插值。
- 给雨滴加风力:一个方向力随时间做正弦摆动,观察
spread和direction的联动效果。 - 把落地水花做成可复用资源,放到场景库里,下次做雪、雾时只换贴图和参数。
粒子系统的文档入口在 doc/classes/GPUParticles2D.xml 和 doc/classes/CPUParticles2D.xml,参数拿不准时对照着改,比凭感觉调要快得多。
【免费下载链接】godotGodot Engine – Multi-platform 2D and 3D game engine项目地址: https://gitcode.com/GitHub_Trending/go/godot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考