01先分清原生云 游戏定制云和当前复现
这里的“UE 原生云”指引擎的 VolumetricCloud 渲染器,不特指某一张默认云材质。UE 没有规定所有云都必须长成同一种噪声。材质可以读取三维纹理、距离场和解析形状,再提供消光、反照率、自发光等介质属性。
“游戏定制云”指 RDC 中实际执行的 Cloudly 追踪、阴影、AO 和重建路径。它仍然运行在 UE 中,但核心云计算没有直接沿用原生 VolumetricCloud 的整套算法。
“当前复现”也经历了两个阶段:最早把恢复的密度放进原生 Volume 材质,后面再把专用追踪和重建接成 RDG 插件。前者适合检验云的形状,后者才开始覆盖原生材质接口之外的行为。
| 环节 | UE 5.8.1 原生云 | 本次捕获的游戏定制云 |
|---|---|---|
| 云形与介质 | Volume 材质定义,可用 SDF 或噪声 | Base、Alto、Cirrus 分层,布局 SDF 加多级位移 |
| 主视线步进 | 按交段与预算求基础步长,结合空区跳过 | 粗追踪区间加 SDF 驱动的自适应步长 |
| 相函数 | 两个 HG 项按 Blend 插值 | 两个 HG 项取 max,并有动态暗边分支 |
| 多次散射近似 | 材质 octave 控制,公开编辑范围最多 2 个额外项 | 参考帧使用 4 个贡献项及自己的衰减参数 |
| 太阳遮蔽 | 二次体积 raymarch 或 Beer 阴影贴图 | 近场有限步追踪加远场级联三维光学深度缓存 |
| 环境光 | 引擎天空输入、材质 AO 和地面贡献等 | 专用天空 LUT、云 AO 与积分后的亮度补偿 |
| 云历史 | 原生 VolumetricRenderTarget 的重投影与重建 | 颜色、距离、可见性、Aux 和 Info 五组历史 |
| 场景集成 | 使用引擎组件和材质接口 | 还需要维护自定义资源、参数与生命周期 |
这张表描述实现选择。它不代表 UE 缺少对应的大类功能,也不能仅凭这些差异判断哪套一定更快。
02密度都能用 SDF 区别在它参与了哪些计算
原生 UE 云在射线采样位置求值 Volume 材质,再从材质输出中读取介质属性。因此完全可以把游戏的 SDF 解码和密度公式放进去。我最早就是这样做的:先保留引擎积分,只替换“这个位置有没有云、云有多密”。
游戏这一帧的 Base、Alto 使用 512 × 512 × 64 的双通道布局纹理,再叠加两级位移、云底软相交和随高度变化的密度边缘。近处的 Hotsure 细节还会按距离淡出。这些首先属于密度模型,原生材质可以表达其中很大一部分。
真正的区别在消费者。专用路径会继续用距离场决定下一步走多远,用粗追踪得到的区间跳过无云区域,并让查询和阴影使用相应的密度逻辑。若只把最终密度送进材质,原生追踪器并不会自动知道原版距离场的步进规则。
原生材质原型:布局 SDF → 密度 → 消光 → UE 原生积分
游戏专用路径:布局 SDF → 密度、步长、粗区间和查询 → 专用积分
这也解释了为什么原生材质原型能很快接近参考轮廓,却仍然有不同的细节和采样成本。云形接近,不能证明沿射线的采样位置也相同。

