《对马岛之魂》实时武士电影:光照、大气与色调映射

Real-Time Samurai Cinema: Lighting, Atmosphere, and Tonemapping in Ghost of Tsushima


项目背景与开发概况

  • 开发商 :Sucker Punch Productions,自 2011 年起隶属于 Sony Interactive Entertainment ,工作室位于华盛顿州贝尔维尤(西雅图附近)
  • 开发高峰期约 160 人 参与制作
  • 前作包括 《怪盗史库柏》(Sly Cooper) 系列和 《恶名昭彰》(inFAMOUS) 系列
  • 《对马岛之魂》于 2020 年夏季在 PS4 上发售,随后推出了免费合作多人扩展,并在 PS5 向下兼容模式 中支持 60 fps
  • 游戏类型: 开放世界动作冒险 ,背景设定在 13 世纪封建日本 ,玩家扮演武士境井仁(Jin Sakai),抵抗蒙古入侵对马岛

相关技术演讲资源

  • SIGGRAPH 上关于 基于物理的着色(Physically Based Shading) 的研究
  • GDC 上关于 程序化草地(Procedural Grass) 、 世界构建与渲染 、 风与布料模拟 以及 快速加载 等多个专题

项目目标:时光机器与武士电影感

"时光机器" 体验

  • 目标是将玩家沉浸在 1274 年的对马岛 中
  • 需要创建一个比以往作品 大得多的动态开放世界 ,要求 美轮美奂且充满生机
  • 首次引入 动态天气系统 和 连续的昼夜循环(Time of Day) 系统——这在之前的项目中从未做过

经典武士电影风格

  • 致敬传奇电影人 黑泽明(Akira Kurosawa) ,游戏内置 "黑泽模式"
  • 需要实现 戏剧性光照(Dramatic Lighting) 、 凛冽的风(Biting Wind) 以及 富有表现力的天空与大气效果

光照系统总览

艺术方向:风格化写实(Stylized Realism)

  • 并非追求照片级真实(Photorealism) ,而是 风格化写实 ——物理上合理但允许艺术性偏离
  • 艺术家可在光照阶段使用一组 可调旋钮(Knobs) 全局调整光照参数(如 环境光/漫反射/镜面反射平衡 、 天空亮度 等)
  • 这些调整通常以 天气状态和时间段 的粒度进行设置

基于物理的光照模型

组件具体方案
高光 BRDFGGX 分布函数(GGX NDF) ,支持可选的 各向异性(Anisotropy)
可见性项Smith 可见性函数(Smith Visibility Function)
菲涅尔Schlick 菲涅尔近似(Schlick Fresnel Approximation)
漫反射Lambertian 漫反射,支持可选的 能量守恒透射(Energy Conserving Translucency) 和 绒毛模型(Fuzziness)
面光源支持 能量守恒的面光源(Energy Conserving Area Lights)
能量守恒整体光照模型满足 能量守恒(Energy Conserving)

材质系统

  • 材质使用 物理上合理的参数(Physically Plausible Parameters) 进行创作
  • 部分材质采用 摄影测量(Photogrammetry) 获取
  • 物理合理的材质保证了 对光照的一致响应

光源单位

  • 光源使用 物理单位(Physical Units) 进行设置

间接光照

  • 基于当前天空和平行光(Directional Light)动态更新的 球谐函数(Spherical Harmonics, SH) 和 反射探针(Reflection Probes)
  • 加上 局部光照传递数据(Local Light Transfer Data)

天空与大气

  • 使用 基于物理的多重散射大气散射模型(Physically Based Multi-Scattering Atmospheric Scattering Model)
  • 统一用于 云 、 雾霾(Haze) 和 粒子 的大气光照

渲染管线

  • 场景在 HDR 下渲染,使用 自定义色调映射(Custom Tonemapping) 技术来达成目标视觉风格

演讲结构:三大主题

本演讲分为三大部分:

  1. 间接光照(Indirect Lighting) ——漫反射间接光照 + 镜面反射间接光照
  2. 大气体积光照(Atmospheric Volumetric Lighting) ——天空、云、体积雾霾、粒子
  3. 色调映射(Tonemapping) ——局部色调映射算子、白平衡色彩分级、自定义色调映射色彩空间、人眼低光视觉模拟(夜景)

间接漫反射光照(Indirect Diffuse Lighting)

前作方案:《恶名昭彰:次子》的做法

  • 使用 二次辐照度探针(Quadratic Irradiance Probes) 排列在 四面体网格(Tetrahedral Meshes / Tet Meshes) 中,为整个世界提供间接漫反射光照
  • 详见 Adrian Bentley 在 GDC 2014 的演讲
  • 该方案在 静态昼夜和天气 条件下表现良好——天气/时间切换仅在 加载屏幕后面 发生

《对马岛之魂》的挑战与改进

由于需要照亮 更大的世界 ,且首次面对 动态昼夜与天气 ,必须对方案进行重大调整。

规则栅格探针(Regular Grid Probes)

  • 在地面上以 12.5 米间隔 排列探针
  • 每个位置在地面以上 1.5 米、10 米、30 米 三个高度层放置探针
  • 演讲中展示了 24 小时昼夜循环 中全岛 9 个 SH 波段绝对值 的变化——在 日出和日落 时变化最剧烈
  • 这里的 "9 个 SH 波段" 指的是 二阶球谐函数(L=0,1,2) 的 9 个系数,用于编码每个探针处的 辐照度(Irradiance) 信息

栅格探针的局限:室内照明

  • 12.5 米的探针间距 太粗 ,无法精确照亮室内场景

解决方案:四面体网格叠加(Tet Mesh Override)

  • 在 城镇、村落、农庄 等需要精细照明的地方,使用 四面体网格(Tet Meshes) 作为补充
  • 这些四面体网格作为独立单元 随场景流式加载(Streamed)
  • 加载后, 四面体网格会覆盖(Override)规则栅格 ,并在边界处进行 平滑混合(Blend at Boundary)

