Godot 4 体积雾实战:godot-demo-projects 官方 Volumetric Fog 演示全解析

原创2026-10-02 16:12:201,898 阅读
文章标签:示例工程

Godot 4 体积雾实战:godot-demo-projects 官方 Volumetric Fog 演示全解析

体积雾(Volumetric Fog)是 Godot 4 在 Vulkan 渲染管线(Forward+)中提供的高质量大气效果,可模拟光线在雾介质中的散射、吸收与自发光。本指南以 godot-demo-projects 仓库中的 3d/volumetric_fog 官方演示为蓝本,完整拆解其核心特性、场景搭建、材质参数、灯光交互与实时调试方式。读完本文,你将掌握在 Godot 4 中启用体积雾、配置正负密度雾体、使用 3D 纹理调制密度、编写自定义 FogVolume 着色器,以及利用时间重投影与全局密度参数平衡画质与性能的完整方案。

Godot 4 体积雾演示运行截图,展示彩色雾块、发光雾与场景灯光融合效果

演示概览与运行前提

该演示以 GDScript 编写,专用于展示 Godot 体积雾在 Vulkan 渲染器(Forward+) 下的完整能力。根据 project.godot 中的声明:

  • config/features=PackedStringArray("4.7"),项目基于 Godot 4.7 特性构建;
  • run/main_scene="res://volumetric_fog.tscn",主场景即体积雾演示场景;
  • [rendering] 段开启了 MSAA 4x(anti_aliasing/quality/msaa_3d=2)、去偏色(use_debanding=true)、4 级各向异性过滤与高质量软阴影。

需要特别说明的是:体积雾依赖 Vulkan 渲染器,在 GL Compatibility(兼容)渲染器下不可用。该演示同样被发布在 Godot 官方 Asset Store 中,便于一键获取;其自定义噪声雾着色器改编自社区作者 alghost 公开分享的 Godot 4 雾效着色器方案。

体积雾核心能力总览

README 明确了该演示希望展示的五大能力,下文逐一结合场景与源码展开:

  1. 正/负密度体积:通过正密度雾体堆积雾气,通过负密度雾体在全局雾中"挖空"区域,同时密度会影响雾的 albedo(入射光散射)与 emission(自发光)。
  2. 多样形状与密度调制:支持盒子/椭球/圆锥/圆柱等基础形状、高度衰减(height falloff),并可用 3D 纹理对密度进行空间调制。
  3. 时间重投影:对体积雾逐帧结果做时间域重投影,提升稳定性、抑制闪烁,演示通过一个移动的雾体直观对比开启前后的差异。
  4. 全局密度调整:调整 Environment 的全局雾密度,配合正密度 FogVolume,可在场景中仅在指定区域应用体积雾。
  5. 自定义 FogVolume 着色器:使用 shader_type fog 编写实时 3D 噪声雾,让雾体获得流动、有机的动态形态。

场景解剖:volumetric_fog.tscn

主场景 volumetric_fog.tscn 由一个 WorldEnvironment、多组灯光、地面 CSG 几何体、十余个 FogVolume 节点与一个驱动移动雾体的 AnimationPlayer 构成。整体布局以"一处一个特性"的方式排布雾体,方便对照观察。

Environment:开启体积雾的第一步

场景中的 WorldEnvironment 使用 Environment 子资源,其中与体积雾直接相关的关键开关为:

volumetric_fog_enabled = true

同时环境还配置了程序化天空(ProceduralSkyMaterial)、ACES 色调映射(tonemap_mode = 4)与辉光(glow_enabled = true)。可见体积雾与天空背景、辉光效果可以协同工作——雾效叠加在天空之上,形成远景大气朦胧感。

FogVolume 家族与 FogMaterial 参数

场景中排布了多种 FogVolume 节点,全部使用 FogMaterial 或自定义 ShaderMaterial,涵盖 README 提到的全部特性组合。下表为从 volumetric_fog.tscn 提取的节点与参数对照:

节点 形状(shape) 尺寸 FogMaterial 关键参数 演示目的
FogVolumeNegativeDensity 默认椭球 8×8×8 density=-1.6842 负密度,抵消全局雾制造空洞
FogVolumeEllipsoid 椭球(0) 4×4×4 density=0.2、emission=绿色、edge_fade≈0 基础椭球发光雾
FogVolumeCone 圆锥(1) 4×4×4 density=0.2、emission=品红 锥形雾
FogVolumeCylinder 圆柱(2) 4×4×4 density=0.2、emission=品红 圆柱雾
FogVolumeEllipsoidHeightFalloff 椭球(0) 4×4×4 density=0.2、height_falloff=1000000 高度衰减
FogVolumeBox / FogVolumeBoxHeightFalloff 未显式设置 4×4×4 density=0.3、emission=红色,后者附加 height_falloff=1000000 大块体量雾与高度截断(从节点命名可推断其盒子体积的演示意图)
FogVolumeAlbedoTweak 默认椭球 8×8×8 density=0.1、albedo=Color(1,15,10) HDR albedo 增强入射光散射
FogVolumeBlue(挂在 MovingBox 下) 默认椭球 默认尺寸 albedo=Color(0,0,4)、edge_fade=0 移动雾体,用于对比时间重投影
FogVolumeTexture3D 默认椭球 32×32×4 density=2.0、emission=蓝色、density_texture=icon_outlined.png 3D 纹理密度调制
FogVolumeShader 默认椭球 32×8×32 ShaderMaterial(自定义 fog 着色器) 实时 3D 噪声雾