03步长和积分不同 薄云与边缘就会不同
本机 UE 5.8.1 的原生主循环,先根据云壳交段长度与采样预算计算样本数,再得到基础步长 StepT。它也能跳过空区域:Conservative Density 可以减少空位置的昂贵材质求值,源码还提供独立的 Empty Space Skipping 路径。
游戏专用路径则先做 CoarseTrace,给出可能含云的区间。主追踪在区间里根据 GetSteppingSDF、视线方向、表面距离、连续空步和最小步长等条件调整前进距离,再叠加蓝噪声。它对“哪里值得多算”有一套与自身云形表示配合的规则。
这里不能简单写成 UE 等步长、游戏变步长,更不能写 UE 没有空跳步。准确的差别是:两者用于决定采样位置的输入与策略不同;游戏直接使用专用 SDF 和粗区间,而原生云通过自己的循环和材质接口工作。
积分方法也不完全相同。原生云的一条主要路径把每段介质视为常量,使用解析积分;游戏恢复的代码包含前后样本的梯形项和边界修正。即便连续密度相同,离散采样位置与积分方法也会改变薄云厚度和边缘透射率。
// UE 原生每段常量介质积分的简化形式
deltaL = T_before * source * (1 - exp(-sigma * stepMeters)) / sigma;
提高采样数能减小一部分离散误差,却不会把一种步进策略变成另一种。这是后面需要进入渲染插件,而不只继续调材质参数的原因之一。
04相函数 暗边和环境光决定了颜色差异
原生云的 SamplePhaseFunction 计算两个 HG 相函数,再按 PhaseBlend 插值。游戏这张参考帧的基础组合则是:
UE: phase = lerp(HG(mu, g1), HG(mu, g2), blend)
参考帧: phase = max(HG(mu, 0.2), 0.5 * HG(mu, 0.69))
两条曲线对观察方向与太阳夹角的响应不同。把同样的 g 值填进 UE,再调整 Blend,也不能一般性地得到 max 的结果。原版还启用了根据局部条件变化的 DarkEdge 分支,所以暗边也不是一条固定调色曲线。
多次散射方面,两套都是实时近似。参考帧使用 4 个贡献项;早期 UE 原型用了 2 个额外 octave,共 3 个项。本机原生材质公开的编辑范围是 0 到 2 个额外 octave,但 Shader 的 MSCOUNT 来自宏,不能把这个编辑范围说成 UE 永远不能算更多项。更关键的是,每项如何缩放光学深度、贡献和相函数,仍要逐项对应。
环境光带来的差异更明显。游戏从 DistantSkyLightLut 读取环境输入,经过自己的去色、蓝偏移、强度和云 AO 处理;在整条视线积分完成之后,还会对直射与环境项的合计亮度做补偿。原生云使用引擎天空输入及对应的 AO、云底和地面贡献,并不是同一组公式。
其中“积分完成之后”很关键。Volume 材质是在单个采样点求值,不能直接取得这条射线最后累计的 direct 与 ambient 总和。把环境光塞进 Emissive 可以做近似实验,但不等于恢复了原版的整条射线补偿;再调整曝光,也只会同时影响亮部和暗部。


05阴影和 AO 的差别是表示方式与更新方式
原生 UE 云可选二次体积 raymarch,或 Beer cloud shadow map。前者沿光线继续求介质,后者复用阴影贴图;适用距离、颜色细节和成本各有取舍。Epic 的体积云说明也把它们作为两条不同路径介绍。
参考帧的专用方案采用近远分工:近太阳方向最多做 6 步局部追踪,后续距离按自己的规则展开;更远的光学深度来自级联三维纹理,并在前后缓存之间混合。它缓存的是空间中不同高度和位置的遮蔽信息,不能简单等同于切换成 UE 的 Beer 阴影模式。
“6 步”也不是全部阴影成本。三维缓存需要生成、更新和读取;只拿局部步数和 UE 的阴影采样上限比,漏掉的恰好是这套方案最重要的资源更新部分。
游戏的 Cloud AO 也有独立三维数据,主追踪再按位置查询。原生 UE 同样有天空光云 AO 相关路径,但具体表示、生成与采样方式不能仅凭名字视为相同。这里的云体积遮蔽、屏幕空间 AO、Lumen GI,以及太阳自阴影,需要分别核对。
这次噪点在关闭 Lumen 后仍然出现,只能说明 Lumen 不是问题出现的必要条件,不能反过来直接证明动态 AO 就是根因。当前复现默认仍使用部分捕获的云内阴影输入,实验性生成桥接也尚未完整对应原生的更新策略;这一点和原游戏完整动态阴影系统还有距离。
06两套方案都有重建 但保留的历史语义不同
UE 原生 VolumetricRenderTarget 已经有低分辨率追踪、历史重投影和深度相关的重建、上采样。不能把“云先少算一些像素,再重建”写成游戏专有技术。
游戏这张参考帧的网格是主追踪 598 × 336、云时域 1196 × 672,再重建到有效 1707 × 960 场景,最后由 UE TSR 输出 2560 × 1440。因此有两层需要分开:专用云自己的历史重建,以及后面的整帧抗锯齿与升采样。
更具体的差异在中间数据。当前恢复的专用时域阶段有颜色、距离、可见性、Aux 和 Info 五组历史;Aux 记录首次命中云后若干距离段的透射率,后级会用它调整重建。历史拒绝时,还需要让颜色与这些元数据选择同一份深度相容的当前样本。
它们并不是简单多存几张纹理就会更好,而是整套滤波判断依赖这些数据的语义。颜色已经做了历史稳定,控制核半径的元数据如果还来自当前抖动采样,前后两级就可能产生不一致。最后用于显示的空间平滑,也不能随意反馈成下一帧时域历史。
原生云同样面临穿云时的深度近似、遮挡失效与稳定性取舍。本机源码甚至明确说明,近距离关闭部分重投影可以隐藏某些错误,但也会让云更吵。专用云有自己的处理方式,并不表示它不需要在噪点和拖影之间取舍。

