现象:为什么传统雾效在动态光照下“露馅”?

在UE5中,当你用指数高度雾(Exponential Height Fog)搭建清晨山谷时,第一缕定向光斜射进来,雾会整体变亮——但真实世界的丁达尔效应(Tyndall effect)要求光在介质中发生各向异性散射,且散射强度随介质密度、粒子尺度剧烈变化。指数高度雾的密度场是解析函数(仅随高度指数衰减),无法表达云团内部的空洞、边缘的絮状结构,更无法让局部区域对光源产生“自阴影”。这就是为什么影视级云雾必须引入体积纹理(Volume Texture)——一种在三维网格中存储密度、温度、速度等标量/矢量场的离散数据结构。现象背后是一个根本矛盾:解析雾是连续的但缺乏空间细节,体积纹理是离散的但能承载任意复杂场。理解这个矛盾,就理解了UE5体积云雾的全部设计逻辑。

UE5体积纹理云雾:从体素空间到光线步进的原理级拆解 - 配图1
UE5体积纹理云雾:从体素空间到光线步进的原理级拆解

原理:体素空间与光线步进的数学契约

体积纹理本质是一个三维数组,每个体素(Voxel)存储一个或多个通道值。在UE5中,体积纹理通常以R8G8B8A8或R16F格式导入,分辨率常见64×64×64到256×256×256。但纹理只是数据容器,真正让云雾“活”起来的是光线步进(Ray Marching)算法:从摄像机出发,沿视线方向以固定步长采样体积纹理,累加每个采样点的散射贡献。

设视线方向为d,步长为Δs,第i个采样点位置为pi = o + i·Δs·d,密度为ρ(pi),则最终颜色C的离散近似为:

C = Σ [ Ti · (1 - exp(-σt·ρ(pi)·Δs)) · Lscatter(pi) ]

其中Ti = exp(-σt·Σj<iρ(pj)·Δs)是累积透射率,σt是消光系数,Lscatter是单次散射光照。这个公式揭示了三个关键设计约束:步长Δs必须小于最小特征尺寸(否则会走样),密度场需要预乘消光系数(否则无法正确表现不同介质的吸收差异),透射率必须逐像素累积(否则无法表现云团的自遮挡)。UE5的Volumetric Cloud组件正是用Compute Shader在屏幕空间执行此步进,而体积纹理提供密度场的空间采样源。

为什么是“体积纹理”而不是“程序化噪声”?

程序化3D噪声(如Perlin Worley)可以生成云状密度,但每帧对每个采样点实时计算噪声的代价是O(N3)的ALU开销,且难以实现艺术可控的局部编辑。体积纹理将计算“烘焙”到离线或半离线阶段,运行时只需纹理采样(TMU操作),代价从ALU转移到带宽。更关键的是,体积纹理支持稀疏体素八叉树(Sparse Voxel Octree)压缩和mipmap链,在远距离时自动降低采样精度——这是程序化噪声无法直接获得的LOD能力。因此,UE5的云层系统采用“体积纹理+光线步进”的混合架构:近处用高分辨率体积纹理保证细节,远处用低mip层级降低采样成本。

推导:从密度场到光照积分的完整链路

要让体积纹理云雾在UE5中物理可信,必须完成以下推导链:

  • 密度场生成:体积纹理的RGB通道通常编码密度、温度、速度。密度值需归一化到[0,1],并乘以消光系数σt(典型值0.01~0.1 cm-1)。注意:UE5的体积纹理默认使用线性色彩空间,导入时务必关闭sRGB,否则密度值会被伽马校正扭曲。
  • 相位函数:散射不是各向同性的。Henyey-Greenstein相位函数用各向异性参数g(-1~1)控制前向/后向散射比例。云层通常g≈0.8(强前向散射),而雾g≈0。UE5的Volumetric Cloud材质节点内置了HG相位函数,但自定义体积纹理材质时需手动实现。
  • 光照积分:单次散射假设下,Lscatter = 太阳辐照度 × 相位函数 × 透射率(从采样点到光源的累积消光)。这里需要第二次光线步进——向光源方向步进,计算自阴影。这是体积云雾最昂贵的部分,UE5通过阴影贴图体积(Shadow Map Volume)预计算光源透射率来加速。
  • 深度整合:体积云雾需要与场景深度正确交互。UE5使用深度缓冲在光线步进时提前终止(当采样点深度超过场景深度时停止),避免对不可见区域做无效计算。

