FidelityFX 组合自适应计算环境光遮蔽 (CACAO) 1.4
组合自适应计算环境光遮蔽 (简称 CACAO) 是 Intel(R) ASSAO 屏幕空间环境光遮蔽实现的的高度优化改编版 [ASSAO-16]。
CACAO 提供 5 种 SSAO 生成的质量级别(FFX_CACAO_QUALITY_LOWEST、FFX_CACAO_QUALITY_LOW、FFX_CACAO_QUALITY_MEDIUM、FFX_CACAO_QUALITY_HIGH、FFX_CACAO_QUALITY_HIGHEST),其中最后一个级别使用了自适应方法。

着色语言要求
HLSL GLSL CS_6_0
请注意,GLSL 编译器还必须支持 GL_EXT_samplerless_texture_functions 和 GL_GOOGLE_include_directive 以处理 GLSL 着色器系统中使用的 #include。
集成指南
CACAO 运行需要两个矩阵(projection、normalsToView)。深度缓冲区是必需的输入,法线是可选输入,否则将从深度缓冲区计算。输出是环境光遮蔽 (AO) 值的单通道纹理。
需要将一个常量缓冲区填充相关值。在提供的实现中,许多值应保持不变。集成效果时,将需要一些值。这是因为分辨率不同、相机矩阵不同或设置已更改。这些值在 Modify 列中用 Y 表示。在 Modify 列中用 N 表示的值通常在提供的实现中保持不变。
| 修改 | 元素名称 | 类型 | 描述 |
|---|---|---|---|
| Y | DepthUnpackConsts | float2 | 用于 剪辑到视图深度转换 的乘法和加法值。 |
| Y | CameraTanHalfFOV | float2 | x 和 y 维度的值。 |
| Y | NDCToViewMul | float2 | 从归一化设备坐标 (NDC) 转换为视图坐标的乘法值。 |
| Y | NDCToViewAdd | float2 | 从 NDC 转换为视图坐标的加法值。 |
| Y | DepthBufferUVToViewMul | float2 | 从深度缓冲区的 UV 坐标转换为视图坐标的乘法值。 |
| Y | DepthBufferUVToViewAdd | float2 | 从深度缓冲区的 UV 坐标转换为视图坐标的加法值。 |
| Y | EffectRadius | float | 遮蔽球体的世界空间半径。半径越大,越远的物体对点的环境光遮蔽贡献越大。 |
| Y | EffectShadowStrength | float | 阴影的线性乘数。值越高,阴影越强。 |
| Y | EffectShadowPow | float | 阴影值的指数。值越大,阴影越暗。 |
| Y | EffectShadowClamp | float | 将阴影值限制在特定范围内。 |
| Y | EffectFadeOutMul | float | 效果淡出倍数。 。 |
| Y | EffectFadeOutAdd | float | 效果淡出的加法值。 。 |
| Y | EffectHorizonAngleThreshold | float | 在产生遮蔽所需的几何体与点之间的最小角度。调整此值有助于减少自阴影。 |
| N | EffectSamplingRadiusNearLimitRec | float | 默认值: 。 详情请参阅实现。 |
| N | DepthPrecisionOffsetMod | float | 默认值: 。 用于防止由于精度问题引起的伪影的偏移。 |
| Y | NegRecEffectRadius | float | 设置为: |
| N | LoadCounterAvgDiv | float | 设置为: |
| Y | AdaptiveSampleCountLimit | float | 限制在自适应质量级别下采样的总样本数。 |
| Y | InvSharpness | float | 设置为 。 锐度控制着模糊在边缘上溢出的程度。 |
| Y | BlurNumPasses | int | 默认值为 。在最低质量级别下,默认值为 。 |
| Y | BilateralSigmaSquared | float | 仅影响下采样 SSAO。值越高,模糊越大。 |
| Y | BilateralSimilarityDistanceSigma | float | 仅影响下采样 SSAO。值越低,边缘越锐利。 |
| N | PatternRotScaleMatrices | float4[4][5] | 用于采样图案。详情请参阅实现。 |
| Y | NormalsUnpackMul | float | 用于解压法线的乘法值。如果法线已在 范围内,则设置为 。 |
| Y | NormalsUnpackAdd | float | 用于解压法线的加法值。如果法线已在 范围内,则设置为 。 |
| Y | DetailAOStrength | float | 根据边缘增加更精细的阴影。这些阴影在时间上不太稳定。 |
| Y | SSAOBufferDimensions | float2 | SSAO 缓冲区的尺寸。 |
| Y | SSAOBufferInverseDimensions | float2 | |
| Y | DepthBufferDimensions | float | 深度缓冲区的尺寸。 |
| Y | DepthBufferInverseDimensions | float | |
| Y | DepthBufferOffset | int2 | 默认值为 。 |
| N | PerPassFullResUVOffset | float4[4] | 详情请参阅实现。 |
| Y | InputOutputBufferDimensions | float2 | 输出 AO 缓冲区的尺寸。 |
| Y | InputOutputBufferInverseDimensions | float2 | . |
| Y | ImportanceMapDimensions | float2 | 重要性图的尺寸。 |
| Y | ImportanceMapInverseDimensions | float2 | . |
| Y | DeinterleavedDepthBufferDimensions | float2 | 去隔行深度缓冲区的尺寸。 |
| Y | DeinterleavedDepthBufferInverseDimensions | float2 | . |
| Y | DeinterleavedDepthBufferOffset | float2 | 默认值为 。 |
| Y | DeinterleavedDepthBufferNormalisedOffset | float2 | 默认值为 。 |
| Y | NormalsWorldToViewspaceMatrix | mat4 | 法线矩阵。 |
技术
算法结构
FidelityFX CACAO 算法包含多个通道,这些通道的配置方式因使用的 FidelityFX CACAO 算法变体而异。