FogMaterial 参数速查(均有场景实例支撑):

  • density:雾体密度,可为负值——负密度体积会从已有雾中减去密度,常与全局密度配合实现"局部无雾"效果;
  • albedo:控制雾对入射光(如灯光的 light_volumetric_fog_energy)的散射系数,允许超过 1 的 HDR 数值以增强散射亮度;
  • emission:雾的自发光颜色,让雾体本身呈现彩色光晕(演示中绿、品红、蓝、红多色并置对比);
  • height_falloff:密度随高度变化的衰减速率,值越大密度随高度下降越剧烈。演示中的 FogVolumeEllipsoidHeightFalloff 将其设为 1000000,形成高度方向近乎瞬间的截断效果;
  • edge_fade:雾体边缘的淡出宽度,edge_fade=0 时边缘锐利,默认值则让边缘柔和过渡;
  • density_texture:绑定一个 Texture3D,在雾体空间内按纹素调制密度,实现复杂的不规则密度分布。

其中 FogVolumeTexture3D 使用的 density_texture 资源在场景中被声明为 CompressedTexture3D(res://icon_outlined.png),演示了将图片资源作为 3D 密度场使用的做法。

灯光:light_volumetric_fog_energy

体积雾的能量来源不仅依赖环境,还依赖场景灯光。场景中特意布置了四组灯光以展示灯光对体积雾的独立贡献(见 volumetric_fog.tscn):

  • OmniLight3D:黄色点光源,light_energy=2.0,常规照亮雾体;
  • OmniLight3DHighVolumetricEnergy:橙红色点光源,light_energy=0.1(对表面几乎无照明)但 light_volumetric_fog_energy=500.0,同时 light_specular=0——直观演示"对表面几乎不贡献光照,却能在雾中形成强烈光斑"的独立体积雾能量通道;
  • OmniLight3DShadow:黄色点光源并启用阴影,观察阴影对雾的影响;
  • SpotLight3D:蓝色聚光灯,light_volumetric_fog_energy=25.0、spot_angle=35,展示聚光灯在雾中形成光锥。

可见在实际项目中,light_volumetric_fog_energy 是控制"雾中光效"而无需增强表面照明的关键旋钮,适合用于打造手电筒光柱、霓虹光晕等效果。

移动雾体与时间重投影

AnimationPlayer 内置 move_fog_volume 动画(时长 10 秒、循环播放,autoplay 开启),驱动 MovingBox 节点连同其子节点 FogVolumeBlue 在空间中平移、旋转与放大(关键帧插值见场景中 Animation 子资源)。这颗"移动的蓝色雾体"正是 README 所述用于对比时间重投影开启前后差异的道具:重投影开启时,移动雾体保持平滑稳定;关闭时,体积雾采样在帧间抖动、易出现闪烁。

自定义着色器:实时 3D 噪声雾

FogVolumeShader 节点使用内嵌于 volumetric_fog.tscn 的 shader_type fog 着色器。其核心思路是用三层不同频率的 3D 梯度噪声叠加,驱动密度的动态起伏:

shader_type fog;

uniform float base_density: hint_range(0, 1) = 0.8;
uniform vec3 base_color: source_color;
uniform float fade_out_height = 2.0;
uniform float fade_out_distance = 1.5;

uniform vec3 noise_amounts = vec3(0.4, 0.35, 0.25); // 三层噪声权重,合计为 1
uniform vec3 noise_scales = vec3(1.0, 2.0, 4.0);     // 三层噪声频率
uniform vec3 noise_velocity1 = vec3(0.5, 0.0, 0.0);  // 各层流动速度
uniform vec3 noise_velocity2 = vec3(1, 0.0, -1);
uniform vec3 noise_velocity3 = vec3(0.0, 0.6, 0.3);

void fog() {
    vec3 base_pos = WORLD_POSITION * vec3(0.1, 0.5, 0.1);
    DENSITY = base_density;
    float noise1 = noise(base_pos * noise_scales.x + TIME * noise_velocity1) * noise_amounts.x;
    float noise2 = noise(base_pos * noise_scales.y + TIME * noise_velocity2) * noise_amounts.y;
    float noise3 = noise(base_pos * noise_scales.z + TIME * noise_velocity3) * noise_amounts.z;
    DENSITY *= smoothstep(-0.1, 0.0, noise1 + noise2 + noise3);
    DENSITY *= 1.0 - smoothstep(fade_out_height, fade_out_height + fade_out_distance, WORLD_POSITION.y);
    ALBEDO = base_color;
}

关键点解读:

  • 使用 Godot 内置的 WORLD_POSITION 与 TIME 内置变量,将世界坐标映射为噪声采样坐标,并用时间驱动噪声场平移,实现"流动的雾";
  • DENSITY 是 fog() 函数必须写出的输出,最终密度由基础密度乘以噪声平滑阈值与高度淡出系数得到;
  • 高度淡出用两次 smoothstep 组合:低于 fade_out_height 区域全密度,超过 fade_out_height + fade_out_distance 后密度归零,形成地平线附近集中、向上消散的雾层;
  • ShaderMaterial 实例中通过 shader_parameter/base_density = 1.0、base_color = Color(1, 0, 0, 1) 等参数覆盖默认值,雾体呈红色并可实时微调。

该着色器内嵌的 noise() 函数为 Inigo Quilez 的经典 3D 梯度噪声实现(MIT 许可),属于社区广为流传的 SDF/噪声配方,这也是 README 标注其来源的依据。

实时交互:camera.gd 与输入映射

volumetric_fog.tscn 中的 Camera3D 挂载 camera.gd,为演示提供了完整的"飞行相机 + 实时调参"能力,是理解体积雾各项参数作用的最快路径。相机启动即捕获鼠标(MOUSE_MODE_CAPTURED),支持:

  • 移动与视角:W/A/S/D 平移、鼠标视角(灵敏度 MOUSE_SENSITIVITY = 0.002,俯仰角限制在 ±1.57 弧度),移动带 0.85 的阻尼惯性;
  • 全局雾密度:左右方向键调整 environment.volumetric_fog_density,范围 0.0 ~ 1.0、步长 0.01(初始值 0.05)。将全局密度降到 0,即可验证"仅 FogVolume 覆盖区域有雾"的局部雾效玩法;
  • 时间重投影:空格键切换 volumetric_fog_temporal_reprojection_enabled;上下方向键/鼠标滚轮调整 volumetric_fog_temporal_reprojection_amount,范围 0.5 ~ 0.99、步长 0.01;
  • 体积雾质量:PageUp/PageDown 调整体积雾分辨率,经 RenderingServer.environment_set_volumetric_fog_volume_size() 在运行时生效,范围 16 ~ 384、步长 16。

屏幕左上角的 Label 会实时显示当前状态(雾密度、重投影开关与强度、分辨率 X×X×Z),左下角 HelpLabel 则列出全部快捷键,方便对照参数变化观察渲染差异。

对应的输入映射定义在 project.godot 的 [input] 段,动作名与绑定如下:

动作 按键/设备
move_forward / move_back / move_left / move_right W / S / A / D
toggle_mouse_capture Esc 与鼠标捕获切换
increase_fog_density / decrease_fog_density 右 / 左方向键
toggle_temporal_reprojection 空格
increase_temporal_reprojection / decrease_temporal_reprojection 上 / 下方向键或鼠标滚轮
increase_volumetric_fog_quality / decrease_volumetric_fog_quality PageUp / PageDown

渲染配置与质量权衡

体积雾以低分辨率 3D 纹理逐帧累积的方式计算,其分辨率直接决定开销。camera.gd 从 ProjectSettings 读取 rendering/environment/volumetric_fog/volume_size 与 volume_depth 作为初始质量(默认 64),再通过 RenderingServer.environment_set_volumetric_fog_volume_size(size, depth) 在运行时动态调整——这正是演示提供 PageUp/PageDown 快捷键的原因:在低端设备上可将分辨率降至 16×16×16 换取流畅度,在高端设备上可提升至 384 获得更细腻的雾体细节。

时间重投影则是"画质性价比"的另一个关键维度:开启后(amount 越高越依赖历史帧)能显著抑制闪烁与颗粒感,但对快速移动的雾体与相机,过高的重投影强度可能引入拖影,因此演示将可调范围限制在 0.5 ~ 0.99 并允许实时切换对比。

此外,project.godot 的 [rendering] 段还针对画质做了配套设定:soft_shadow_filter_quality=3(更柔和的阴影过滤)、textures/default_filters/anisotropic_filtering_level=4(4 倍各向异性过滤)、msaa_3d=2(4x MSAA)与 use_debanding=true(去色带)。这些设置与体积雾共同作用于最终画面,确保演示效果完整。

运行演示

  1. 使用 Godot 4.7(项目 config/features 声明为 "4.7")导入并打开 3d/volumetric_fog/project.godot;
  2. 确认渲染器为 Forward+(Vulkan)——这是体积雾可用的前提;
  3. 直接运行主场景 volumetric_fog.tscn(也可从场景文件双击预览);
  4. 进入场景后按 W/A/S/D 与鼠标移动观察各雾体,使用空格、方向键、滚轮与 PageUp/PageDown 实时调节密度、时间重投影与分辨率,对照屏幕左上角参数观察效果差异。

若要在自己的项目中复刻体积雾效果,最小步骤是:在 Environment 上勾选 Volumetric Fog(volumetric_fog_enabled)→ 添加 FogVolume 节点并赋予 FogMaterial(或自定义 fog 着色器)→ 为灯光设置合适的 light_volumetric_fog_energy → 按平台性能调整体积雾分辨率与时间重投影强度。本仓库中的 3d/volumetric_fog 演示即为以上全部参数与组合的最完整参考实现。

登录后查看全文
godot-demo-projects