实际效果

  • 演讲中展示了漫反射间接光照缓冲区的可视化,可以看到 规则栅格光照 与 四面体网格光照 之间存在 平滑过渡 ,无明显接缝
  • 以游戏中的 "金阁寺"(Golden Temple) 场景为例进行了演示

关键技术总结

特性规则栅格探针四面体网格探针
覆盖范围全岛局部(城镇、村落等)
间距12.5 米更密,适配室内
高度分布1.5m / 10m / 30m 三层自定义布局
加载方式常驻随区域流式加载
优先级被 Tet Mesh 覆盖覆盖栅格,边界平滑混合
适用场景室外大范围室内与半封闭空间

间接漫反射光照(Indirect Diffuse Lighting)


动态辐照度探针(Dynamic Irradiance Probes)

核心挑战

  • 游戏拥有 动态昼夜循环 和 动态天气系统 ,因此辐照度探针必须在 运行时更新 ,不能完全依赖离线烘焙

离线 + 运行时的混合方案

  1. 离线阶段 :不直接捕获辐照度(irradiance),而是捕获每个探针位置的 天空可见性(Sky Visibility) ,以 球谐函数(SH) 形式存储
  2. 运行时阶段 :
    • 计算当前天空光照的 SH 投影
    • 将 天空亮度 SH × 天空可见性 SH ,得到该探针接收到的天空光
    • 对结果进行 余弦瓣卷积(Cosine Lobe Convolution) ,与传统辐照度探针处理方式一致
    • 最终像普通辐照度探针一样用于光照计算

优缺点

  • 优点 :支持完全动态的天空光照更新
  • 缺点 :只包含 直接天空光照(Direct Sky Lighting) ,没有来自环境的 反弹光(Bounce Light)

天空反弹光(Bounce Sky Lighting)

之前方案的局限

  • 在 《恶名昭彰》(inFAMOUS) 中曾使用 辐射传递矩阵(Radiance Transfer Matrices) ,适用于小世界
  • 但该方案需要 至少 9 倍的存储 ,在《对马岛》的开放世界中 内存消耗过大 ,且 捕获时间过长

近似方法:均匀天空假设

  • 核心假设:天空光在 半球上近似均匀(Approximately Constant)
  • 离线阶段 :
    • 用 均匀白色天空 加上天空可见性 SH 对世界进行光照
    • 将得到的反弹辐射投影到 SH,得到 反弹天空可见性(Bounce Sky Visibility)SH
  • 运行时 :
    • 将反弹天空可见性 SH 乘以 平均天空颜色(Average Sky Color)
    • 加到之前的直接天空光照结果上

视觉效果示例

阶段效果
仅使用天空 SH(无可见性)光照非常 平坦 ,没有遮蔽信息
加入 直接天空可见性有了基本的遮蔽和方向感
再加入 反弹天空可见性出现来自环境的 彩色反弹光 (如周围黄色树叶产生的黄色间接光)

太阳反弹光(Sun Bounce Light)

动机

  • 在 晴天 条件下,大部分反弹光来自 太阳 而非天空
  • 需要将太阳反弹光加入模型,但 不希望存储额外数据

核心思路:复用反弹天空可见性

  • 考虑一组 固定的少量反弹方向(Bounce Directions) ,效果优于假设反弹光在球面上均匀分布

反弹方向的选择

  • 观察发现:实际中大部分反弹光来自 水平面(地面) 或 垂直面(墙面)
  • 使用 虚拟地面平面 和 虚拟墙面平面 对光线方向进行反射
    • 地面反射方向 和墙面反射方向 恰好指向 相反方向
  • 将 取反后的反射光方向 投影到 SH,并进行 去振铃(De-ringing) 确保处处非负

计算流程

  • 云层遮蔽(Cloud Shadowing) 是动态的,不包含在离线捕获的天空可见性中,因此在运行时单独应用
  • 将结果加到之前的辐照度上

视觉效果

  • 无太阳反弹 → 室内/阴影区域偏暗偏冷
  • 加入太阳反弹 → 显著增加暖色调和亮度 ,差异非常大
  • 特别是在 室内场景 中,太阳反弹光让空间变暖变亮,效果自然

假设与局限

  • 关键假设:反弹天空可见性 SH 中包含的 余弦加权平均天空可见性 ,可以作为表面对太阳光遮蔽的合理估计
  • 这个假设 并不总是成立 ,但在实践中被证明 足够好

SH 方向性增强(Directionality Boost)

问题

  • 使用 二阶 SH(Quadratic SH / L2) 无法很好地表示 高频数据
  • 两个二阶 SH 相乘会产生 四阶结果 ,但为了节省存储,只保留到 二阶 ,高阶项被截断
  • 结果:光照看起来 偏平坦 ,法线贴图的细节不够突出

启发式解决方案

  • 向 线性 SH 最大值方向 上的 Delta 函数的 SH 投影 做 Lerp 插值
  • 对 直接光照部分 和 反弹光照部分 分别执行此操作
  • 计算开销很小
  • 最终全游戏统一使用 25% 的增强因子

效果

  • 未增强:光照平坦,法线贴图不明显
  • 增强后:法线贴图获得了 更清晰的明暗定义 ,表面细节更丰富

SH 去振铃(De-ringing)

问题:负瓣(Negative Lobes)

  • SH 表示中的 负值 是已知问题,尤其在高对比度区域(如窗户附近)
  • 会导致 不自然的暗区或颜色错误

解决方案

  • 初始尝试:对天空可见性施加 固定的去振铃因子 → 但会 降低方向性和保真度 ,不理想
  • 最终方案:在 运行时 GPU 上 对 天空亮度 SH 和 最终辐射度探针 SH 进行去振铃
  • 使用了 Peter-Pike Sloan 的论文 中提出的方法