下表总结了在可能选择的不同配置下,FidelityFX CACAO 算法存在的通道。根据所需的性能级别,可以调整质量级别。通过调整质量级别,将省略构成效果的某些通道。
在表中,复选框中的勾表示该通道存在,而叉表示该通道被省略。在所有配置中,FidelityFX CACAO 集成应按照上面图示的顺序执行通道。
除了配置质量级别外,FidelityFX CACAO 还有一个选项允许算法以缩减的分辨率运行。如果选择了此选项,将执行额外的双边上采样作为算法的最后一步。这也在下表中的行中得到了说明。
| 质量模式 | 原生 | 准备 | 生成 SSAO | 创建重要性图 | 生成自适应 SSAO | 边缘感知模糊 | 应用 | 双线性上采样 |
|---|---|---|---|---|---|---|---|---|
FFX_CACAO_QUALITY_LOWEST | ||||||||
FFX_CACAO_QUALITY_LOW | ||||||||
FFX_CACAO_QUALITY_MEDIUM | ||||||||
FFX_CACAO_QUALITY_HIGH | ||||||||
FFX_CACAO_QUALITY_HIGHEST | ||||||||
FFX_CACAO_QUALITY_LOWEST | ||||||||
FFX_CACAO_QUALITY_LOW | ||||||||
FFX_CACAO_QUALITY_MEDIUM | ||||||||
FFX_CACAO_QUALITY_HIGH | ||||||||
FFX_CACAO_QUALITY_HIGHEST |
准备阶段
准备阶段将传统格式提供的渲染数据(例如深度和法线缓冲区)转换为更优化的数据布局,以便后续通道使用。
对于所有质量设置,这意味着生成深度缓冲区和法线缓冲区的去交织版本。根据所选的质量级别,FidelityFX CACAO 还可能为去交织深度缓冲区生成 mipmap 链。这是使用 FidelityFX SPD [SPD-19] 完成的。