技巧:体积纹理的分辨率并非越高越好。64×64×64的体积纹理在近处会暴露体素块状伪影,但256×256×256会带来16倍的内存和采样开销。实践中的折中方案是:基础云层用128×128×128,局部细节用64×64×64的二级体积纹理叠加,通过三线性插值平滑过渡。

验证:在UE5中构建体积纹理云雾的实操路径

下面以“动态云海”为例,验证上述原理的落地方式。核心步骤不是“点按钮”,而是理解每个操作背后的数学意图。

步骤1:生成体积纹理密度场

在Houdini或EmberGen中生成密度场,导出为EXR序列或VDB。UE5可直接导入VDB为体积纹理(需启用Volume Texture导入选项)。关键参数:密度缩放(控制整体消光强度)、噪声频率(控制云絮尺度)、边缘衰减(用球体或盒体遮罩约束云团边界)。导入后,在材质编辑器中用Texture Sample节点采样体积纹理,输出到Volumetric Advanced材质节点的Density输入。

UE5体积纹理云雾:从体素空间到光线步进的原理级拆解 - 配图2
UE5体积纹理云雾:从体素空间到光线步进的原理级拆解

步骤2:构建光线步进材质

UE5的Volumetric Cloud组件已封装光线步进,但自定义体积纹理云雾通常需要手写Ray March循环。在材质中启用Volume材质域,使用Custom节点嵌入HLSL循环:

float3 rayOrigin = GetWorldPosition();
float3 rayDir = normalize(GetCameraVector());
float transmittance = 1.0;
float3 color = 0;
for (int i = 0; i < MAX_STEPS; i++) {
    float3 pos = rayOrigin + rayDir * (i * stepSize);
    float density = SampleVolumeTexture(pos);
    float extinction = density * sigmaT;
    float stepTrans = exp(-extinction * stepSize);
    color += transmittance * (1 - stepTrans) * ScatterLight(pos);
    transmittance *= stepTrans;
    if (transmittance < 0.01) break;
}

注意:UE5材质中的循环次数必须为常量(MAX_STEPS),且采样体积纹理时需使用Texture3DSampleLevel而非普通采样,以控制mip层级。步长stepSize需根据体积纹理的体素尺寸动态调整——经验公式:stepSize ≈ 体素尺寸 / 2,保证每个体素至少被采样两次以避免走样。

步骤3:性能与质量验证

用Stat GPU和ProfileGPU观察光线步进的耗时。典型瓶颈在采样次数:128步×每步2次纹理采样(密度+阴影)= 256次采样/像素。在1080p下就是5亿次采样,必须用时间性上采样(Temporal Upscaling)将实际步进分辨率降到1/4。验证方法:对比开启/关闭时间性上采样的视觉差异,若云边缘出现闪烁,说明上采样权重或历史帧重投影需要调优。

注意:体积纹理的采样坐标必须归一化到[0,1]范围,且需考虑体积纹理的边界模式。UE5默认Clamp,若云团超出边界会拉伸边缘体素,造成“硬切”伪影。解决方法是生成体积纹理时在边界留出至少2个体素的透明padding。

总结:体积纹理云雾的技术判断

从原理层看,UE5体积纹理云雾的本质是用离散体素场近似连续介质,用光线步进求解辐射传输方程。它的优势在于艺术可控性和物理可信度的平衡——你可以用体积纹理精确雕刻云团形状,同时用步进积分获得正确光照。但它的代价是采样带宽和步进次数,必须依赖时间性上采样和mipmap LOD来维持实时性能。

我的判断是:体积纹理云雾适合中近景的影视级云层,但不适合全屏远景的大气散射。远景大气应交给指数高度雾+天空大气系统,体积纹理只负责局部云团。在UE5项目中,合理的架构是“大气散射做底,体积纹理做云”,两者通过深度和透射率耦合,而不是试图用单一方案解决所有尺度的问题。

UE5体积纹理云雾:从体素空间到光线步进的原理级拆解 - 配图3
UE5体积纹理云雾:从体素空间到光线步进的原理级拆解

关于火星人教育:作为创办24年、专注数字艺术与AIGC实战职业技能培训的机构,火星人教育在UE5游戏特效、AIGC视觉设计、AI漫剧创作、室内全屋定制、MAYA三维动画、C4D动态设计、工业设计、NUKE影视后期、摄影摄像实训等课程中,始终强调“原理驱动”的教学理念——就像本文拆解体积纹理云雾一样,我们要求学员不仅会连节点,更要理解光线步进的数学本质。北京、深圳双校区开设线下面授班,面向美术生、在校大学生及意向转行的职场人群,以项目化实训教学夯实专业技能,助力就业与职业提升。咨询电话:010-65918670。

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