实现细节

  • 寻找 SH 最小值:使用 深度为 3 的二分搜索树(Binary Search Tree)
  • 在实践中,单步牛顿迭代(Single Newton Step) 就足以找到 SH 最小值
  • 寻找保证 SH 处处非负所需的 最小去振铃因子

新旧窗口函数对比

  • 新的窗口函数(Sloan 论文)比 inFAMOUS 中使用的旧窗口函数 产生 更尖锐的结果
  • 对 Delta 函数的 SH 表示应用窗口化:新函数(蓝色曲线)比旧函数(红色曲线)保留了更多方向性

效果

  • 窗户附近的负瓣被修复,同时 场景其余部分的光照不受影响 (因为每个探针独立去振铃)

光照泄漏问题(Light Leaking)

问题描述

  • 当一个 明亮的辐照度探针 的光照 穿透遮挡物 (如墙壁、屋顶),导致另一侧出现 不自然的过亮光照
  • 在 inFAMOUS 中可以通过 在厚墙内放置额外探针 来回避,因为室内场景不多
  • 《对马岛》有 大量室内场景 ,且由于时代建筑特征, 墙壁非常薄 ,问题严重

尝试过的方案(均不满意)

方案问题
为每个探针添加 锥体(Cones) 标记被遮挡的邻居探针性能开销高
添加 遮挡平面(Occlusion Planes) 表示墙壁等遮挡物性能开销高
使用 低分辨率阴影图(Low-res Shadow Maps)性能开销高

最终方案:内外部探针分类 + 内部遮罩(Interior Mask)

步骤

  1. 分类探针 :将每个探针标记为 室内(Interior) 或 室外(Exterior)

  2. 内部遮罩值 :

    • 为每个表面分配一个 内部遮罩值 ,默认为 0.5
    • 可通过以下方式设置:
      • Shader 参数
      • 顶点颜色通道(Vertex Color Channel)
      • 延迟贴花(Deferred Decal) 单独叠加
  3. 加权插值 :

    • 正常计算 四面体重心坐标(Tetrahedral Barycentric Coordinates)
    • 对每个重心坐标进行加权:
      • 若对应探针为 室内 探针:乘以
      • 若对应探针为 室外 探针:乘以
    • 重新归一化 重心坐标
    • 按加权后的重心坐标进行正常的辐照度混合
  4. 回退机制 :若所有权重为零,回退到 原始重心坐标

效果

  • 未使用内部遮罩 :室内后墙因光照泄漏而 过亮
  • 应用内部遮罩后 :光照泄漏问题被修复,室内光照自然合理
  • 该方案在 运行时开销 和 额外制作负担 方面均可接受

间接镜面反射光照(Indirect Specular Lighting)


反射探针系统(Reflection Probes)

规模与内存管理

  • 前作 《恶名昭彰:次子》(inFAMOUS Second Son) 使用了 230 个静态反射探针 ,已接近内存上限
  • 《对马岛》最终使用了 235 个 反射探针
  • 由于重新光照(Relighting)所需的额外数据量约为 压缩后已光照探针的 1.5 倍 ,因此改为 按需流式加载(Streaming on Demand)

减少探针数量的策略

  • 为每个 生态群落(Biome) 添加 默认探针 ,作为该区域的基础反射
  • 对许多小型房屋等场景,使用 实例化室内探针(Instanced Interior Probes) ——多个相似室内共享同一组探针数据
  • 支持 一级嵌套(One Level of Nesting) ,处理游戏中大量的室内场景
  • 运行时最多同时支持 128 个重新光照的探针

重新光照所需的离线捕获数据

数据类型压缩格式说明
反照率立方体贴图(Albedo Cube Map)BC1存储表面颜色
法线 + 深度立方体贴图BC6HR/G 通道存储 八面体法线(Octahedral Normals) ,B 通道存储 双曲深度(Hyperbolic Depth)
  • 所有立方体贴图分辨率均为 256×256

运行时重新光照流程

更新策略

  • 每帧选择 一个探针 ,在 异步计算(Async Compute) 中更新
  • 由于探针体积不一定被 级联阴影贴图(Cascaded Shadow Maps) 覆盖,改用 远距阴影贴图图集(Far Shadow Map Atlas)
    • 每个 200 米 Tile 对应一张 128×128 的阴影贴图

间接光照采样

  • 出于性能考虑,每个探针使用 单个 SH 采样 来计算间接光照
  • 同一采样转换为 亮度(Luminance) 后,用于 反射探针亮度归一化(Luminance Normalization)
    • 确保探针在其捕获位置使用时具有 正确的预期亮度
    • 避免了将探针投影到 SH 的额外开销

探针预过滤与压缩

  • 使用 过滤重要性采样(Filtered Importance Sampling) 配合 GGX NDF 进行预过滤
  • 压缩为 BC6H 格式,使用 Krzysztof Narkowicz 的开源压缩器
  • 好处:
    • 显著 减少内存占用
    • 防止在高光泽且法线变化剧烈的表面(如 水面 )上出现 缓存抖动(Cache Thrashing)

立方体贴图阴影追踪(Cube Map Shadow Tracing)

问题

  • 室内探针的阴影不正确,原因:
    • 远距阴影贴图 分辨率太低
    • 许多建筑在渲染远距阴影时被 LOD 简化 ,丢失了几何细节

解决方案:利用立方体贴图深度进行遮蔽

  • 立方体贴图中已存储了 深度信息 ,包含丰富的 遮蔽信息
  • 重新光照某个纹素时 :
    1. 从该纹素位置 向光源方向回溯
    2. 找到光线与 立方体贴图体积的交点
    3. 在交点处 采样立方体贴图深度
    4. 使用 1 - Z 深度 表示,足够小的值视为 无遮挡
    5. 在 4×4 采样区域 上应用 PCF 过滤 来柔化阴影