如果 FidelityFX CACAO 算法运行在 FFX_CACAO_QUALITY_LOWEST 质量模式下,算法将不会生成四个缓冲区(每个缓冲区在每个维度上具有一半分辨率),而是生成两个缓冲区(同样在每个维度上具有一半分辨率),从而有效地丢弃 50% 的输入数据以供进一步考虑。此外,在以较低分辨率运行时,准备通道还将生成较低分辨率的去交织缓冲区(在每个维度上四分之一分辨率,而不是在每个维度上二分之一分辨率)。
请注意:虽然此算法阶段实现为两个单独的调度,但它们不共享任何数据。因此,组成准备通道的两个调度之间不需要管线屏障。
下表描述了根据您的分辨率和质量模式应使用的计算着色器入口点。根据分辨率和质量模式,您应为准备深度和准备法线调度使用的计算着色器选择一个合适的主函数。
深度准备入口点
| 深度准备入口点 | 分辨率 | 质量模式 |
|---|---|---|
FFX_CACAO_PrepareNativeDepthsAndMips | 原生 | FFX_CACAO_QUALITY_MEDIUM 或更高。 |
FFX_CACAO_PrepareDownsampledDepthsAndMips | 降采样 | FFX_CACAO_QUALITY_MEDIUM 或更高。 |
FFX_CACAO_PrepareNativeDepths | 原生 | FFX_CACAO_QUALITY_LOW |
FFX_CACAO_PrepareDownsampledDepths | 降采样 | FFX_CACAO_QUALITY_LOW |
FFX_CACAO_PrepareNativeDepthsHalf | 原生 | FFX_CACAO_QUALITY_LOWEST |
FFX_CACAO_PrepareDownsampledDepthsHalf | 降采样 | FFX_CACAO_QUALITY_LOWEST |
法线准备入口点
| 法线准备入口点 | 分辨率 | 提供的应用法线 |
|---|---|---|
FFX_CACAO_PrepareNativeNormalsFromInputNormals | 原生 | |
FFX_CACAO_PrepareDownsampledNormalsFromInputNormals | 降采样 | |
FFX_CACAO_PrepareNativeNormals | 原生 | |
FFX_CACAO_PrepareDownsampledNormals | 降采样 |
资源输入
下表描述了准备过程的输入。
| 名称 | 类型 | 说明 |
|---|---|---|
| 应用程序的深度缓冲区 | 深度缓冲区 | 场景渲染过程中生成的深度缓冲区。FidelityFX CACAO 同时支持传统的 Z 缓冲区和反向 Z。 |
| [可选] 应用程序的法线缓冲区 | 法线缓冲区 | 一个可选缓冲区,包含场景渲染过程中生成的法线。如果您选择不提供此缓冲区,FidelityFX CACAO 将从提供的深度缓冲区生成法线缓冲区。它通过计算深度缓冲区中像素邻域的偏导数来得到一个 隐式 法线。法线缓冲区的格式可以通过在集成过程中更改 FFX_CACAO_Prepare_LoadNormal 来修改。 |
资源输出
下表描述了由准备过程计算的输出。
| 名称 | 类型 | 说明 |
|---|---|---|
| 去交织深度缓冲区 | R16_SFLOAT 纹理 | 场景渲染过程中生成的深度缓冲区。 |
| 去交织深度 MIP 链 | R16_SFLOAT 纹理 | 包含去交织深度缓冲区过滤集合的 MIP 链。注意:此项仅在 FFX_CACAO_QUALITY_MEDIUM 或更高质量下生成。 |
| 去交织法线缓冲区 | R8B8B8A8_SNORM 纹理 | 当未将法线缓冲区作为输入时,使用深度缓冲区的偏导数生成去交织法线缓冲区。 |
描述
去交织过程对于深度缓冲区和法线缓冲区是相同的,并在下图所示。考虑 2x2 像素的每个组,并将其分离成四个单独的纹理,每个纹理的分辨率是原始输入的四分之一。这样做的原因是提高 GPU 中缓存层次结构的效率。

在上图中,左侧图像中的每个正方形代表一个单独的像素。您可以看到每个 2x2 像素集包含四种不同的颜色。
现在转向图的右侧,我们可以看到每种颜色的像素被收集到自己的纹理中,从而有效地从原始纹理创建了四个非常相似的降采样纹理。
如果使用 FFX_CACAO_QUALITY_LOWEST,则在准备通道中丢弃 50% 的输入像素。这是通过在每个 2x2 网格中丢弃右上方和左下方的像素来完成的。正如预期的那样,这确实会导致 AO 结果质量的明显下降,但会带来显著的性能提升。
生成 SSAO(非自适应)
生成 SSAO 阶段计算遮蔽值,并检测将在后续的边缘感知模糊通道中使用的边缘。遮蔽值编码了像素被邻近几何体(从传递给 FidelityFX CACAO 的深度和法线缓冲区重建)遮挡的概率,并存储在生成 SSAO 通道的输出纹理的红色通道中。边缘值用每个基数方向(北、东、南、西)的 2 位进行编码。边缘值由当前像素在基数方向到下一个像素的深度不连续性的强度确定。

