《刺客信条:影》的渲染
Rendering Assassin's Creed Shadows
Anvil 引擎概述与历史演进
Anvil 引擎的诞生与定位
- Anvil 引擎 诞生于 2004 年(开发阶段),随 《刺客信条 1》 于 2007 年正式面世
- 引擎设计核心目标:
- 支撑 大型系统化开放世界(Large Systemic Open Worlds)
- 远距离渲染(Long-range Rendering)
- 系统化游戏玩法(Systemic Gameplay)
- 除《刺客信条》系列外,Anvil 还支撑了多个育碧大型 IP:《幽灵行动》(Ghost Recon) 、《荣耀战魂》(For Honor) 、《彩虹六号:围攻》(Rainbow Six Siege) 等
- 这些游戏类型跨度极大——竞技 FPS、多人对战、开放世界动作 RPG——对同一引擎的适配提出了巨大挑战
引擎分叉(Fork)问题与统一化改革
《刺客信条:影》的渲染目标与起点
项目定位与前作基准
- 前作 《刺客信条:英灵殿》(Valhalla) 是本项目启动时的 开放世界 AC RPG 基准线
- 关键区别:
- 《英灵殿》是一款 跨世代(Cross-gen) 游戏,需要同时兼容上一代和当代主机
- 《影》被定位为 首款真正的次世代(Next-gen)刺客信条游戏 ——不再需要兼容旧世代硬件
《英灵殿》的可扩展性局限
- 《英灵殿》在 画质模式(Quality Mode) 和 性能模式(Performance Mode) 下画面差异很小,可扩展性有限
- 主要的可扩展性手段几乎仅依赖 渲染分辨率(Render Resolution) 的调整
- 具体数据:在 Xbox Series X 上以 4K 原生分辨率 、 30 FPS 运行时,GPU 占用仅约 20 毫秒出头 ——这意味着 GPU 的性能预算远未被充分利用
《影》的核心渲染目标
- 基于对前作的分析,团队明确了核心方向:将可扩展性(Scalability)推向全新高度
- 作为纯次世代游戏,可以放开手脚利用新硬件特性,在画质和性能之间实现更有意义的差异化
要点总结
| 维度 | 关键信息 |
|---|
| 引擎 | Anvil,2004 年起步,支撑育碧多个核心 IP |
| 架构改革 | 从多引擎多分叉 → Monorepo 单一代码库共享引擎 |
| 前作基准 | 《英灵殿》跨世代,GPU 利用率低,可扩展性有限 |
| 本作定位 | 首款纯次世代 AC,目标:大幅提升可扩展性与渲染质量 |
《刺客信条:影》的项目规模与渲染管线
项目规模与复杂度
《影》的功能范围
- 使用 Anvil 引擎 构建
- 16×16 公里的开放世界 ,支持 昼夜变化(Time of Day)
- 以上这些在《英灵殿》中已经实现,但《影》在此基础上新增了:
- 大规模破坏系统(Massive Destruction)
- 光线追踪(Ray Tracing)
- 虚拟几何体(Virtual Geometry)
- 系统化天气(Systemic Weather)
- 四季变化(Seasons)
- 演讲者坦言:项目初期看到这份需求清单时"表情和大家一样震惊",但最终确实成功交付了
复杂度的直观展示
- 游戏场景同时叠加了 昼夜 、天气状态 、四季 三个维度的变化
- 同一场景在不同时间点、不同天气、不同季节(含冬季积雪)下呈现截然不同的视觉效果
平台与模式配置
- 纯次世代(Gen 5 Only) 游戏,支持三款当代主机
- 提供三种显示模式:
- 性能模式(Performance Mode)
- 平衡模式(Balanced Mode)
- 画质模式(Quality Mode)
- 各模式有不同的 目标分辨率
- 关键决策: 团队在开发初期就决定,光线追踪(Ray Tracing)优先用于画质模式
Anvil 引擎的远距离渲染架构
世界分区与流式加载
- Anvil 引擎 从底层就为远距离渲染(Long-range Rendering)而设计
- 世界被划分为 单元格(Cells) ,支持 多用户协同编辑
- 数据组织为 流式网格层(Streaming Grid Layers) ,网格定义完全 数据驱动(Data-driven) ——不同游戏可以有不同的网格配置
LOD 网格层级体系
整个渲染距离被划分为多个层级,从近到远依次为:
| 层级 | 名称 | 覆盖范围 | 内容说明 |
|---|
| 近距离网格(Short-range Grid) | LOD 网格 | 最近距离 | 大量小型道具(Props),靠近玩家时显示,远离后可以消失(对整体画面和游戏性影响不大) |
| 主网格(Main Grid) | LOD 网格 | 中等距离 | 大部分游戏资产 都在此层级 |
| 远距离网格(Long-range Grid) | LOD 网格 | 较远距离 | 大型资产或 兴趣点(Point of Interest) ,需要在更远距离保持可见 |
| 伪实体网格(Fake Entity Grid) | 简化资产 | 最远约 4 公里 | 包含 抽稀资产(Decimated Assets) 和 聚合资产(Aggregated Assets) |
| 点云(Point Clouds) | 批量冒名顶替者渲染 | 最远约 8 公里 | 大规模四边形冒名顶替者渲染器(Mass Quad Renderer) ,主要用于远距离树木等 |
| 地形远景(Terrain Vista) | 烘焙地形 | 8 公里以上 | 仅剩地形本身,大量细节被 烘焙(Baked) 进地形纹理 |
LOD 选择器与加载网格
- 加载网格(Loading Grids) 可以在 实体级别(Entity Level) 指定
- 距离切换由 LOD 选择器(LOD Selectors) 驱动
- LOD 选择器必须与加载网格 匹配(Matching) ——如果设置不一致,可能导致物体在错误的距离消失
点云渲染器效果展示
- 点云渲染器 本质上是一个 极快的批量四边形渲染器(Lightning-fast Quad Renderer)
- 用于在最远 8 公里 处渲染树木等植被的 冒名顶替者(Imposters)
- 开启前后对比效果显著——远处山坡、森林的覆盖密度差异巨大
- 调试视图显示:场景中冒名顶替者的数量 极为庞大 ,遍布整个视野
GPU 驱动管线的演进
历史:从《刺客信条:大革命》开始
- GPU 驱动管线(GPU-driven Pipeline) 自 《刺客信条:大革命》(Unity,2014 年) 起就是 Anvil 引擎的 基石(Cornerstone)
- 此后经历了多款游戏和多次迭代
第一代:Batch Renderer(批次渲染器)
第二代:GPU Instance Renderer(GPU 实例渲染器,简称 GPU IR)
- 专为 DX12 级别 API 设计的全新管线
- 关键改进:
| 特性 | Batch Renderer(旧) | GPU IR(新) |
|---|
| API 级别 | DX11 | DX12 |
| 绑定模式 | 需要绑定纹理 | 完全无绑定(Fully Bindless) |
| 批处理粒度 | 逐材质(Per-material) | 逐着色器(Per-shader) |
| 批处理时机 | 运行时 | 加载时(Load Time) 预计算 |
| 剔除能力 | 百万级以下 | 设计为 每帧剔除数百万实例 |
| CPU/GPU 分工 | CPU 占比大 | 大量步骤从 CPU 迁移到 GPU |
Database 概念
- GPU IR 依赖一个称为 Database 的核心结构
- Database 不是传统意义上的数据库 ,而是一个 CPU 与 GPU 之间共享数据结构的容器(Container)
- 它充当 CPU 和 GPU 之间的桥梁,使得 GPU 端可以高效访问渲染所需的所有实例、材质、几何数据
要点总结
| 维度 | 关键信息 |
|---|
| 项目规模 | 16×16km 开放世界 + 昼夜 + 天气 + 四季 + 破坏 + 光追 + 虚拟几何体 |
| 远距离渲染 | 6 层 LOD 体系,从近距道具到 8km+ 地形远景,完全数据驱动 |
| 点云渲染 | 极速四边形渲染器,8km 内渲染海量树木冒名顶替者 |
| GPU 管线演进 | DX11 Batch Renderer → DX12 GPU Instance Renderer(全无绑定、逐着色器批处理、加载时预处理) |
| 核心抽象 | Database ——CPU/GPU 共享数据结构容器,驱动整个 GPU 管线 |
GPU 数据库(GPU Database)系统
设计理念与核心概念
数据导向设计(Data-Oriented Design)
- GPU Database 遵循 数据导向设计(Data-Oriented Design) 原则,配合引用机制(Referencing Mechanism)
- 演讲者将其比喻为一个 "超级结构化缓冲区(Super-Structured Buffer)" ——本质上就是一块高度组织化的 GPU 可见内存
- Anvil 引擎内部有一套自研的着色器绑定编译器,称为 SIG(Shader Input Groups)
- SIG 负责 自动生成 所有 getter/setter 函数以及绑定代码
- 团队 扩展了 SIG 语言 ,使其能够 声明数据库表(Tables)
- 开发者无需手写访问接口——SIG 自动生成 C++ 端和 HLSL 端完全一致的访问代码
数据库类比
- 之所以称为"数据库",是因为使用了 数据库的类比方式 来组织数据
- 核心目的:在 CPU 和 GPU 之间共享完整的场景描述(Full Scene Description)
- 一个 行(Row) 本质上等价于一个 指向对象的指针 ——例如
Row<MyObject> 就相当于 MyObject*
表声明与跨语言访问
声明方式
- 在 SIG 格式中声明表结构(顶层定义)
- 编译后同时生成 C++ 和 HLSL 两端的访问代码
- 所有接口(getter、setter 等)全部自动生成 ,操作非常简便
关系系统(Relations)
一对一关系(One-to-One Relation)
- 数据库中的 一对一关系 本质等价于一个 指针(Pointer)
- 一张表中的某一行指向另一张表中的某一行
一对多关系(One-to-Many Relation)
- 一对多关系 是一对一的扩展——相当于 一个带有大小(size)的指针
- 可以从一个父对象指向 多个子对象
- 这使得系统能够构建出 类似 C++ 对象图的完整网格关系与属性描述
- 例如:一个 Mesh 实例拥有多个 SubMesh,每个 SubMesh 引用不同的 Material 等
CPU 到 GPU 的数据同步模式
GPU Database 在 CPU 和 GPU 上各有 不同的表实例(Table Instances) ,支持多种数据传播模式:
| 同步模式 | 机制描述 | 适用场景 |
|---|
| Copy Mode(完整拷贝) | 最简单的模式,将 CPU 端整张表 完整复制 到 GPU 端的 Byte Address Buffer 中 | 数据量较小、变化频繁的表 |
| Dirty Row / Dirty Pages(脏行/脏页更新) | 维护一个 脏标记掩码(Dirty Mask) ,仅将标记为"脏"的行或页 增量复制 到目标表 | 数据量较大但每帧仅少量变化的表 |
| CPU 端仅存脏行(Flush Mode) | 对于 极大的表 ,CPU 端 不完整存储 全部数据(避免内存饱和),仅暂存脏行,刷新(Flush)后即释放 | 超大规模表,CPU 内存受限场景 |
关键设计要点
- 数据流向 通常是 CPU → GPU ,但架构本身支持更灵活的方向
- GPU 端的表结构与 CPU 端 并非完全相同 ——GPU 端会 针对性优化 ,移除不需要的参数,保留渲染所需的最小数据集
要点总结
| 维度 | 关键信息 |
|---|
| 核心思想 | 用数据库范式在 GPU 上构建 结构化的完整场景描述 |
| 代码生成 | 通过扩展 SIG 编译器 自动生成 C++ 和 HLSL 双端访问代码 |
| 关系支持 | 一对一(指针)、一对多(带 size 的指针),可描述复杂的网格/材质层级 |
| 同步策略 | 三种模式:完整拷贝、脏行/脏页增量更新、仅存脏行刷新 |
| 优化原则 | GPU 端表结构独立优化,不存冗余数据 |
CalMesh 表结构、GPU 驱动管线与微多边形几何管线
CalMesh 数据模型与表结构
CalMesh 的 LOD 体系
- 每个 CalMesh 最多支持 5 个 LOD 级别
- 每个 LOD 包含:
- 两个 LOD 距离 ——一个用于 主视图(Main View) ,一个用于 阴影(Shadows)
- 两个 LOD 自定义参数 ,用于调整阴影 LOD 距离
- 几何体与 PSO(Pipeline State Object)的关联 在 子网格(Sub-mesh)级别 通过 Batch Hash 实现
- 关键约束:每个 PSO 只对应一个 Batch ,因此批次的去重(Deduplicate)极其简单
SIG 中的表声明
- 所有上述结构都通过 SIG 语言声明为表(Tables)
- 视觉上非常接近 结构化缓冲区(Structured Buffer) 的写法
- 表与表之间通过 Row(行引用) 和 Range(范围引用) 关系链接——对应前文提到的一对一和一对多关系
世界组织:核心树与叶节点
层级剔除结构
- 整个游戏世界被组织为一棵 核心树(Core Tree)
- 为了达到良好的 剔除(Culling)性能 ,依赖层级化结构:
- 实体组(Entity Groups) → 叶节点(Leaf Nodes)
- 叶节点本质上是一组实例(Group of Instances)
- 将 空间上彼此接近的实例 聚合到同一叶节点中
- 目的:最小化包围体(Bounding Volume) ,使 CPU 端的剔除更高效
表的生命周期(代码层面)
整个流程分为四步:
- 声明 ——分别声明 CPU 表和 GPU 表(二者结构可以不同)
- 填充 ——在 CalMesh 表中创建条目,设置各种属性
- 同步 ——触发表的 GPU 更新(底层使用前文描述的 Copy / Dirty Row / Flush 等策略)
- GPU 端使用 ——在着色器中获取数据并使用
布局注解:SoA 与 AoS 的灵活选择
- SIG 语言支持通过 注解(Annotations) 指定表的内存布局:
- 结构体数组(Array of Structures, AoS)
- 数组的结构体(Structure of Arrays, SoA)
- 甚至可以 混合搭配(Mix and Match)
- 这确保了 最大化缓存效率(Cache Efficiency) ——根据实际访问模式选择最优布局
- 演讲者总结:GPU Database 本质上就是一个 "我一直希望图形 API 能原生提供的超级结构化缓冲区"
完整 GPU 驱动管线流程
三阶段剔除架构
整个管线分为 CPU 阶段 和 GPU 两阶段 :
| 阶段 | 执行位置 | 具体操作 |
|---|
| 粗粒度剔除(Coarse Culling) | CPU | 对 叶节点(Leaf Nodes) 进行剔除——即按实例组为单位快速排除 |
| 帧级剔除(Frame Culling) | GPU | 对通过 CPU 剔除的实例,针对 所有渲染 Pass 的所有视锥体 统一执行剔除;同时处理 LOD 选择与混合(LOD Selection & Blending) |
| 逐 Pass 剔除(Per-Pass Culling) | GPU | 执行 特定于 Pass 的视锥剔除(Frustum Culling) 和 遮挡剔除(Occlusion Culling) ;例如太阳阴影会 按级联(Per Cascade) 进行视锥剔除 |
逐 Pass 剔除的额外职责
- 准备实例数据 ,供顶点着色器和像素着色器访问:
- 几何数据(统一顶点缓冲区中的偏移)
- 材质数据和常量(统一材质缓冲区中的偏移)
- 因为引擎使用 统一缓冲区(Unified Buffers) 存储顶点和材质数据,所以必须维护一套 描述信息 来定位每个实例的数据位置
可选的集群级剔除
- 在最终光栅化之前,支持 可选的(Optional) 进一步剔除:
- Cluster Culling(集群剔除)
- Triangle Culling(三角形背面剔除)
微多边形几何管线(Micro-Polygon Geometry Pipeline)
技术来源
- 基于 Brian Karis 在 2021 年发表的 Nanite 技术
- 本质是 离散集群网格管线(Discrete Cluster Mesh Pipeline) 的进一步演化
核心机制
| 特性 | 说明 |
|---|
| 集群层级结构(Cluster Hierarchy) | 网格由集群层级组成,支持 连续 LOD(Continuous Level of Detail) |
| 集群流式加载(Cluster Streaming) | 基于可见性 逐集群单独流式加载 |
| 混合光栅化(Hybrid Rasterization) | 多边形根据其屏幕大小选择 硬件光栅化 或 软件光栅化 |
| 使用场景 | 用于 G-Buffer 渲染 和 阴影光栅化 |
| 内存效率 | 相同几何体在此管线中占用的内存约为 GPU 实例渲染管线的一半 |
与业界其他实现的共同点
- 使用 Metis 库 进行 集群分区(Cluster Partitioning)
- 根据三角形大小选择 Mesh Shader 或 软件光栅化
- 采用 两趟层级缓冲遮挡剔除系统(Two-Pass Hierarchical Buffer Occlusion System)
- 从 Visibility Buffer 渲染不同材质到 G-Buffer
- 集群大小为 128 个三角形 (相比旧版 GPU 驱动管线如《刺客信条:大革命》使用的 64 个三角形,翻倍)
与业界其他实现的差异点
| 差异维度 | 《影》的做法 |
|---|
| 网格简化(Mesh Simplification) | 使用 SimpliGol 生成集群组简化——效果良好 |
| 自定义着色器支持 | 支持 用户自定义着色器代码 ,通过 手动 API 接入 Shader Graph |
| Bindless 架构 | 管线 完全无绑定(Fully Bindless) ,与 GPU 实例渲染器保持一致 |
要点总结
| 维度 | 关键信息 |
|---|
| CalMesh 模型 | 最多 5 LOD,每 LOD 双距离(主视图+阴影),PSO 通过 Batch Hash 在 Sub-mesh 级别关联 |
| 世界组织 | 核心树 → 实体组 → 叶节点(空间聚合的实例组),CPU 端粗粒度剔除 |
| GPU 剔除 | 帧级(全 Pass 统一)→ 逐 Pass(视锥+遮挡)→ 可选集群/三角形剔除 |
| 微多边形管线 | 基于 Nanite 思路,连续 LOD、逐集群流式、混合光栅化、128 三角形/集群、内存减半 |
| 统一设计 | GPU Database + Bindless 架构贯穿两套管线,SIG 自动生成双端代码 |
微多边形渲染统计与全局光照管线
软件光栅化优化:坐标翻转
X/Y 坐标交换技巧
- 软件光栅化算法本质上执行的是 扫描线算法(Scanline Algorithm) 来逐行填充三角形
- 通常扫描线是 水平方向 执行的
- 问题: 当遇到 垂直方向的三角形 时,水平扫描线的分支一致性(Branch Coherency)和负载均衡会变差
- 解决方案: 根据三角形的朝向配置,动态交换 X 和 Y 坐标 ——将垂直三角形"翻转"为水平处理
- 效果:提升分支一致性 和 工作负载均衡(Workload Balancing)
微多边形与 GPU 实例渲染器的分工
当前支持范围
| 渲染器 | 支持的几何类型 | 典型用途 |
|---|
| 微多边形管线(Micro-polygon) | 仅支持 静态不透明几何体(Static Opaque Geometry) | 城市建筑、静态几何 |
| GPU 实例渲染器(GPU Instance Renderer) | 支持 Alpha Test | 大规模植被渲染(树木等) |
- 目前微多边形管线 不支持 Alpha Test ,但这是未来计划要做的功能
城市场景统计数据
| 指标 | 微多边形管线 | GPU 实例渲染器 |
|---|
| 实例数 | ~28,000 | ~9,000(跨所有 Pass) |
| 渲染三角形数 | ~3,400 万 | ~200 万 |
| 软件光栅化比例 | 90% 的三角形由软件光栅化处理 | — |
- 软件光栅化比例 取决于 :
- 几何体本身的特性
- 曲面细分级别(Tessellation Level)
- 渲染分辨率 ——分辨率越低,每个多边形覆盖的像素越少,更适合软件光栅化
森林场景统计数据(反转场景)
| 指标 | 数值 |
|---|
| 剔除前实例数 | ~300 万 |
| 剔除后渲染实例数 | ~30,000 |
| 剔除前三角形总数 | 15 亿(1.5 Billion) |
| 最终渲染三角形数 | ~700 万 |
- 森林场景中 微多边形管线退居次要地位 ——仅渲染少量建筑和岩石
- GPU 实例渲染器承担主要负荷 ——大量树木植被的渲染
- 剔除效率极高:从 300 万实例中仅保留 3 万,从 15 亿三角形中仅渲染 700 万
关键结论
- 由于微多边形管线主要处理建筑等静态不透明几何,而森林场景的主要负载由 GPU 实例渲染器承担,因此 没有迫切压力 在微多边形管线中支持 Alpha Test
- 但未来 一定会加入 Alpha Test 支持
全局光照(Global Illumination)管线
GI 技术的历史演进
| 作品 | 技术方案 | 关键特性 |
|---|
| 《刺客信条:大革命》(AC Unity) | 体积化开放世界 GI(Volumetric Open World GI) | GPU 上使用 光线束(Ray Bundles) 烘焙;均匀 Mipmap 辐射度体积;Mipmap 作为远距离 LOD;不支持动态昼夜 ,使用 4 个固定静态氛围伪装 |
| 《刺客信条:枭雄》(AC Syndicate) | 在 Unity 基础上改进 | 新增 动态昼夜支持 ——在两个固定 GI 关键帧之间 混合插值(Blending) |
| 《刺客信条:起源》(AC Origins) | 稀疏化(Sparse) 体积 GI | 适配 16×16 公里超大开放世界 |
| 《刺客信条:影》(AC Shadows) | 可扩展 GI 管线 + 光线追踪 GI | 支持四季变化;从全烘焙到全光追的完整光谱 |
推荐参考:Josh Opson 关于 《战神》(God of War) 中辐照度缓存(Irradiance Caching)的演讲,其技术基础源自 AC Unity 的工作
规模化挑战:为何需要新方案
- 从 Unity/Syndicate 的数据 朴素外推 到 16×16 公里开放世界:
- 若再叠加《影》的 四季系统 :
- 数据量飙升至接近 2 TB
- 烘焙时间超过 600 天
- 即便拥有无限的云计算资源(Google Cloud、Azure 等),蓝光光盘容量也无法容纳 这么多数据
- 结论:必须从根本上改变技术方案
《影》的 GI 管线设计:可扩展光谱
设计原则
- 从一开始就以 可扩展性(Scalable) 为目标
- 光线追踪代价高昂,不希望为了 GI 牺牲游戏的其他部分——尤其是在 60 FPS 模式 下
- 考虑到 硬件多样性 ,给予玩家更多选择——实践证明这种做法 广受欢迎
GI 质量光谱
管线设计为一个从低到高的 连续光谱 :
完全烘焙(Fully Baked) ←————————————————→ 完全光追(Fully Ray-Traced)
漫反射 + 镜面反射 漫反射 + 镜面反射
| 模式 | 漫反射 GI | 镜面反射 GI | 说明 |
|---|
| 全烘焙 | 烘焙 | 烘焙 | 最低开销 |
| 混合 | 可选光追/烘焙 | 可选光追/烘焙 | 灵活配置 |
| 全光追 | 光线追踪 | 光线追踪 | 最高质量 |
光线追踪实现方式
- 硬件光线追踪(Hardware Ray Tracing) ——使用 GPU 的 RT 核心
- 软件光线追踪(Software Ray Tracing) ——使用 计算着色器(Compute Shaders) 实现
特殊场景:藏身处(Hideout)
- 藏身处是一个 完全动态的类《模拟城市》建造系统
- 建筑物完全由玩家放置,无法预先烘焙
- 必须使用光线追踪 GI ——否则将完全没有全局光照
要点总结
| 维度 | 关键信息 |
|---|
| 软件光栅化优化 | 根据三角形朝向交换 X/Y,提升分支一致性 |
| 城市场景 | 微多边形为主(2.8 万实例 / 3400 万三角形),90% 软件光栅化 |
| 森林场景 | GPU 实例渲染器为主,剔除比例极高(15 亿 → 700 万三角形) |
| GI 历史 | Unity(均匀体积)→ Syndicate(动态昼夜)→ Origins(稀疏化)→ Shadows(光追光谱) |
| 规模化瓶颈 | 16km 世界 + 四季 = ~2TB 烘焙数据 + 600 天烘焙时间,不可行 |
| 《影》GI 方案 | 可扩展光谱:从全烘焙到全光追,支持硬件/软件两种光追实现 |
烘焙 GI 的规模化优化策略
从 GPU 烘焙迁移到 CPU 烘焙
迁移动机
团队在从《起源》时代开始,将 GI 烘焙后端 从 GPU 转移到 CPU ,原因包括:
| 原因 | 说明 |
|---|
| VRAM 限制 | GPU 烘焙需要大量显存,内存悬崖(Memory Cliff) 问题严重,尤其在《起源》时期 |
| 构建农场一致性 | CPU 端不受 驱动差异 和 GPU 型号多样性 影响,结果更稳定 |
| 输入确定性 | 使烘焙输入 完全确定(Deterministic) ——能精确知道哪些需要烘焙、哪些不需要 |
| 分发更快 | 本地机器执行的工作更少,更容易分发到构建农场 |
密度图与稀疏探针放置
密度图(Density Map)
- 核心洞察: 在烘焙 GI 方案中,纹素/探针密度决定了细节质量 ——但密度 不需要在整个世界中均匀分布
- 解决方案: 使用 密度图(Density Map) 手动绘制 GI 分辨率
- 确保 最重要的区域 获得最高密度
- 只有 少数区域 (主要城市,图中蓝色区域)达到与旧作《大革命》相同的 50 厘米轴距 分辨率
- 尽管如此,这些高密度区域的 面积仍然大于 前几代游戏的整个地图
- 世界其余部分使用 低得多的密度 ,大幅节省存储空间
稀疏八叉树探针分布(Sparse Octree)
密度图之后数据仍然过大,进一步优化:
- 探针分布在 稀疏八叉树(Sparse Octree) 中
- 八叉树节点 仅在包含表面(Surface)时才细分
- 丢弃位于几何体内部的探针 ,进一步节省空间
- 最终结果:探针数量 仅为均匀分布的约 10%
昼夜与四季支持
昼夜变化:关键帧方案
- 存储 11 个关键帧(Key Frames) :
- 1 个 用于 局部光源(Local Lights)
- 10 个 用于 太阳不同位置
- 关键帧数量 完全由数据驱动 ,可根据需求增减
- 数据按 太阳光、局部光、天空光 分开存储,使用 YCoCg 格式 :
- Y(亮度/Luma) :具有方向性,以 球谐函数(Spherical Harmonics) 存储
- Co/Cg(色度/Chroma) :标量值
四季变化:最小化烘焙开销
目标:即使需要多次烘焙 GI,也要将 数据量额外开销降到最低 。
团队做出两个 "明知有误但实际可用" 的近似假设:
| 假设 | 说明 | 合理性 |
|---|
| 春季 ≈ 夏季 | 在间接光照层面视为同一季节 | BRDF 几乎一致,季节视觉差异主要来自 资产替换、雾和天气 ,而非光照本身 |
| Luma 跨季节不变 | 亮度(Y 通道)仅存储一份,色度(Co/Cg)按季节分别存储 | 这是明确的近似——当几何体在不同季节间发生显著变化时(如植被出现/消失),亮度与色度可能不匹配 |
处理不匹配问题的策略:
- 大多数受季节强烈影响的是 植被 ,影响可控
- 有问题的几何体可以由 技术美术(Tech Artist)标记并排除出烘焙
- 实际项目中 问题很少
运行时:稀疏数据到级联体积的插入
运行时管线流程
稀疏体素数据 → 解压(Decompression)→ 插入到级联3D体积(Cascaded 3D Volumes)
- 运行时使用 均匀采样的级联体积(Uniform Cascades)
- 稀疏数据需经过 解压步骤 ,转换为非稀疏格式后再插入级联
混合策略(避免 Popping)
| 混合类型 | 说明 |
|---|
| 跨级联混合(Cross-Cascade Blending) | 相邻级联之间平滑过渡 |
| 原地 GI Block LOD 混合(In-place GI Block LOD Blending) | 当新的 GI Block LOD 加载时,在原位置进行混合,避免弹出伪影(Popping) |
与前作对比
| 维度 | 《大革命》(AC Unity) | 《影》(AC Shadows) |
|---|
| GI 格式 | 离散 GI 网格(Discrete GI Grid) | 稀疏 GI Block 插入 级联 GI 体积 |
| LOD 机制 | Mipmap 按视距离散加载(类似 2D 纹理流式加载,但对象是 3D 体积) | 连续的细节层次(Continuous Level of Detail) |
| 视觉效果 | 效果已经很好 | 过渡更加平滑自然 |
最终数据量对比
| 方案 | GI 数据量 |
|---|
| 朴素均匀方案(类似《大革命》方式外推到 16×16km) | ~2 TB |
| 《影》最终方案(密度图 + 稀疏八叉树 + 季节压缩) | ~9 GB |
- 压缩比约 220 倍 ——从完全不可行的 2TB 降低到可接受的 9GB
- 主要贡献来自 密度图 和 稀疏网格
效果评价
- 团队 并未追求完全精确(Full Exactitude/Accuracy) ——这是一个 近似方案
- 但最终效果 可信且合理(Plausible and Believable)
- 考虑到数据量仅 9GB 却覆盖 16×16 公里 + 昼夜 + 四季,团队 对结果相当满意
要点总结
| 维度 | 关键信息 |
|---|
| 烘焙后端 | GPU → CPU ,解决 VRAM、确定性、一致性问题 |
| 空间优化 | 密度图 控制分辨率分布 + 稀疏八叉树 仅 10% 探针量 |
| 时间维度 | 11 个昼夜关键帧;春≈夏,Luma 跨季节共享,Chroma 按季节存储 |
| 运行时 | 稀疏数据解压后插入 级联均匀体积 ,跨级联 + LOD 混合 |
| 数据量 | 从理论 2TB 压缩至 9GB ,效果可信 |
镜面反射、光线追踪抽象层与混合光追 GI
镜面反射(Specular Reflections)管线
反射层级(按优先级排序)
| 优先级 | 技术 | 说明 |
|---|
| 1(最高) | 屏幕空间反射(SSR) | 首选方案 |
| 2 | 可重定位的 GBuffer 立方体贴图(Relatable GBuffer Cubemaps) | 预烘焙的局部立方体贴图 |
| 3(兜底) | 动态立方体贴图(Dynamic Cubemap) | 在玩家位置渲染,作为全局兜底的"区域立方体贴图" |
GBuffer 立方体贴图(GBuffer Cubemaps)
存储内容
- 每张立方体贴图存储完整的 GBuffer 属性 :
- Albedo(反照率)
- Normal(法线)
- Depth(深度)
- 运行时 动态读取并重新光照 ,而非存储预计算的最终颜色
烘焙阴影的巧妙编码
- 阴影信息也被烘焙进立方体贴图
- 存储方式:在 8 位纹理 中存储 8 个关键帧 ——每个关键帧占 1 bit
- 运行时:
- 选择与当前昼夜时间 最近的两个关键帧
- 在两者之间 插值混合(Blend)
- 效果 出奇地好 ——由于立方体贴图分辨率本身不高,即使没有过滤(No Filtering)也看不出问题
季节支持:变体状态(Variation States)
- 使用 变体状态(Variation States) 系统——一种数据驱动的、实体级别的游戏特定逻辑机制
- 每张立方体贴图最多存储 3 个变体 (回顾前文:春季 ≈ 夏季,因此只需 3 个季节变体)
- 并非所有立方体贴图都有变体——部分室内场景不需要季节变化
规模数据
| 指标 | 数值 |
|---|
| 总立方体贴图数量 | 16,000 张(不含变体) |
| 变体覆盖率 | 大多数室外立方体贴图都有变体 |
动态立方体贴图
- 设计目标:渲染成本极低
- 渲染内容:伪实体(Fake Entities) ——即抽稀/聚合的 LOD 资产
- 阴影使用 更低分辨率
- 对比展示:动态立方体贴图与同位置的局部烘焙立方体贴图 效果非常接近
光线追踪抽象层
设计背景与动机
- 光线追踪是《影》的 重大开发投入
- 受到 育碧 Snowdrop 引擎团队 工作的启发
- 关键决策:团队 不确定 最终哪种光追方案最优,因此选择 保持所有选项开放
- 目标:实现 Inline(内联)与 Non-inline(非内联) 以及 硬件与软件 光线追踪的 完全抽象
Fusion 硬件抽象层
- 光线追踪技术栈被抽象到一个名为 Fusion 的硬件抽象层之下
- Fusion 在 育碧内部跨多个引擎共享
- 采用 内源开发模式(Insourcing Model) :
- 代码托管在内部 GitLab
- 任何团队都可以贡献改进,惠及育碧多个项目
统一光线追踪 API
抽象维度包括:
| 抽象维度 | 说明 |
|---|
| 平台特定 API | 统一不同平台的光追 API(常规做法) |
| 硬件 vs 软件光追 | 同一接口同时支持硬件光追和软件光追 |
| Inline vs Non-inline | 同一接口同时支持内联和非内联模式 |
回调接口设计
光追循环(Ray Tracing Loop)
├── Hit Callback(命中回调)
├── Any Hit Callback(任意命中回调)
└── Miss Callback(未命中回调)
- Inline 模式: 根据命中状态(Hit/Any Hit/Miss),直接调用对应的回调函数
- 用户代码负责编写回调,使其 行为等同于 Non-inline 模式中的各个着色器阶段
- Non-inline 模式: 在对应的着色器阶段(Closest Hit Shader、Miss Shader 等)中调用 同一个回调函数
- 当然,Non-inline 模式通常还需要配置 Shader Table(着色器表)
切换的便捷性
| 切换类型 | 实现方式 |
|---|
| 软件 ↔ 硬件光追 | C++ 端仅需更改一个 枚举值(Enum) |
| Inline ↔ Non-inline | 差异主要在于 Shader Table 的设置 ,代码改动极小 |
| CPU 光追 | 部分平台甚至支持以相同接口进行 CPU 光线追踪 |
实际价值
- 在 Inline 和 Non-inline 之间自由切换,有助于:
- 验证假设(Validating Assumptions)
- 测试新功能(Testing New Functionalities)
- 找到最适合游戏的方案
混合光线追踪 GI(Hybrid Ray Traced GI)
两步骤架构
| 步骤 | 技术 | 说明 |
|---|
| 步骤 1 | 逐像素光线追踪(Per-pixel Ray Tracing) | 结合 屏幕空间光线(Screen Space Rays) 和 世界空间光线(World Space Rays) |
| 步骤 2 | DDGI 风格的探针级联(DDGI-like Probe Cascade) | 5 个级联,共约 10,000 个探针 ;每帧更新约 1,000 个探针 |
光追命中数据存储
- 光线追踪命中点的信息被存储为 一组 PBR 属性 ,写入一个 光追 GBuffer(Ray Tracing G-Buffer)
- 这意味着命中点不是直接计算最终颜色,而是记录表面属性,后续再进行延迟光照——类似于延迟渲染的思路
要点总结
| 维度 | 关键信息 |
|---|
| 反射层级 | SSR → GBuffer 立方体贴图 → 动态立方体贴图(三级回退) |
| 立方体贴图阴影 | 8 bit 存 8 个时间关键帧,运行时选最近两帧混合 |
| 季节变体 | 每张立方体贴图最多 3 个变体,全游戏共 16,000 张 |
| 光追抽象 | Fusion 层统一了平台/硬件软件/Inline Non-inline 三个维度 |
| 混合 GI | 逐像素光追 + DDGI 探针级联(5 级 10,000 探针,每帧更新 ~1,000) |
| 光追 GBuffer | 命中点存储 PBR 属性,延迟计算光照 |
光线追踪管线、加速结构与 Uber Shader
混合光线追踪管线流程
完整管线架构
屏幕空间追踪 → 世界空间追踪(硬件光线) → 命中缓冲区 → 去滤波/着色 → 降噪 → 最终合成
详细流程:
| 阶段 | 操作 | 说明 |
|---|
| 1. 屏幕空间追踪 | 首先在屏幕空间中追踪光线 | 作为 加速手段 ——硬件光线非常昂贵,先尝试在屏幕空间中找到命中 |
| 2a. 命中 | 将命中结果存入 命中缓冲区(Hit Buffer) | 无需发射硬件光线 |
| 2b. 未命中 | 保留当前 T 值,回退到世界空间追踪 | 从屏幕空间光线的终点 继续步进 ,使用硬件光线遍历 BVH |
| 3. 命中着色(Hit Deferred Shading) | 在延迟着色 Pass 中对命中缓冲区中的所有命中点进行 统一着色 | 类似延迟渲染的思路 |
| 4. 未命中处理 | 若某像素最终无命中 → 触发 Miss 事件 → 采样 探针缓存(Probe Cache) | 兜底方案 |
| 5. 第二次及后续弹射 | 采样 DDGI 级联(DDGI Cascades) 获取间接光照的后续弹射 | 仅第一次弹射使用光追,后续弹射用探针近似 |
| 6. 降噪 | 对结果进行 降噪(Denoise) | — |
| 7. 合成 | 叠加可选的 RT-AO 项 + 镜面反射(如可用) → 最终图像 | — |
为何额外叠加 RT-AO
看似矛盾的做法
AO 理论上应该 已经包含在光照积分中 ,为何还要在最终阶段额外叠加一个 RT-AO 项?
三个实际原因
| 原因 | 详细说明 |
|---|
| 频率混合问题 | 系统混合了两种不同频率的信号——精确的光追结果与低频的辐照探针;探针会 衰减高频细节 ,尤其是 AO |
| 四分之一分辨率追踪 | 大多数平台上光线在 1/4 屏幕分辨率 下追踪,丢失高频细节 |
| 光栅世界与光追世界的差异 | 某些几何体(如 草地 )出于性能原因 不存在于光追世界中 ,导致遮蔽信息缺失 |
补偿策略
| 补偿手段 | 作用范围 | 效果 |
|---|
| RT-AO(艺术驱动) | 大型物体(房屋、树木等) | 帮助大物体 融入画面(Ground to the frame) ,效果显著 |
| 微妙的 SSAO 项 | 厘米级细节(树冠、叶片等) | 弥补 1/4 分辨率追踪丢失的 近距离精细遮蔽 |
加速结构(Acceleration Structure / BVH)
灵活的配置选项
| 配置维度 | 选项 |
|---|
| 纹理模式 | 无绑定纹理(Bindless Textures) 或 平均颜色替代(用于金属纹理等,面向低端平台) |
| 剔除依据 | 按 尺寸(Size) 或 类型(Type) 过滤进入 BVH 的物体 |
| LOD 选择 | 使用 全局 LOD 偏移 决定放入 BVH 的 LOD 级别 |
| 微多边形管线 | 基于 LOD 误差度量(LOD Error Metric) 选择近似几何——与 NVIDIA 推荐的方法一致 |
| 覆盖机制 | 一切都可以 逐资产(Per Asset) 或 逐材质(Per Material) 覆盖 |
关键说明
- 加速结构的 GPU 开销很小 ——因为 GPU 驱动管线中所需的数据 已经存在
- 在没有 Mega Geometry 等技术的情况下,LOD 误差度量是 当前最佳实践
Alpha Test 植被的光追难题与解决方案
问题描述
游戏中有 大量茂密森林 ,Alpha Test 植被在光追中带来两难困境:
| 方案 | 问题 |
|---|
| 精确 Any Hit 着色器 | 大量重叠叶片导致 Any Hit 调用极其昂贵 ,性能不可接受 |
| 限制命中次数 | 遮蔽过度(过多阴影/黑暗区域) |
| 仅在植被上补偿 | 效果不佳,更像是 hack |
最终方案:按不透明度缩放三角形
团队尝试了一个 起初不被看好 的方案——结果效果出奇好:
- 方法: 根据纹理的 平均不透明度(Average Opacity) 缩放三角形面积
- 不透明度越低 → 三角形缩得越小 → 等效于部分透明
- 本质: 将 Alpha Test 问题转化为 纯几何问题 ——用缩小的不透明三角形 近似 半透明效果
效果与优势
| 方面 | 表现 |
|---|
| 性能 | 比 Any Hit 方案 快 30% |
| 漫反射 GI 质量 | 与参考图像 非常接近 |
| 屏幕空间精度 | 最近命中(Closest Hit)在 屏幕空间中解算 ,结果 像素级精确 |
| 遮蔽一致性 | 所有层级的遮蔽关系保持一致 |
| 镜面反射 | 作为额外收益,对 镜面光追 也是很好的近似——即使叶片三角形变成了不连续的集合 |
核心洞察: 两全其美——屏幕空间提供像素精确的最近命中,缩放三角形提供合理的全局遮蔽。
Uber Shader 方案
为何需要 Uber Shader
- 因为使用 Inline 光线追踪 ,无法使用传统的 Hit Group Shader 分发
- 需要一个 统一的 Uber Shader 来处理所有材质的光追着色
育碧的优势:严格的着色器管理
| 对比 | 说明 |
|---|
| Capcom 方案(参考) | 需要用 JSON 文件重新映射材质着色器——非常复杂 |
| 育碧 Anvil 方案 | 由于 GPU 驱动管线的需求 ,引擎对 着色器种类有严格限制 ——Master Shader 数量受控 |
- 这种严格管理使得编写 One-Fits-All Uber Shader 相对容易
- 当然仍然存在一些 极端案例(Epic Fails) ,但可以通过 覆盖机制 轻松解决:
- 可覆盖 BVH 中的内容
- 可覆盖 LOD 设置
- 可覆盖材质
- 可覆盖着色器
- 一切都可以覆盖
要点总结
| 维度 | 关键信息 |
|---|
| 管线设计 | 屏幕空间优先 → 硬件光线兜底 → 延迟命中着色 → DDGI 提供后续弹射 |
| AO 补偿 | RT-AO + SSAO 弥补低分辨率追踪和光栅/光追世界差异 |
| Alpha Test 植被 | 按平均不透明度 缩放三角形 ——比 Any Hit 快 30%,质量接近参考 |
| Uber Shader | 得益于严格的着色器管理,One-Fits-All 方案可行,极端情况靠覆盖解决 |
| 加速结构 | GPU 驱动管线数据复用 + LOD 误差度量 + 全面可覆盖 |
统一材质、软件光追、光探针与降噪管线
统一材质表示与季节处理
材质表(Material Table)
- 使用前文描述的 GPU Database 材质表 存储统一材质表示
- 光追命中时,通过 命中几何体 ID(Hit Geometry ID) 索引材质表
- 季节变化通过 材质版本(Material Version) 处理:
- 落叶季节:调整叶片材质以 减少过度遮蔽
- 叶片颜色:使用 查找表(LUT) 驱动不同季节的颜色变化
天气与积雪
| 特性 | 镜面反射光追 | 漫反射光追 |
|---|
| 延迟天气(Deferred Weather) | 完整评估 | 不评估(多次评估成本过高) |
| 静态积雪 | — | 烘焙在 地形远景(Terrain Vista) 中,仍可被漫反射访问 |
加速结构(BVH)规模数据
典型城市场景(Xbox Series X)
| 指标 | 数值 |
|---|
| BLAS 数量 | ~2,000 |
| 实例数量 | ~30,000 |
| BVH 总数据量 | 320 MB |
- PC 端数据更大——因为更多物体参与光追(LOD 配置更激进)
- 展示了 同一场景四个季节 的加速结构差异(植被变化导致 BVH 显著不同)
软件光线追踪(Software Ray Tracing)
定位与设计
| 方面 | 说明 |
|---|
| 目标平台 | 低端 PC(如 GTX 1070 等),未在主机上发布 |
| 技术来源 | 与 Snowdrop 引擎 的软件光追栈非常相似,属于 Fusion 底层抽象层 的一部分 |
| BVH 结构 | 三级 BVH(Three-level BVH) ,在底层 API 中实现 |
| 更新策略 | 依赖 空间分区(Space Partition) ,仅在 单元格加载或物体移动 时执行 局部更新(Partial Updates) |
室内体积与探针系统
室内体积(Indoor Volumes)
- 用于解决室内/室外 GI 漏光(Light Leaking) 问题
- 由 平面列表(List of Planes) 定义
- 同一份数据 被多个系统复用:
- 烘焙 GI
- 延迟天气(Deferred Weather)
- 音频系统(Sound)
- 用途:对探针进行分类(Classify Probes)
探针采样流程
采样位置 → 找到 8 个周围探针 → 按相同分类加权采样
- 确保室内位置只采样室内探针,室外位置只采样室外探针
光探针的两级缓存
| 缓存级别 | 类型 | 说明 |
|---|
| 近辐射度缓存(Near-Radiance Cache) | 类似 DDGI(McGuire) | 精确但可能不稳定 |
| 辐射度缓存(Radiance Cache) | 兜底方案 | 顶层稳定(Top-level Stable) |
信号稳定化策略
- 追踪更短的光线 ,减少噪声
- 远距离 回退到辐射度缓存 ——牺牲精度换取稳定性
- 演讲者展示的对比视频:一个具有 大量间接光照和狭窄开口 的挑战场景,稳定化前后差异显著
- 明确的取舍: 精度略有下降,但稳定性大幅提升
半透明处理(Translucency)
半透明表面的光追策略
| 情况 | 处理方式 |
|---|
| 直接命中半透明表面 | 随机全面评估(Stochastically Fully Evaluate) 半透明表面 |
| 阴影光线命中半透明表面(如障子——日本纸门) | 在表面 两侧分别采样探针 ,使用 半透明因子(Translucent Factor) 混合 |
全方向聚簇光照结构(Omnidirectional Clustered Lighting)
与传统聚簇光照的区别
| 传统方案 | 本作方案 |
|---|
| 视锥体对齐的聚簇体积(Frustum Cells) | 均匀网格(Uniform Grid) 围绕相机映射 |
| 单级结构 | 两级层级 :I-Clusters → Clusters |
结构细节
| 层级 | 说明 |
|---|
| I-Cluster | 包含 16×16×16 个 Cluster |
| Cluster 总数 | ~260,000 |
| 剔除流程 | 先执行 粗粒度 I-Cluster 剔除 → 再执行 细粒度 Cluster 级别光源剔除 |
- 使用全方向(Omnidirectional)结构而非视锥体对齐的好处:光追光线可以 向任意方向发射 ,不受视锥体限制
光追镜面反射(Ray-Traced Specular)
开发背景
- 项目末期紧急添加 ——在游戏延期后才有时间实现
- 演讲者坦言 "能发布简直是奇迹"
技术特性
| 方面 | 说明 |
|---|
| 目标平台 | 高端平台 ——PS5 Pro 和 PC |
| 设计基础 | 复用 漫反射光追 GI 的大部分工作 |
| 开发难度 | 相对容易——但暴露了 BVH 质量问题 ,这些问题在低频漫反射 GI 中不明显 |
| 降噪挑战 | 镜面反射信号更高频,降噪难度更大 |
降噪管线(Denoising)
引擎中的三套降噪器
| 降噪器 | 类型 | 说明 |
|---|
| 自研降噪器(True Denoiser) | SVGF 家族 算法 | 内部开发 |
| NRD(NVIDIA Real-time Denoisers) | NVIDIA 提供的 ReBLUR | — |
| MSD(Snowdrop Denoiser) | Snowdrop 引擎提供 | 最终发布使用的方案 |
MSD 降噪器特性
- 基于 时空滤波器(Spatio-temporal Filter) ,采用 递归模糊(Recurrent Blur) 方法——类似 A-BLUR
- 额外支持:
- 材质遮罩(Material Masking) ——为角色、植被、动态物体使用 特定启发式 处理 去遮挡(Disocclusion) 等挑战
- 球谐降噪(Spherical Harmonics Denoising) ——信号以 YCoCg 格式存储,其中 Y 通道为 球谐函数
降噪效果展示(逐层对比)
原始光追输出(Raw RT Output)
↓ 标准降噪
降噪后结果
↓ 球谐降噪
球谐降噪后结果(更平滑的方向性光照)
↓ 最终光照合成
最终光照(Final Lighting)
↓ 后处理
最终图像(Final Image)
- 与 纯烘焙 GI 的对比:演讲者表示纯烘焙 GI 的结果 "也还不错(Not too bad)" ——这正是可扩展管线的价值所在
小结:GI 管线的光谱
本作实现了从 全烘焙 到 全光追 的完整 GI 光谱:
纯烘焙 GI ←→ 烘焙 + 探针缓存 ←→ 软件光追 ←→ 硬件光追漫反射 ←→ 硬件光追漫反射+镜面反射
(低端 PC) (PS5 Pro / 高端 PC)
光追性能、天气与季节系统
光追镜面反射效果与性能
视觉效果对比
- 光追漫反射(RT Diffuse) 单独效果已经不错
- 叠加 光追镜面反射(RT Specular) 后,即使场景反射性不强,仍能显著 增强画面扎实感(Grounding)
- 关键优势:屏幕外物体(如商店外部)仍能 被正确反射
性能数据
| 组件 | Xbox Series X / PS5 | PS5 Pro |
|---|
| 光追探针(RT Probes) | ~1 ms | 更低(硬件更强) |
| 逐像素光追(Per-pixel RT) | ~4–5 ms | 更低 |
| 漫反射总计 | 5–6 ms | 显著更低 |
| 镜面反射 | 较昂贵 | 可在目标分辨率下运行 |
- 漫反射开销 分布在图形队列(Graphics Queue)和异步计算队列(ACQ) 之间
镜面反射的分辨率策略
- 发布时使用 半分辨率:宽度 ÷ 2,高度保持不变
- 选择半分辨率而非四分之一分辨率的原因:视觉效果显著更好,且预算允许
- PS5 Pro 上:
- 一切都更便宜
- 漫反射光追成本 大幅降低
- 最终 维持了目标渲染分辨率
天气与季节:系统化方法
整体架构
Atmos(大气模拟) ──┐
├──→ Ambiance Graph(氛围图)──→ 驱动所有天气/季节逻辑
引擎输入 ──────────┘
| 系统 | 职责 |
|---|
| Atmos | 大气因子模拟与传播(流体模拟) |
| Ambiance Graph | 基于节点图的数据驱动天气逻辑控制 |
| Multi-state Entities | 实体级别的季节/状态切换 |
Atmos 大气模拟系统
- 独立可做一整场演讲 的复杂系统
- 在玩家周围使用 低分辨率体素数据 进行运行时模拟
- 模拟并传播的大气因子:
| 因子 | 说明 |
|---|
| 蒸汽(Vapor) | — |
| 温度(Temperature) | — |
| 湿度(Humidity) | — |
| 风(Wind) | 使用体素碰撞 |
- 模拟结果输出到下游系统:
- 体积云(Volumetric Clouds) ——驱动云的 形成与消散
- 风和降雨 效果
- 右侧展示了 随海拔变化 的各物理量分布
Ambiance 系统演进
| 系统 | 特性 |
|---|
| 旧版 Ambiance Manager | 曲线驱动,逻辑有限,控制昼夜光照、后处理等 |
| 新版 Ambiance Graph | 基于 节点图系统(Another Graph System) ,完全数据驱动 |
- Ambiance Graph 的工作方式:
- 消费输入 :来自引擎和 Atmos 的数据
- 驱动输出 :整个天气和季节技术逻辑
- 完全由技术美术(Tech Art)控制 ——TA 可以决定一切行为
延迟雨渲染(Deferred Rain)
技术基础
- 基于 Sébastien Lagarde 的 Wet Block Post 系列博文(业界知名方案)
材质修改逻辑
| 步骤 | 操作 |
|---|
| 湿度(Wetness) | 根据湿度等级 压暗反照率(Darken Albedo) + 降低粗糙度(Decrease Roughness) |
| 水坑(Puddles) | 在湿度之上叠加水坑效果 |
数据存储
- 湿度遮罩存储在 GBuffer 中,仅占 单个 float
- 角色不参与 统一湿度系统——角色使用独立的 动态角色层系统(Dynamic Character Layer System)
效果序列
干燥场景 → 湿润场景(反照率压暗 + 粗糙度降低)→ 叠加水坑
积雪系统(Snow System)
三层积雪架构
| 层级 | 名称 | 说明 |
|---|
| 1 | 深雪(Deep Snow) | 数据驱动的印章系统(Stamper),可捕获纹理并 变形地形或任意高度图 |
| 2 | 延迟积雪(Deferred Snow) | 类似延迟雨的动态积累系统 |
| 3 | 冷/暖区域 | 由技术美术通过 静态/动态积雪遮罩(Snow Mask) 绘制 |
延迟积雪的材质修改流程
原始材质
├─ 1. 反照率(Albedo)→ 向雪白色插值(根据当前积雪等级)
├─ 2. 粗糙度(Roughness)→ 同样向雪的粗糙度插值
├─ 3. 半透明度(Translucency)→ 降低(主要影响植被,积雪越多越不透明)
├─ 4. 微可见性(Micro Visibility)→ 遮罩排除
└─ 5. 法线朝向阈值 → 垂直表面不积雪(模拟真实物理行为)
完整天气循环
暴风雪 → 积雪逐渐累积 → 暴风雪消散 → 积雪缓慢衰减 → 转变为湿润+水坑 → 最终融化干燥
- 整个循环逻辑 完全由 Ambiance Graph 驱动
室内排除与粒子遮挡
室内天气排除
| 系统 | 方法 |
|---|
| 延迟雨/雪 | 复用 室内体积(Indoor Volumes) ——与烘焙 GI、光追 GI 等使用 同一份数据 |
| 遮挡判定 | 将室内体积光栅化为 室内深度图(Indoor Depth Map) ,用于确定天气遮挡因子 |
| 性能 | 非常廉价——室内体积本质上 只是平面(Planes) |
雨粒子遮挡
| 步骤 | 说明 |
|---|
| 渲染遮挡深度图 | 以 雨方向为朝向 渲染周围环境的深度图 |
| 遮挡粒子 | 用此深度图遮挡雨粒子和涟漪 |
| 窗户穿透 | 雨粒子 可以穿过窗户进入室内 ——增加真实感 |
系统复用总结
一个值得注意的架构模式是 室内体积数据的极高复用率 :
室内体积(平面列表)
├── 烘焙 GI 探针分类
├── 光追 GI 探针分类
├── 延迟雨排除
├── 延迟雪排除
├── 延迟天气系统
└── 音频系统
这种 一份数据服务多个系统 的设计,体现了成熟引擎架构中数据驱动与系统解耦的理念。
可扩展性、性能管理、总结与 Q&A
设计背景
- 由于性能模式和画质模式使用 不同的 GI 系统(烘焙 GI vs 光追 GI),帧结构 差异很大
- 需要一套系统化的方案来管理所有配置
核心概念
| 概念 | 说明 |
|---|
| 数据驱动性能设置 | 按 平台 和 上下文 实现,不仅用于引擎和图形系统 |
| UI 自动生成 | 所有设置 自动生成编辑界面 ,且支持 实时编辑 |
| Profile(配置文件) | 性能模式、画质模式等——修改后需要 重新加载世界 |
| Profile Boot Settings | 需要 重新启动可执行文件 的设置 |
三种运行时调整机制
| 机制 | 触发方式 | 用途示例 |
|---|
| Air Context | 由 游戏逻辑触发(进入菜单、照片模式、返回游戏世界) | 照片模式下提升毛发渲染质量 |
| Modifiers | 由 数据触发——可通过绘制或 3D 体积触发 | 洞穴中禁用某些室外系统,解决局部性能问题 |
| Profiles | 玩家选择 | 性能模式 vs 画质模式 |
平台管理器的定位
Platform Manager 是 Anvil 引擎中的一等公民(First-class Citizen)
- 极大便利了 性能分析(Profiling) 工作
- 可以 模拟主机设置(在编辑器中,虽有限制)
- 与硬件厂商协作时非常有用——可以按厂商反馈快速调整配置
资源与性能追踪工具
内存追踪
| 工具级别 | 功能 |
|---|
| 高层级视图 | 追踪 资源生命周期 ,定位帧内 内存峰值 |
| 低层级工具 | 检查 内存分配器 ,调试 内存浪费 和 不期望的内存别名模式(Memory Aliasing Patterns) |
性能遥测(Telemetry)
- 游戏内置 大量遥测计数器 ,存储在数据库中
- 追踪示例:
- 动态分辨率因子 ——世界中每个位置的数据
- GPU 性能回归 ——跨构建版本在 PS5 上对比
- 其他各类性能指标
总结与未来展望
项目成就
| 里程碑 | 说明 |
|---|
| 首款 Monorepo + 共享引擎游戏 | AC Shadows 是首款以 Monorepo 和共享引擎模式发布的游戏 |
| 最大的 AC 游戏 | 有史以来规模最大的刺客信条 |
| 最可扩展的 Anvil 版本 | 迄今为止 Anvil 引擎最具可扩展性的版本 |
未来改进方向
| 方向 | 详情 |
|---|
| 微多边形(Micro Polygon) | 希望在 更多管线中支持 ,进一步提升几何细节——此次因需提前确定多边形预算而偏保守 |
| 光追 GI 更普及 | 烘焙 GI + 光追 GI 并存 对开发者非常困难 ;希望让光追更为主流以 简化管线 ;但认为给玩家选择始终是好事 |
| QA 复杂性 | 昼夜 × 四季 × 天气 组合使 QA 极其困难 ;升频器(Upscaler)的碎片化更加剧了问题;呼吁行业层面 重新思考 如何应对这种复杂性 |
| 基于图的天气/季节 | 原型迭代非常方便,但 QA 和问题复现困难;需要 更多迭代和成熟度 |
| 帧图模块化与定制化 | 希望在 Monorepo + 共享引擎的背景下进一步推进 帧图的数据驱动调度 |
Q&A 精选
Q1:macOS / iOS 移植的挑战?
问题: 最近也在 macOS 和 iOS 上发布了,与 PC/主机相比有何不同?
回答:
- 平台跨度很大(M1 到 M4),低端平台是挑战
- 通过 合理妥协(不影响游戏体验的功能降级)成功运行
- 主要挑战是开发环境 ——在 Mac 环境下使用 Xcode 工作,团队不太习惯
- 低端 Mac 上可能使用了 软件光追(Software Ray Tracing)
- 演讲者坦言:由于 Platform Manager 的配置 极其动态 ,有时自己都不确定某个平台具体用了哪些特性
Q2:微多边形管线是否支持植被(Alpha Test)?
问题: 类似 Nanite 中植被压缩的挑战,微多边形管线是否优化了植被?
回答:
- 目前不支持 Alpha Test
- 原因:现有 GPU 驱动管线 处理 Alpha Test 已经 非常高效 ——能渲染数百万三角形的森林,无性能问题
- 策略:先把不透明几何体做对 ,之后再攻克 Alpha Test
- 承认这是一个挑战,希望 花时间做对
Q3:多帧率目标(33ms vs 16ms)下的帧时间预算?
问题: 支持 30fps 和 60fps 多个目标,帧时间预算如何规划?
回答:
- 最大问题 是有/无 RTGI 的帧结构差异巨大——性能模式和画质模式是 两种完全不同的帧
- 尽量让 GPU 调度 尽可能接近 ,以避免各模式特有的 Bug
- 承认这是 一个头痛的问题 ,未来可能需要 按模式定制调度
- Monorepo 环境下同一代码库服务多个游戏,进一步增加复杂性
- 已开始探索 数据驱动的帧图调度 ,但此次项目中不敢激进推进
整场演讲核心要点回顾
AC Shadows 渲染技术栈
│
┌─────────────────────┼─────────────────────┐
│ │ │
共享引擎架构 渲染管线 系统化天气/季节
├─ Monorepo ├─ GPU-Driven ├─ Atmos 大气模拟
├─ Anvil 引擎 │ Pipeline ├─ Ambiance Graph
├─ Platform Manager ├─ 微多边形 ├─ 延迟雨/雪
└─ Fusion 抽象层 ├─ 混合 GI ├─ Multi-state Entities
│ (烘焙+光追) └─ 密度图 + 季节变体
├─ 光追抽象层
│ (HW/SW, Inline/Non-inline)
├─ 统一材质表
└─ 降噪 + 合成
核心理念: 在开放世界规模下,通过 数据驱动、分层抽象、可扩展架构 ,实现从低端 PC(GTX 1070)到 PS5 Pro 的全平台覆盖,同时支持昼夜、四季、天气的完整动态变化。