局限性

  • 该方法较为 粗糙 ,仅沿光线采样一次深度
  • 可通过 沿光线多次采样深度 来提高精度
  • 存在误判情况:
    • 某些本应被遮蔽的位置可能被判为未遮蔽(漏判)
    • 某些本应未被遮蔽的位置可能被错误地判为遮蔽(误判)

视觉对比

  • 未启用 立方体贴图阴影追踪:室内反射中出现明显的 异常发光(Glowing)
  • 启用后 :发光大幅减少,反射中的地板和墙壁与实际场景 正确匹配

水平线遮蔽项(Horizon Occlusion Term)

问题描述

  • 美术反馈:法线贴图凹凸的 背面 在反射光照中 过亮
  • 原因:反射光本应被 宏观几何(Macro Geometry) 部分遮挡,但标准计算未考虑法线贴图法线 相对于顶点法线 的 倾斜(Tilt) 造成的遮蔽

输入空间

四维问题:

  1. 表面粗糙度(Roughness)
  2. 法线贴图法线相对于顶点法线的倾斜角
  3. 视角方向的两个分量

近似求解步骤

  1. 用锥体近似反射光线分布 :对于 GGX 粗糙度 ,包含能量比例 的锥体半角 由以下公式给出:

  • 取 (95% 能量)
  • 使用 曲线拟合 降低锥角计算开销
  1. 投影简化 :将法线贴图法线 投影到由 反射向量 和 顶点法线 组成的平面上,得到投影法线

  2. 定义关键角度 :

    • :投影法线与顶点法线的夹角
    • :反射向量的倾斜角
    • :锥体低于表面的角度
  3. 遮蔽角计算 :

  • 由于 BRDF 在 时已包含遮蔽,且 变化 1° 导致 变化 2°,因此钳制为 ,只计入 额外遮蔽
  1. 最终遮蔽量 :使用近似公式计算,结果永远不超过 (即锥体内的能量比例 95%)

视觉效果

  • 无水平线遮蔽 :河床岩石的背面出现 不真实的发光
  • 启用后 :岩石背面不再异常发光,效果自然

视差校正(Parallax Correction)

基本原理

  • 反射探针使用 美术创作的包围盒(Authored Bounding Box) 建模反射环境
  • 将 反射向量与包围盒求交 ,交点位置即为立方体贴图的采样位置
  • 问题:当前视点(蓝色眼睛)与探针捕获视点(红色相机)距离不同

粗糙度补偿

  • 设当前视点到采样位置距离为 ,捕获相机到采样位置距离为
  • 利用之前的锥角公式:

  • 观察到该比值 近似等于距离比 :

  • 因此采样立方体贴图时,按 距离比调整粗糙度 :

视觉效果

  • 未启用 :轻微粗糙的镀铬球体中障子纸屏风的反射 过于模糊
  • 启用后 :反射清晰度与实际距离匹配

天空、大气散射与云渲染


大气散射查找表(Atmospheric Scattering LUTs)

基本结构

  • 使用 预计算的 3D 查找表 来光照天空,同时也用于 云、体积雾霾(Volumetric Haze)和雾粒子(Fog Particles)

天空 LUT

  • 存储 瑞利散射(Rayleigh) 和 米氏散射(Mie) 的散射值,除以各自的相函数(Phase Function)
  • 索引维度:
    • 海拔高度(Altitude)
    • 平行光极角(Directional Light Polar Angle)
    • 视线极角(View Polar Angle)
  • 包含 多次散射反弹(Multiple Scattering Bounces)
  • 基于 Bruneton、Elek 和 Yusov 的论文
  • 3D LUT 不考虑 方位角(Azimuthal Angle) ,运行时应用 解析地球阴影项(Analytic Earth Shadow Term) 补偿

辐照度 LUT(Irradiance LUTs)

  • 问题 :直接用天空 LUT 光照云/雾/霾时,在 地平线附近 出现精度问题
  • 解决方案 :增加一组平行的 LUT,以相同方式索引,存储每个点的 散射后的瑞利和米氏光照值
    • 这些值是 乘以局部密度之前 的值,除以相函数
    • 单位为 勒克斯(Lux) ,可理解为每个点的一种 平均辐照度
  • 使用时:
    • 米氏辐照度 应用 阴影(Shadowing) ——因为米氏散射是 强前向散射
    • 瑞利辐照度 应用 环境光遮蔽(AO) ——因为瑞利散射分布 更加均匀
  • 体积雾霾中使用间接光照数据的 平均天空可见性 作为 AO,辅以 雨阴影贴图(Rain Shadow Map) 防止室内雾霾过亮

云渲染系统

基础参考

  • 基于 Andrew Schneider(SIGGRAPH 2015)和 Sebastian Hillaire(PBR 课程 2016)的工作

渲染目标

  • 云渲染到 抛物面贴图(Paraboloid Map) ,覆盖整个半球
  • 分辨率仅 768×768 (性能限制)
  • 格式:RGB11F

三通道编码

通道存储内容运行时操作
R米氏散射量乘以 LUT 中的 米氏辐照度
G瑞利散射量乘以 LUT 中的 瑞利辐照度
B透射率(Transmittance)直接使用

多次散射的重要性

  • 无多次散射 :日出/日落时天空和云的光照效果偏暗、缺乏层次
  • 有多次散射 :对场景外观影响 极为显著 ,尤其在日出/日落场景中

时间切片渲染

  • 使用 3 张抛物面纹理 :
    • 2 张 用于在云运动方向滚动时进行 混合(Blend)
    • 1 张 用于当前渲染
  • 渲染以 60 帧为周期进行时间切片 ,尽量降低开销