资源输入
| 名称 | 类型 | 说明 |
|---|---|---|
| 去交织深度 MIP 链 | R16_SFLOAT 纹理 | 在 准备 通道中生成的去交织深度缓冲区。如果您使用的是 FFX_CACAO_QUALITY_MEDIUM 或更高质量,则应提供完整的去交织深度缓冲区,其中包含 MIP 链。有关 MIP 链生成的更多详细信息,请参阅 准备通道。 |
| 去交织法线缓冲区 | RGB888 法线缓冲区 | 准备 通道生成的法线缓冲区。 |
资源输出
| 名称 | 类型 | 说明 |
|---|---|---|
| 中间目标 | RG88 纹理 | 一个中间渲染目标,其中红色通道包含遮蔽值,绿色通道包含边缘值。 |
描述
对于每个像素,深度和法线值以围绕像素的旋转对称模式进行采样(参见下图)。在较高的质量级别,FidelityFX CACAO 将从多个 MIP 级别采样深度值。采样模式会根据像素的深度进行缩放。采样模式会为邻近像素进行旋转。对于每个采样的像素,FidelityFX CACAO 会计算一个遮蔽值。每个像素的最终遮蔽值是所有样本的遮蔽值的加权平均值。

位置为 p、法线为 n 的像素,从位置为 q 的样本计算出的遮蔽值如下。
![]()
遮蔽项是命中方向与法线之间夹角的余弦值,乘以一个随像素与样本之间距离的平方而增加的衰减。
生成自适应 SSAO,第一部分
在自适应质量级别,初始生成 SSAO 通道的目的略有不同。
虽然基础通道以与非自适应通道相同的方式计算 SSAO,但它会在写入未转换的遮蔽值后提前退出,并跳过边缘检测计算。自适应 SSAO 生成会接受额外的输入(重要性图、加载计数器以及基础通道的输出),然后根据重要性图给出的位置的计算重要性,在基础通道之后执行可变数量的额外采样。

资源输入
| 名称 | 类型 | 说明 |
|---|---|---|
| 去交织深度 mipmap 链 | R16_SFLOAT 纹理 | 在 准备 通道中生成的去交织深度缓冲区。如果您使用 FFX_CACAO_MEDIUM 或更高质量,则应提供完整的去交织深度缓冲区,其中包含 mipmap 链。有关 mipmap 链生成的更多详细信息,请参阅 准备 通道。 |
| 去交织法线缓冲区 | R8G8B8A8_SNORM 纹理 | 当未将法线缓冲区作为输入时,使用深度缓冲区的偏导数生成去交织法线缓冲区。 |
资源输出
| 名称 | 类型 | 说明 |
|---|---|---|
| 中间目标 | R8G8_UNORM | 一个中间渲染目标,其中红色通道包含遮蔽值。 |
描述
与 生成 SSAO(非自适应)通道 相同,但会在写入未转换的遮蔽值后提前退出,并跳过边缘检测计算。
重要性图生成
在自适应质量中,运行 SSAO 基础通道 后,会生成一个重要性图,以确定在最终效果中在哪里使用最多的样本。

资源输入
| 名称 | 类型 | 说明 |
|---|---|---|
| 基础通道 SSAO | R8G8_UNORM | 来自 SSAO 基础通道 的包含遮蔽值的中间纹理。 |
资源输出
| 名称 | 类型 | 说明 |
|---|---|---|
| 重要性图 | R8_UNORM | 重要性图中的每个重要性值对应于 8x8 的 SSAO 值方块,其重要性设置为该方块中最大值与最小值之间的差值。然后对重要性图进行模糊处理,以避免从重要区域到不重要区域的急剧过渡。 |
| 加载计数器。 | R32_UINT | 包含总重要性之和的计数器。 |
描述
对于基础通道 SSAO 遮蔽值的每个 8x8 方块,都会计算最小值和最大值之间的差值。然后对其进行模糊处理,以创建从高重要性区域到低重要性区域的平滑过渡。
生成自适应 SSAO,第二部分