07哪些能靠材质完成 哪些需要改渲染器
第一阶段适合留在材质里做的,是云布局、SDF 解码、位移、密度边缘,以及公开接口能表达的介质与光照参数。我能很快验证轮廓,也能用 UE 自己的质量模式观察云形。这一阶段不需要先接完整专用渲染器。
当目标转向原版的采样位置、相函数组合、整条射线的环境补偿、三维阴影缓存和五组历史时,就超出了仅修改云材质的范围。后来的插件保留 UE 的场景和 RDG 调度,在云的核心阶段使用恢复的专用实现,再接回场景合成。
这会增加工程责任:当前和上一帧相机、曝光、尺寸、场景深度、历史有效条件,以及资源代际都要自己维护。原生方案已经和引擎组件协同;自定义方案需要重新接好这些关系。多了一条能定制的路径,也多了一批需要验证的接口。
例如原生 CPU 写给 CameraSpeedMeter 的实际值是米制帧位移,不是米每秒;捕获的 70% 重建变体也不一定能直接改尺寸当成 100% 使用。Shader 数学公式相同,桥接语义错了,画面仍然会有问题。
接进新工程时,我关闭的是原生云绘制,避免与专用云重复合成。Lumen 和 Nanite 保持开启。当前云组件负责场景中的可见开关,但宿主风速、天气、太阳和动态曝光还没有全部映射到专用参数,不能把“能显示”视作已完成原生组件的全部替代。
08性能优势要用相同目标画质来比较
从算法可以看出,游戏把一部分成本转成可复用数据:粗区间减少空位置工作,SDF 调整步长,远场阴影从缓存查,稀疏屏幕采样交给历史重建。代价则是额外资源、生成流程和跨帧维护。
原生 UE 也有自己的省算路径。比较时,不能一边用全分辨率、高采样的原生诊断模式,另一边用低分辨率和历史缓存,再把帧率差全归到算法。原生的 Mode、阴影路径、密度复杂度、目标误差和镜头运动都要对齐。
目前我没有同一 GPU、相同目标画质和完整缓存更新周期下的双方稳态 GPU 耗时,因此不写“快几倍”。合理的测法是把密度或缓存生成、主追踪、时域重建和合成分开统计,再同时检查静止、转向与穿云时的画面。
低采样不会自然带来稳定画面。原生云或专用云都需要让采样、过滤和重建配合;缓存也必须把新增的生成成本计入平均帧预算。
09当前画面能说明什么 还不能说明什么
目前专用路径已经能在新 UE 工程自由观察。共同背景对照用于看云形与颜色,新工程的实际单帧和连续序列用于看动态稳定性。网页对照中的城市来自同一张原帧底图,并不是已经在 UE 重建的场景。

新工程 1280 × 720 的固定近景与纯 yaw 连续测试中,最终视口异步读回没有复现早期那么强的闪烁;实际查看的观感也改善了。不过纯旋转测试覆盖不了平移视差和穿云,新露出区域的历史失效还需要继续检查。这次增加的最终视口采集工具本身没有修改云去噪算法。


如果目标是做一套自己的云,我会先用原生材质验证造型和光照需求;如果目标是贴近这个游戏已经形成的视觉结果,就需要继续对应它的追踪、缓存和重建。当前复现已经走到后一条路径,但天气动画、动态阴影与宿主场景适配还没有闭合。这个工程上的差距,也需要和两种渲染方案本身的差异分开看。
10参考资料
原生实现对照为本机 UE 5.8.1 的 VolumetricCloud.usf、VolumetricRenderTarget.cpp 和材质接口源码;游戏侧以 RDC 实际绑定、预处理 HLSL、资源配置和原生写入证据为准。各阶段画面条件见图注,原游戏图像与资源属于其权利方。