密度抗锯齿(Density Anti-Aliasing)

  • 问题 :低分辨率导致云在 UV 空间中位置变化快的区域出现 噪点和像素化边缘
  • 解决方案 :
    • 在极坐标下计算:
      • 径向云位置对径向纹理坐标的 导数
      • 角向云位置对角向纹理坐标的 导数
    • 极坐标下可以得到 相对简单的解析表达式
    • 当这些导数的最大值较大时,降低云密度
  • 效果 :关闭时有明显的采样噪点和锯齿边缘;开启后这些瑕疵 完全消失

运行时 LUT 优化

3D → 2D 重采样

  • 每帧根据当前 太阳和月亮角度 ,将 3D LUT 重采样为 2D LUT
  • 使用 三次上采样(Cubic Upsampling) :
    • 避免日出/日落时的 走样问题
    • 使后续 LUT 查找 更廉价

光谱近似瑞利散射(Spectral Approximation for Rayleigh Scattering)

动机

  • 大气散射驱动了游戏中大部分的世界光照,瑞利散射的精度至关重要

方法来源

  • 基于 Kristen Schüler 的博客文章,使用 自定义颜色空间 近似光谱渲染

两步优化过程

  1. 步骤一 :寻找三个 光谱主色波长 (长、中、短),使得在一系列太阳角度下 瑞利透射率误差最小化

    • 对浅角度(日出/日落)给予 更高权重
    • 使用该波长处的 点采样瑞利散射系数
  2. 步骤二 :固定主色波长,允许 瑞利散射系数自由变化 ,进一步精化结果

对比结果

对比项Rec 709 + Bruneton 系数LMS 颜色空间 + 优化系数
透射率绝对值和色调都有明显偏差与光谱渲染结果 非常接近
外散射色调偏差,偶尔出现 偏绿色调匹配度极高
日出/日落差异最显著显著减少偏绿色调

新颜色空间细节

  • 使用与 Rec 709 相同的 D65 白点
  • 自定义的 LMS 光谱主色 和对应的散射系数

大气光照:云层与体积雾


云层相位函数设计(Cloud Phase Function)

核心方法:深度自适应的 Henyey-Greenstein 相位函数

  • 使用 Henyey-Greenstein 相位函数 ,其中 不对称参数 随云层内部深度动态变化
  • 核心思想:
    • 在 低密度、稀薄的云层边缘 :以 前向散射(Forward Scattering) 为主,模拟 单次散射 主导的行为
    • 随着 密度增加 及 光照方向上的密度增加 : 多重散射(Multiple Scattering) 变得更重要,逐渐过渡到 后向散射(Back Scattering)

值的插值控制

  • 使用 到光源的透射率(Transmittance to Light) 与 当前光线步进段的透射率 的 乘积 作为插值因子:
    • 乘积 → 0:倾向 后向散射
    • 乘积 → 1:倾向 前向散射

自然产生的视觉效果

效果说明
银边效果(Silver Lining)逆光云层顶部边缘出现明亮光晕,自然产生无需特殊处理
暗边效果(Dark Edges)云层边缘变暗,无需使用 Schneider 提出的 "糖粉启发式(Powdered Sugar Heuristic)"

后向散射亮度缩放

  • 后向散射源自 多重散射 ,需要对其亮度进行缩放
  • 缩放系数为 2.16 ,通过模拟得出:
    • 使用大气多重散射模型模拟一个 反照率(Albedo)为 0.9 的致密 Mie 散射层
    • 理论上限为 4 (均匀散射层、反照率 = 1 时,等价于白色 Lambertian 表面)

视觉对比

  • 仅前向散射 :云层明亮但缺乏立体感
  • 仅后向散射 :可见暗边但整体偏暗
  • 前向 + 后向结合 :暗边清晰可见,逆光时银边效果自然呈现

体积雾光照与渲染(Volumetric Haze)

技术基础

  • 构建于 Bart Wronski(SIGGRAPH 2014) 和 Michał Drobot(Digital Dragons 2017) 描述的技术之上

Froxel 网格配置

参数值
网格分辨率宽度 128,高度 64,深度 64
覆盖范围近平面 10 cm 到远平面 100 km (覆盖整个视锥体)
深度切片分布指数增长 ,每层比前一层厚 20%

密度函数

  • 限制为两种 解析密度函数 的组合:
    1. 指数高度衰减(Exponential Height Falloff) :经典雾气分布
    2. S 形高度衰减(Sigmoidal Height Falloff) : 几乎总是为零
  • 在其他维度上的局部变化通过 粒子(Particles) 添加

计算流程

  • 通过 单次 Compute Dispatch 更新整个 Froxel 网格
  • 从前向后积分内散射(In-Scattering) ,使用 Quad Swizzling 和 4×4×4 线程组
  • 使用 时间滤波(Temporal Filtering) 平滑抖动的:
    • 阴影采样
    • 环境光遮蔽采样
    • 局部光源采样

双缓冲策略

  • 使用单个 RGB11F 缓冲存储最终光照值会导致 明显色带(Banding)
  • 改用 两张纹理分别存储 :
    • 好处一:可以对局部光源使用 不同的重投影策略(Reprojection Strategy)
    • 好处二:可以 跳过被遮挡 Froxel 的光照计算
    • 性能:两张纹理以全速率过滤,性能约等于采样单张 RGBA16F 纹理
  • 对于被遮挡的 Froxel,仍更新 阴影和环境光遮蔽项 ,以减少 去遮挡伪影(Disocclusion Artifacts)

性能

  • 全部在 异步计算(Async Compute) 中执行
  • 在 基础版 PS4 上,包含大量局部光源的重负载场景中约 0.5 毫秒