资源输入
| 名称 | 类型 | 说明 |
|---|---|---|
| 去交织深度缓冲区。 | R16_FLOAT | 准备 通道中从输入深度缓冲区生成的去交织深度缓冲区。 |
| 去交织法线缓冲区。 | R8G8B8A8_FLOAT | 在 准备 通道中从输入法线缓冲区生成的去交织法线缓冲区,或者从深度缓冲区生成的。 |
| 基础通道 SSAO | R8G8_UNORM | 来自 SSAO 基础通道 的包含遮蔽值的中间纹理。 |
| 重要性图。 | R8_UNORM | 模糊后的重要性图。 |
| 加载计数器。 | R32_UINT | 用于计算平均总重要性的计数器。 |
资源输出
| 名称 | 类型 | 说明 |
|---|---|---|
| SSAO 缓冲区 | R8G8_UNORM | 输出的 SSAO 缓冲区,包含转换后的遮蔽值和边缘值。 |
描述
对于每个像素,会额外采样深度和法线值。这是通过在像素周围的旋转对称模式下采样深度来完成的,有效地接续了基础通道中已完成的工作。额外采样的数量基于重要性图中所存储的重要数值。对于每个像素,CACAO 会计算每个样本的遮蔽值,并将其与来自 基础通道 SSAO 的先前存储的未转换遮蔽值相结合。每个像素的最终遮蔽值是基础通道和此通道组合的累积所有遮蔽值的加权平均值。

位置为 p、法线为 n 的像素,从位置为 q 的样本计算出的遮蔽值如下。
![]()
遮蔽项是命中方向与法线之间夹角的余弦值,乘以一个随像素与样本之间距离的平方而增加的衰减。
边缘感知模糊

资源输入
| 名称 | 类型 | 说明 |
|---|---|---|
| 生成的带边缘的 SSAO 纹理 | R8G8_UNORM | 包含遮蔽值和边缘的非模糊 SSAO 纹理。 |
资源输出
| 名称 | 类型 | 说明 |
|---|---|---|
| 模糊后的带边缘的 SSAO 纹理 | R8G8_UNORM | 输出的 SSAO 缓冲区,包含模糊后的遮蔽值。 |
描述
边缘敏感模糊应用于 SSAO 生成之后,以帮助去除随机采样产生的噪声。模糊核为 3x3,其中每个像素根据其边缘值进行加权。模糊可以运行 0 到 8 次,以有效地创建更宽的核。
应用
非降采样质量级别的最后一个阶段。

资源输入
| 名称 | 类型 | 说明 |
|---|---|---|
| 去交织 SSAO 纹理 | R8G8_UNORM | 包含由 边缘感知模糊 通道或生成 SSAO 通道生成的模糊遮蔽值和边缘值的纹理,具体取决于边缘感知模糊通道的数量是否大于 0。 |
资源输出
| 名称 | 类型 | 说明 |
|---|---|---|
| 最终输出 | 输出 AO 纹理 | 一个包含最终 AO 值的输出纹理。此纹理提供给 ffxCacaoContextDispatch 函数。 |
描述
将前面通道生成的去交织 SSAO 纹理重新交织,以输出正确的解析度。然后对邻域样本进行采样,以应用高分辨率模糊。结果写入输出 AO 纹理。
双边上采样
使用双线性上采样器来为降采样质量级别创建最终输出。上采样器使用 5x5 的输入 SSAO 值及其对应的深度核,并创建一个混合的输出值。

资源输入
| 名称 | 类型 | 说明 |
|---|---|---|
| 去交织 SSAO 纹理 | R8G8_UNORM | 包含先前计算的 AO 值的纹理。 |
| 去交织深度 | R16_FLOAT | 来自 准备 通道的去交织深度纹理。 |
| 输入深度 | R32_FLOAT | 深度缓冲区。 |
资源输出
| 名称 | 类型 | 说明 |
|---|---|---|
| 最终输出 | 输出 AO 纹理 | 一个包含最终 AO 值的输出纹理。此纹理提供给 ffxCacaoContextDispatch 函数。 |
描述
双线性上采样器使用 5x5 的输入 SSAO 和深度值核创建混合输出值。此上采样器可以进行边缘感知(使用先前生成的边缘)或无边缘感知运行。
版本历史
| 版本 | 日期 | 说明 |
|---|---|---|
| 1.0 | 2020 年 5 月 | FidelityFX CACAO 的初始发布。 |
| 1.1 | 2020 年 8 月 | 添加 Vulkan 版本 |
| 1.2 | 2021 年 2 月 | 小样本更新 |
| 1.3 | 2023 年 5 月 | 移植到 FidelityFX SDK |
参考文献
- [ASSAO-16] 自适应屏幕空间环境光遮蔽,https://github.com/GameTechDev/ASSAO