光源裁剪(Tiled Light Culling)

  • 分块光源裁剪 Compute Shader 同时输出 每 Tile 的光源列表 供体积雾使用
  • 线程间光源集合的 发散(Divergence) 对性能影响很大
  • 采用 扁平位数组(Flat Bit Array) 技术(Drobot,2017),某些场景下性能提升近 2 倍
  • 有趣发现 :对于 前向着色材质 ,使用 排序后的光源索引列表 反而比位数组稍快,因为光源列表的开销低于遍历位数组

体积雾抗锯齿(Volumetric Haze Anti-Aliasing)

问题

  • Froxel 网格非常 粗糙 但覆盖整个视锥体
  • 传统方法在以下场景产生 严重锯齿 :
    • 地平线附近
    • 薄雾层 中
  • 原因:密度变化的 欠采样(Undersampling)

核心技巧:存储辐射度 / 不透明度

  • 不直接存储散射辐射度 ,而是存储:

其中 是不透明度, 是透射率

  • 由于密度函数是 解析的 ,可以在 逐像素 级别重新计算透射率,合成到场景时再应用
  • 额外好处:不需要存储不透明度,体积纹理可以使用 RGB11F 格式

数学推导

  1. 假设 :散射系数 与消光系数 成正比,比值为反照率 :

  1. 体积渲染方程(距离 上的内散射辐射度):

  1. 代入 ,将 提出积分外

  2. 假设 (入射辐射度)在积分区间内 近似常数 (对于体积雾通常成立,除阴影区域外)

  3. 分离积分:

  1. 剩余积分有 解析解 :

  1. 因此:

  • 根据假设 近似常数,所以 是比 本身 更平滑的函数 ,采样时锯齿大幅减少

视觉效果

  • 未启用密度抗锯齿 :水面附近出现平行于地平线的明显 条带(Bands)
  • 启用后 :条带伪影显著减少

三维方向的全面抗锯齿

三次 B 样条滤波(Tricubic B-Spline Filtering)

  • 密度抗锯齿解决了深度方向的问题,但 所有三个维度 都需要抗锯齿
  • 使用 三次 B 样条三线性滤波(Tricubic B-Spline Filtering) 采样体积纹理
    • 需要 8 次三线性采样(Trilinear Taps)

性能

  • 令人惊讶地 廉价 :在 PS4 Pro 上以 3200×1800 棋盘格分辨率 运行时,仅比三线性采样多 50 微秒
  • 使用了三次权重函数的 近似公式 优化 ALU,对视觉效果无任何影响(详细公式见 Desmos 图表)

逐级效果对比

滤波方式效果
三线性滤波(Trilinear)X/Y 方向锯齿明显
双三次滤波(Bicubic) XY 方向X/Y 改善但仍有可见条带
三次滤波(Tricubic) 全方向几乎 完全消除 剩余锯齿,光轴与光源开口正确连接

大气粒子光照(Atmospheric Particle Lighting)


粒子雾气光照模型(Haze Lighting Model for Particles)

动机与方法

  • 使用 粒子(Particles) 为场景添加 局部雾气(Local Fog) 效果
  • 在粒子系统中增加了一个可选的 雾气光照模型(Haze Lighting Model)

光照数据来源

  • 在体积雾(Volumetric Haze)的 Compute Shader 中,将之前公式中的 存储到一个 并行光照体(Parallel Light Volume) 中
  • 该光照值 = LUT 采样的光照 × 相位函数 ,并应用了 阴影(Shadowing) 和 环境光遮蔽(AO) ,再加上 局部光源贡献

粒子着色器中的采样

  • 在粒子像素着色器中,采样 Froxel 光照体 并乘以 粒子不透明度(Opacity)
  • 优化策略 :
    • 不透明度低于阈值时,使用 三线性过滤(Trilinear Filtering) (性能优先)
    • 不透明度超过阈值后,切换到 双三次过滤(Bicubic Filtering) (质量优先)
    • 大多数粒子是 面向摄像机(Camera Facing) 的,因此 Z 方向上不需要额外过滤

视觉对比

  • 标准粒子光照 :雾气粒子与周围环境不够融合
  • 雾气光照模型 :雾气粒子更好地 融入场景

粒子多重散射近似(Multi-Scattering Approximation)

问题

  • 切换到雾气光照后,特效美术反馈:粒子在 正面照明时几乎看不见
  • 原因:雾气模型假设 单次散射 且以 前向散射为主 ,导致从正面(背光方向)观察时粒子极暗

解决方案:低成本多重散射近似

  1. CPU 端预计算 :

    • 计算 后向散射相位函数 与 Mie 相位函数 在前向和后向方向上的 比值
    • 使用 Henyey-Greenstein 相位函数 ,不对称参数 ,模拟多重散射(与云层方案类似)
  2. 粒子像素着色器中 :

    • 根据 视线方向与光照方向的点积 ,在前向和后向两个比值之间 线性插值(Lerp) ,得到 多重散射缩放因子
    • 再根据 粒子不透明度 ,从 1 到 之间插值
    • 用最终值 缩放粒子亮度
  3. 实际调整 :

    • 针对 后向散射 方向适当 降低效果强度 ,因为缺少完整的 Mie 颜色贡献时,粒子会看起来不自然地明亮

视觉效果

  • 无多重散射近似 :粒子平坦、缺乏形状感
  • 启用多重散射近似 :粒子获得更多 形状感和细节定义(Shape and Definition)

色调映射(Tone Mapping)


曝光系统(Exposure System)

前作的问题

  • 在 《恶名昭彰:次子》 和 《First Light》 中,难以维持资产的 物理合理漫反射反照率(Physically Plausible Diffuse Albedo)
  • 原因分析:基于 亮度(Luminance) 的曝光与反照率之间存在 反馈循环 ,导致:
    • 漫反射反照率值 偏暗
    • 镜面反射分量 相对过亮

改进措施

  1. 漫反射颜色参考图表(Diffuse Color Reference Chart) :

    • 基于多种物体的 反射光谱 转换为 sRGB 颜色
    • 帮助美术选择 物理合理的反照率值
  2. 基于照度的曝光系统(Illuminance-Based Exposure) :

    • 主要使用 照度(Illuminance) 而非亮度(Luminance),将 反照率从曝光方程中去除
    • 仅在 高光亮度超过阈值 时(如火焰粒子、明亮镜面高光)才回退到基于亮度的曝光

动态范围挑战

室内外亮度差异

  • 由于游戏的 历史设定 ,室内光照通常 非常昏暗
  • 室内外亮度差可达 10 EV(曝光值)
  • 目标:
    • 尽可能 保持可见性 ——提亮过暗区域
    • 同时 避免高亮区域过曝(Blown Out)
    • 天空驱动间接光照 ,常比环境更亮,但 艺术上不希望天空因色调映射而过度去饱和

摄影与电影行业的解决手段

技术说明
渐变滤镜(Graduated Filters)在镜头前使用渐变中灰密度滤镜压暗天空
特殊灯光装置与反射板(Bounce Cards)为暗部补光
冲洗阶段的减淡和加深(Dodging & Burning)选择性地提亮/压暗区域
阴影/高光调整(Shadow & Highlight Adjustment)数字时代的等效操作
多重曝光 / HDR 摄影合成不同曝光的照片

模拟人眼动态范围

  • 人眼能感知的 动态范围远高于相机
  • 选择使用 双边滤波器(Bilateral Filter) 来 保持图像细节的同时降低整体对比度

对比度降低的效果对比

  • 无调整 :高亮区过曝,暗部细节丢失
  • 直接降低 50% 对比度 :恢复大量颜色,但 局部细节严重扁平化
  • 使用双边滤波器 :保留了大量 局部对比度(Local Contrast) ,同时降低全局对比度

双边网格算法(Bilateral Grid)

为何选择双边网格

  • 朴素的双边滤波器 计算昂贵
  • 双边网格算法(Bilateral Grid Algorithm) 可以高效计算,且 内存占用低
  • 允许图像数据被 大幅降采样

网格配置

参数值
网格分辨率(XYZ)
性能开销PS4 @ 1080p 约 250 微秒
附带功能自然地与用于动态曝光的 亮度直方图生成 并行执行

算法流程

  1. 填充网格 :

    • 将 齐次对数亮度值 写入网格
    • 为权重, 为对数亮度
    • 初始权重基于 线性 Z 轴权重 ——每个样本贡献到最近的两个 Z 切片
    • X、Y 方向 无需加权 ,因为后续会施加宽模糊
  2. 高斯模糊 :

    • X、Y 方向使用 宽模糊(Wide Blur)
    • Z 方向使用 窄模糊(Small Blur) ,有时甚至完全省略
  3. 采样与归一化 :

    • 对每个像素,通过 三线性采样(Trilinear Sampling) 从网格中取值,并归一化得到双边滤波后的亮度

对比度调整公式

其中:

  • :输入图像的 对数亮度
  • :输出的 对数亮度
  • :双边滤波后的对数亮度
  • : 中点对数亮度 ——降低对比度时亮度值趋向的目标点
  • : 对比度缩放(Contrast Scale)
  • : 细节强度(Detail Strength)

振铃伪影与混合方案(Ringing Artifacts & Hybrid Approach)

问题

  • 在具有 平滑渐变 的场景中出现 振铃伪影(Ringing Artifacts)
  • 最常见于 云层、软阴影、镜面高光 区域
  • 原理:
    • 绿色输入信号经双边模糊得到紫色曲线
    • 降低模糊曲线的对比度,加回 细节(输入与模糊的差值)
    • 当模糊曲线与原始信号偏差较大时,回加的细节产生 过冲(Overshoot) ,导致振铃

权衡

  • 增大亮度桶(Luminance Buckets)或加宽 Z 模糊可减少振铃,但会 增加光晕(Haloing)

混合解决方案

  • 采用 混合方法(Hybrid Approach) :将双边滤波器输出与 很宽的 2D 高斯模糊 进行混合
  • 最终混合权重:
    • 40% 双边模糊
    • 60% 高斯模糊
  • 高斯模糊参数:
    • 13 tap 半径 的滤波器,应用于 64×32 的低分辨率图像
    • 上采样到 256×128 ,使用 双三次 B-Spline 过滤 (避免双线性过滤伪影,同时进一步增加模糊)
  • 效果:振铃伪影大幅减少,外观更自然,同时 保留了天空中的颜色

细节强度参数 的应用

  • 可以 增强局部对比度 ,使场景更具 冲击力(Punchier)
  • 例如 时画面明显更锐利有力
  • 项目中 节制使用 ,但作为艺术工具非常有价值

色调映射的颜色问题

逐通道色调映射的缺陷

  • 在渲染颜色空间中 逐通道(Per-Channel) 应用色调映射(如 Reinhard 算子):
    • 将饱和的非主色裁剪到 青色(Cyan)、品红(Magenta)、黄色(Yellow) 方向
    • 实际效果非常不自然——如日落和镜面高光处出现 过饱和的黄色
  • 即使预缩放输入颜色使其最大分量不超过 1,问题依然严重

色调映射色彩空间(Tone Mapping Color Space)


色彩空间选择与定制

候选色彩空间评估

  • 2017 年 Brian Karis 提到喜欢 ACEScg 作为色调映射空间时颜色向白色渐变的行为
  • 团队测试了多个色彩空间:
    • ACES AP0
    • ACEScg
    • Rec 2020
    • DCI-P3
  • 最终判定 ACEScg 整体效果最佳

ACEScg 的问题:红色偏黄

  • 在色调映射过程中,ACEScg 会将 红色和橙色色调过度弯向黄色
  • 尤其在日落场景中,艺术总监非常不满意天空 偏黄 的效果

定制解决方案

  • 将 ACEScg 红色基色(Red Primary)的 x 坐标从 0.713 调整为 0.75
  • 效果:
    • 减少了红色向黄色的偏移
    • 在不影响黄色场景(如 金色森林 )色调映射的前提下,恰到好处地减少了色偏和饱和度
  • 仍存在改进空间 :靠近蓝色基色的颜色仍然会较强地 偏向洋红色(Magenta)

色彩空间变换可视化

  • 通过动画展示色调映射如何在定制色彩空间中变换色域
  • 高亮度颜色最终会向白色收敛(Roll Off to White)

色调映射白平衡(White Balance)


调色工具现状

  • 仍使用较传统的调色流程:在 Photoshop 中操作截图,内嵌 32×32×32 sRGB 颜色查找表(Color LUT)
  • 艺术总监喜欢这个工作流,团队不急于更换
  • 局限 :LUT 分辨率有限,使用过于激进会引入 色带伪影(Banding Artifacts)

引入白平衡控制

灵感来源

  • Bart Wronski 的博客文章讨论了游戏中白平衡的应用思路

实现方式

  • 零 GPU 性能开销 :白平衡变换可以合并到 Rec 709 → 色调映射色彩空间的变换矩阵 中
  • 效果非常好,最终 不需要更换整套调色工具

交互设计:反向白平衡选择器

工具操作方式
Lightroom(传统)点击场景中 应该是中性灰的像素 → 系统将其校正为白色
《对马岛》的工具艺术家 选择希望白色变成的颜色 → 如想让场景偏蓝,就选蓝色
  • 艺术家认为这种 反向方式更直观

技术实现:色适应矩阵(Chromatic Adaptation Matrix)

  • 模拟 人类视觉系统 如何适应不同光照环境
  • 使用 Von Kries 变换 在 Bradford LMS 色彩空间 中进行:
    1. 将颜色转换到 LMS 空间 (近似视网膜中 长/中/短波锥体细胞 的响应)
    2. 按 白点比值 缩放各通道
    3. 转换回原始色彩空间

与色调映射的交互

  • 最终色彩空间仍为 Rec 709 ,因此高亮度/高饱和颜色仍会 向显示器白点收敛(Roll Off to Display White)
  • 仅低饱和颜色区域受白平衡影响最明显

浦肯野位移效果(Purkinje Shift)


夜间渲染的两大挑战

  1. 让夜晚 感觉像真正的夜晚 ,而非 "更暗的白天"
  2. 确保玩家在夜间 仍能看清楚 ,保证可玩性

人类视觉系统背景

视网膜感受器

类型数量功能
锥体细胞(Cones)3 种(长波 L / 中波 M / 短波 S)负责 常规彩色视觉
杆体细胞(Rods)1 种对 低光照更敏感 ,但为 单色(Monochromatic)

关键事实

  • 人类视觉是 三维的(3D) 而非四维,因为杆体细胞与锥体细胞共享 相同的神经通路
  • 在低光照下,杆体逐渐接管锥体的工作,引入 色偏 —— 即 浦肯野位移(Purkinje Shift)
  • 低光视觉 并非黑白 ,而是 偏蓝 的

色偏建模

  • 色偏可建模为 对立色彩空间(Opponent Color Space) 中的增量
  • 对立色彩空间被认为是 视觉系统内部使用的色彩空间

数学实现

第一步:RGB → LMSR 转换矩阵

从 Rec 709 RGB 转换到 LMSR 空间 (L/M/S 锥体 + R 杆体):

其中:

  • :LMSR 响应的行索引
  • :RGB 基色的列索引
  • :波长
  • :可见光波长范围
  • :感受器 的响应曲线
  • :D65 光源光谱
  • :使用 Smits 方法 求得的 RGB 反射率光谱

Smits 方法求解反射率光谱

  • 从 RGB 到光谱是一个 欠约束问题(Under-specified Problem)
  • Smits 方法寻找一组 最大化平滑度 的 RGB 基光谱
  • 约束条件:各光谱值在 [0, 1] 范围内且 总和为 1

第二步:计算增益控制向量

将场景颜色 转换为 LMSR 响应 :

计算 乘性增益控制向量(Multiplicative Gain Control Vector) (仅针对锥体):

  • :描述锥体灵敏度的常数向量
  • :描述杆体对 LMS 通路 输入强度 的向量()
  • 根据 Cow 等人 的论文, 应随照度增加而减小,但团队选择参照 Kirk 的方案使用 常数值
  • 这些常数有一定自由度 ,调整会产生不同效果,建议实现时进行实验

第三步:对立色彩空间中的杆体影响

丢弃 的 R 分量得到 (LMS 空间颜色),然后:

其中 为给定的变换矩阵。

计算杆体在对立色彩空间中的增量效应 :

第四步:转回 RGB

其中 是 的 左上 3×3 子矩阵

GPU 着色器实现

  • 整个计算仅需 三行着色器代码 ,非常高效

视觉效果

效果特征

  • 随光照亮度从明亮降至约 0.05 lux :
    • 暗色区域被提亮
    • 出现明显的 蓝色偏移(Blue Shift)

游戏中的实际效果

状态表现
未启用 Purkinje Shift夜间场景偏暗,视觉上像"暗版白天"
启用后(平均照度 ~0.05 lux)暗区(尤其 深蓝色水面和天空 )明显变亮,夜间氛围感更强且可玩性提升

总结要点

技术核心贡献
定制色调映射色彩空间基于 ACEScg 调整红色基色,减少红→黄偏移,保留日落和金色森林的正确色调
艺术白平衡零性能开销的色适应变换(Bradford LMS + Von Kries),反向选色器更直观
浦肯野位移基于人眼视觉模型的低光照色偏模拟,三行着色器代码实现,显著提升夜间场景的真实感和可玩性