[UFSH2025]《三角洲行动》中的全局光照方案

[UFSH2025]《三角洲行动》中的全局光照方案 | 蔚东辰 腾讯天美J3工作室 引擎开发工程师

一、 项目背景与核心挑战

讲座首先明确了《三角洲行动》(以下简称"三角洲")在GI方案选型时面临的两个核心制约:

  1. 核心平台: PC 与手机端同发

  2. 核心要求: 所有玩家可见区域均需实现 GI 覆盖

  3. 核心挑战: PC与手游之间存在巨大的 性能鸿沟,这导致在技术选型上必须做出权衡和 "拉扯"。

二、 常见GI方案光谱 (The Spectrum of GI Solutions)

为了做出选择,讲者首先回顾了业界常见的几种GI方案,并分析了它们在“运行时性能”和“项目制作成本”两个维度上的优劣。

1. 四种主流方案

  • Light Map (光照贴图):

    • 特点: 最传统、最节省 运行时性能 的方案。

    • 优势: GPU效率极高(通过2U采样),美术可灵活控制局部纹素密度以提升精度。

  • Volume GI (PC端):

    • 特点: 基于 稀疏化存储 (Sparse Storage,如稀疏体素八叉树SVO)。

    • 优势: 精度高,显存占用可控。

    • 代表作: 《刺客信条》、《孤岛惊魂》。

  • Volume GI (手游端):

    • 特点: 基于 规整3D纹理 (Regular 3D Texture)。

    • 优势: 结构规整,寻址采样对GPU友好,性能消耗低。

  • 全动态GI (Full Dynamic GI):

    • 特点: 以虚幻引擎的 Lumen 为代表。

    • 优势: 视觉效果好,美术迭代效率 极高(制作成本接近零)。

2. 性能 vs 成本 对比

讲者将这几种方案放在一个“光谱”上进行对比:

维度Light Map (光谱左端)Volume GI (光谱中间)Lumen (光谱右端)
运行时性能最佳(消耗最低)居中(660显卡1080P下 <3ms)最差(Pass数量高一个数量级)
项目制作成本极高(迭代最慢)较低(可自动化)接近为零(迭代最快)

制作成本痛点分析:

  • Light Map 的痛点:

    • 需要制作和管理 2U。

    • Mesh(模型)与光照 不解耦,修改模型即需重新烘焙,"搞人心态"。

    • 调整纹素密度是一个 "时间黑洞"。

    • 对于大地图(如 "长空")和 TOD (Time of Day,动态时辰) 系统,全图烘焙 "根本就是一个不可能的事情"

  • Volume GI 的优势:

    • 无需 2U,Mesh与光照 解耦

    • 运行时根据位置查询即可,非常灵活。

    • 可实现 自动化烘焙流水线,美术只需拉取数据,极大释放生产力。

光谱总结: 越靠近左边,运行时效率越高,但制作成本越高;越靠近右边,开发者迭代越爽,但性能消耗越大

三、 《三角洲行动》的技术选型:“趋同进化”

基于上述分析和项目挑战,《三角洲》团队定下了选型原则:

  1. 第一优先: 保证所有平台的 运行效率(作为多人竞技游戏,目标 >120 FPS)。

  2. 第二优先: 在此基础上,尽可能提高 制作速度

1. 详细的跨平台需求

  • PC端:

    • 目标: 拔高视觉效果。

    • 首要考量: 控制显存。高精度的GI(无论是Light Map还是Volume GI)都会导致显存 "几何级别的增长"。

    • 倾向: 依赖 Volume GI 制作成本低 的优势(讲者给了4星期待)。

  • 手游端:

    • 首要考量 (No.1): 控制包体大小。如果全图铺 Light Map,在有 TOD 的情况下,包体将 "过于庞大"。

    • 第二考量: 控制GPU消耗。手游普遍瓶颈在GPU,Volume GI 的消耗不能比 Light Map 增长太多。

    • 现实: 受限于性能,手游的 Light Map 使用范围仍然更广

2. 最终方案:混合使用

《三角洲》的最终选择是 "全都用了"。讲者称这是一种 "趋同进化" (Convergent Evolution),因为《远光84》、COD等项目也采用了类似的混合方案。

  • 多人地图 (Multiplayer):

    • 采用 Light Map + Volume GI 的组合方案。

    • 其中 Volume GI 使用得更多。

  • 单人战役 (Single Player):

    • 采用 Lumen

    • 原因:没有PVP竞技的性能压力,可以最大化美术品质和迭代效率。

四、 方案详解:PC端的 Light Map 策略

讲座接着深入介绍了PC端 Light Map 的具体使用策略。

  • 烘焙工具:

    • 使用天美 自研JJS烘焙器,这是一个基于 GPU 的烘焙器(从CF手游迭代至今)。
  • 使用评价:

    • "又爱又恨"。品质和效率好,但离线制作 "吞噬时间"。
  • 应用策略 (以 "长空" 地图为例):

    • 克制使用: 仅用于特定区域(地图上标记为 "浅绿色" 的地方)。

    • 主要目的: 负责 室内光照

    • 烘焙内容: Light Map 上 只烘焙人工光天光可见度 (Skylight Visibility)

  • 该策略的优势:

    • 解耦TOD: 由于不烘焙太阳光,美术可以按 "切块" 独立烘焙,不受整体太阳光照方向(TOD)调整的影响。

    • 效率保证: 避免了全图烘焙导致地图 "永远就发布不了" 的问题。

2U 的痛点解析

“2U” 是指 “第二套UV” (Second UV set),也就是 UV1

在3D模型中,"UV" 指的是一套2D坐标,它告诉引擎该如何把一张2D贴图(比如颜色、法线)“贴”到3D模型的表面上。

  • “1U” (第一套UV,即 UV0):通常用于材质贴图(Albedo, Normal, Roughness等)。为了节省贴图空间,这套UV的某些部分可以重叠(比如一个对称模型的左右两边可以共用一套UV)。

  • “2U” (第二套UV,即 UV1):专门用于烘焙光照贴图 (Light Map)

为什么 Light Map 需要单独一套 "2U"?

讲座里提到这是个 "烦恼",关键原因在于 Light Map 有一个绝对要求它的UV必须是唯一且不能有任何重叠的 (Unique & Non-Overlapping)

你想想:

  1. 光照是唯一的: 模型上每一个点的光照和阴影都是不一样的。比如,一个桌子的左上角和右上角接受到的间接光照是不同的。

  2. 烘焙就是存数据: Light Map 这张贴图,存的就是模型表面每一个点的光照信息。

  3. 如果UV重叠: 假设你把桌子左右两边的UV叠在一起(像“1U”那样为了省材质贴图),那么烘焙时,引擎就懵了:这个UV点到底该存左边的光照,还是右边的光照?最后的结果就是光照和阴影全错乱了。

因此,所有需要烘焙 Light Map 的静态模型,都必须由美术师(或算法)额外创建一套完全展开、互不重叠的 "2U"。

为什么 "2U" 是个大痛点?

这就回到了讲座里提到的制作成本问题:

  1. 制作成本高 (时间黑洞):

    • "制作这一堆2U": 为一个大场景里成千上万个模型,手动去创建和优化这第二套UV,是一个极其繁琐、耗时的工作。你不仅要展开,还得排布得紧凑(节省贴图空间),同时保证UV块之间有足够的间距(防止光照"漏"过去)。

    • "Mesh和光照不解耦": 只要你稍微改动一下模型(比如移动个顶点),这个 "2U" 就可能失效了,Light Map 就得全部重新烘焙。这就是 "搞人心态" 的地方。

  2. 包体和显存问题:

    • 每个模型的 "2U" 都要挤进一张或几张巨大的 Light Map 贴图里。场景一大,这些贴图的体积和显存占用会非常恐怖。

总结

  • Light Map 的优势:运行时效率极高。GPU只需要拿到模型(专用于光照的)第二套UV坐标,去 Light Map 贴图上采个色,就拿到了光照结果。

  • Volume GI 的优势: Volume GI 是把光照信息存在三维空间体素(Voxel)里。模型在运行时是动态查询自己所在位置的空间光照,它根本不需要 Light Map 贴图,自然也就不需要那套折磨人的 "2U",实现了 "Mesh和光照解耦"。

五、 方案详解:PC端的 Volume GI (重点)

这是《三角洲》PC端覆盖范围最广的GI方案。其最大的好处大幅提升制作效率,同时品质能接近 Light Map。

1. 警惕:"Volume GI 陷阱"

讲者首先提出了一个项目管理上的“隐秘陷阱”,这是方案选型成败的关键。

  • 理想中的Volume GI: 制作代价(成本)大幅下降,而综合效果(画面+性能)轻微下降

  • “陷阱”中的Volume GI: 团队(程序、美术)都享受到了制作解耦的“爽点”(成本下降),但忽视了Volume GI的固有问题,尤其是 漏光 (Light Leaks)

这会导致两种灾难性后果:

陷阱类型现象最终结果
画面崩坏制作成本下降,但漏光等瑕疵导致画面品质也大幅下降。性价比未提升。
性能崩坏画面品质尚可,但是依赖昂贵的运行时算法去修复漏光,导致性能大幅下降。性价比未提升。

陷阱的最终结局: 测试团队提交大量Bug单(画面瑕疵或性能不佳),团队被迫 "反复折腾" 去写各种Hack代码修复,最终彻底丧失了Volume GI 低制作成本的优势

2. 成功的关键:防漏光 (Light Leak Prevention)

基于上述陷阱,讲者得出结论:

防漏光,是Volume GI方案从项目角度讲能否成功的一个关键因素。

  • 核心痛点: 如果漏光问题无法预测,就会产生海量的Bug单,这种拉扯会完全抵消掉制作效率上的优势。

  • 解决方案: 必须追求 "高性价比",即方案本身必须能 "斩钉截铁地告诉美术" 如何从制作层面完全避免漏光

3. 《三角洲》的"高性价比"防漏光策略

《三角洲》的策略不是依赖复杂的运行时算法,而是通过制定一个清晰的制作规范来从根源上解决问题。

  • 核心原则: 提高体素精度,直到它成为一个可以依赖的“标准”。

  • 《三角洲》的制作标准:

    • 体素精度 (Voxel Precision): 0.25米 (25cm)

    • 美术规范 (Artist Guideline): 所有墙体厚度必须 > 0.25米

  • 为什么这个标准有效?

    • 技术原理: 当墙体厚度大于一个体素的宽度时,在运行时进行 三线性插值 (Trilinear Interpolation) 时,墙体一侧的采样点“无论如何都不可能采到墙后面去”。

    • 效果: 只要美术遵守这个规范,程序就能保证(Guarantee)它 一定不漏光

  • 如何处理例外?

    • 对于必须很薄的物体(如 "铁皮房"),再单独使用 Hack 方案 处理。

    • 但这个清晰的标准能从制作层面规避掉绝大多数的漏光问题。

  • 战略重要性:

    • 这个规范必须从 “项目第一天” 就开始执行。

    • 否则,后期只能依赖昂贵的运行时算法(如 "world-space bent normals")来补救,这就又掉回了 "Volume GI 陷阱"。

4. 基础数据元素 (The Voxel Payload)

  • 存储内容: 方案的基础数据单元(Payload)是经典的 "6个方向的辐照度" (6-directional Irradiance)

    • 讲者提到这在《半条命2》中就很经典,并且《使命召唤:黑色行动》系列也在使用。

    • 这本质上是一个存储了6个面(+X, -X, +Y, -Y, +Z, -Z)光照信息的"Cube"。

  • 运行时采样: 根据物体的 表面法线 (Normal),对这6个方向的辐照度进行插值,得到最终的GI结果。

5. 存储方案:稀疏树形结构 (Sparse Tree Structure)

  • 核心问题: 0.25米是一个非常高的精度。如果使用规整的3D纹理(Dense Grid)来存储,显存会 "很快就炸了"(轻松上 8G / 16G)。

  • 解决方案: 必须使用 稀疏化存储 (Sparse Storage)

  • 核心原则: "越靠近Mesh,才存储高精度的体素"。高精度(0.25m)的数据只应 "贴着" 静态模型表面。

  • 技术参考: 团队参考了UE中集成的 OpenVDB(也是Houdini的核心组件)的存储代码,实现了一套高效方案。

6. 树的层级与构建 (Tree Hierarchy & Construction)

该方案实现了一个逻辑上的 64叉树 (64-ary Tree),具体层级如下:

  • Level 1 (基础层): 4米精度体素

    • 这是一个规整的 (Regular)、粗糙的体素网格(图中的黄色体素)。
  • Level 2 (中间层): 1米精度体素

    • 由4米体素 分裂产生 个子节点)。

    • 剪枝 (Pruning): 只保留那些靠近Mesh足够近(例如 < 3米)的1米体素(图中的蓝色体素),远处的直接舍弃。

  • Level 3 (精细层): 0.25米精度体素

    • 由1米体素再次分裂 个子节点)。

    • 剪枝 (Pruning): 阈值被进一步压缩,只保留距离Mesh表面非常近(例如 < 0.3米)的体素。

    • 结果: 最终的高精度体素 "基本就贴着Mesh摆了一层"。

实现备注: 讲者提到他们的实现中没有一个全局的根节点 (Root Node),而是直接从4米这一层开始。

7. 运行时查询算法 (Runtime Lookup Algorithm)

这是该方案的核心:如何根据一个世界坐标 (World Position),快速在Shader中查到对应的高精度体素数据。

  • 数据布局 (Data Layout):

    1. 首先,将整个树形结构进行 广度优先遍历 (BFS)

    2. 将遍历结果(所有存在的节点)存储在一个线性的序列 (Array) 中。

    3. 利用BFS的性质:一个父节点的所有子节点,在这个序列中必定是连续存储的

  • 节点中存储的关键信息:

    1. exist mask (64-bit): 一个64位的位掩码。它的每一位 (bit) 对应一个 局部栅格中的子节点,1 代表该子节点被保留,0 代表被剪枝。

    2. first_child_index (int): 一个整数 M,表示该节点的第一个子节点在上述 "线性序列" 中的起始下标 (Index)

  • 查询步骤 (Shader Traversal):

    1. 给定 WorldPosition,首先定位到它所属的父节点(比如一个1米体素)。

    2. 计算出 Position 在该父节点内的局部坐标(一个 的位置)。

    3. 将这个局部坐标映射exist mask 上的某一位 (bit)

    4. 检查该位:

      • 如果为 0:说明该位置的子体素被剪枝了 (Miss),查询结束。

      • 如果为 1:说明子体素存在 (Hit),继续下一步。

    5. 计算这个 1 在它之前有多少个 1。这个数量就是该子节点在 "子节点连续块" 中的局部偏移量 C

      关键优化: 这一步在Shader中可以 "一条指令" 完成,即 countbits (Population Count / 统计比特位为1的个数)。

    6. 计算子节点的绝对下标

    7. 迭代: 重复这个过程(最多3次),直到找到0.25米精度的叶子节点,或者中途Miss。

8. 最终数据获取 (Final Data Fetch)

  • 光照数据存储: 实际的 GI数据(6向辐照度)存储在另一个并行的线性序列 (Array) 中。

  • 获取数据: 上一步查询算法得到的最终 ChildIndex同时也是 GI数据数组的下标。

  • 插值: 运行时需要进行 三线性插值 (Trilinear Interpolation),因此上述的整个查询过程需要执行 8次(获取周围8个邻近的体素)。

  • 性能: 尽管要查8次,但由于 countbits 等硬件指令的支持,这个访问速度 "其实它是很快的"。

9. 数据拟合与压缩 (Data Fitting & Compression)

在实现了0.25米的稀疏体素存储后,团队面临两个新问题:

  1. 数据量依然大: 每个体素存储6向辐照度(Ambient Cube)需要 48 B

  2. TOD (动态时辰): 如果有8个时段,每个体素的数据将膨胀到 ,这是不可接受的。

核心目标: 每个体素存储的数据量必须是一个很小的常量,并且不随TOD时段的增长而增长

解决方案:基于"支撑点"的线性拟合

这个方案非常精妙,它将“重数据”和“轻数据”分离开:

  1. 生成支撑点 (Probes):

    • 使用 OpenVDB 沿Mesh表面生成一层 稀疏的 Probes (密度远低于0.25m的体素)。

    • 这些 Probes 负责存储“重数据”:即 48 B 的6向辐照度。

    • Probes 存储所有TOD时段的数据:比如8个时段,Probe就存储 的数据。因为Probe本身很稀疏,所以总包体可控。

  2. 体素存储"轻数据":

    • 对于每一个 密集的体素 (Voxel),不再存储48 B 的GI数据。

    • 而是找到离它 最近的4个Probes,用这4个Probe的数据进行 线性组合(拟合),来重建出当前体素的GI值。

    • 因此,每个体素 只需要存储

      • 4个 Index (用于索引是哪4个Probe)

      • 4个 float (用于这4个Probe的混合权重)

    • 最终体素负载: 恒定的 16 B

这个方案完美解决了两个问题:

  • 空间压缩: 从 48 B 降到了 16 B。

  • TOD解耦: 无论有多少个TOD时段,体素都只存16 B 的索引和权重。TOD的变化体现在Probes的数据上,而体素的重建逻辑不变。

如何求解:全局最优化

现在的问题是:如何确定 Probes 上(所有TOD时段)的最佳GI数值,以及每个 Voxel 上的最佳4个权重?

  • 目标函数: 这是一个全局优化问题。目标是让所有体素"拟合重建值""原始烘焙值" 之间的差的平方和 (Sum of Squared Differences) 最小。

    其中

  • 求解算法:

    • 这是一个可解的问题,因为该函数对于"权重"和"Probe数据"的偏导数 (Partial Derivatives) 都很容易写出,且没有"病态结构"。

    • 团队使用了标准的数值优化算法:共轭梯度法 (Conjugate Gradient Method)

  • 实现与性能:

    • 团队实现了一个基于 SIMD面向数据 (Data-Oriented) 的优化器。

    • 性能极高: 优化一个 64x64m 的数据块,单核仅需 9ms,多核并行后平均 < 0.5秒,远快于烘焙本身的时间。

10. 最终成果与开发哲学

显存成果

  • 通过 稀疏存储 + 拟合压缩 这一整套方案,"刀锋" 这张地图的 Volume GI 总显存 被控制在 200MB 左右,这是一个完全可以接受的量。

核心开发思路 (重要)

讲者最后强调了他们的思考顺序,这是避免"陷阱"的关键:

  1. 目标驱动: 一切从 "高性价比" 出发,这是项目的最高优先级。

  2. 推导1: 为了"性价比",必须避免昂贵的运行时防漏光Hack。

  3. 推导2: 这就 "推导出" 必须使用 0.25米 这种高精度体素,并制定美术规范(墙厚 > 0.25m)来从根源杜绝漏光。

  4. 推导3: 0.25米的高精度 "推导出" 必须使用 稀疏存储(如OpenVDB)来解决显存爆炸。

  5. 推导4: 稀疏存储+TOD需求 "推导出" 必须使用 拟合压缩 方案(Probes + Voxels)来进一步控制数据量。

结论: 方案的每一步都不是为了 "炫技" 或 "高大上",而是被上一步的约束和项目的最终目标(性价比)“逼” 出来的。

六、 方案详解:全地图远景GI (World-Scale GI)

在解决了近景的高精度GI(0.25m)后,团队面临一个新问题:如何用极低的成本实现全地图的GI覆盖。

1. 核心问题:视距与覆盖

  • 问题: 之前的高精度 Volume GI(0.25m)是流式加载 (Streaming) 的,覆盖范围有限(只在近景)。

  • 目标: 需要一个“常驻内存”、“完整的覆盖地图”的GI方案,尤其是为了太阳的间接光照,且其总数据量要极小(讲者希望能做到"近景一个tile的GI那么大的大小")。

  • 挑战: 像“海岛”这样的地图视距极远,传统方案无法胜任。

2. 方案探索:从“巨型体素”到“函数拟合”

  • 初步方案: 沿用之前的稀疏树形结构,但使用“巨大无比”的体素,例如 8米

  • 初步方案的缺陷: 如果一个8米的巨型体素只存一个GI值(如一个Ambient Cube),那么体素内部所有采样点得到的值都一样,远景看过去会是“糊的一团”,精度完全不够。

  • 进阶目标: 需要在8米体素内部定义一个紧凑的函数 F

    • 输入:体素内的局部坐标 XYZ (Local Position)

    • 输出:该局部坐标点 XYZ 对应的精确光照值

    • 效果: 如讲者演示,这个 F(XYZ) 应该能精确模拟出建筑屋檐下的遮蔽关系(里面是黑的)。

3. 最终方案:小型神经网络 (DNN)

这个紧凑的函数 F,就是用一个“小型的深度神经网络”来实现的。

  • 训练 (Offline):

    • 烘焙器在8米体素内部密集烘焙光照数值,提供大量训练数据(即 (XYZ, GI_Value) 数据对)。

    • 用这些数据去训练这个小型神经网络,使其能够“拟合”出体素内部的复杂遮挡结构。

  • 网络架构 (Architecture):

    • 结构: 2个隐藏层,宽度为 4。

    • 激活函数: Leaky ReLU

    • 输入: 局部坐标 XYZ

    • 输出: 单一的Luminance(亮度)值,而不是RGB。

      • 原因: 为了增大训练的精度。
  • 推理 (Runtime):

    • 在Shader中运行这个小型网络,本质上只需要 两次矩阵乘法

    • 性能: 因为网络极小,"并不会造成很大这个运行时的负担",但却能在8米范围内提供足够高的局部精度。

4. 方案特点与取舍

  • 优化器 (Offline):

    • 由于网络函数很小,团队 “手动的把里面这个各个参数这个导数写出来”,无需依赖PyTorch等重型框架。

    • 继续使用之前提到的 “共轭梯度优化器” (Conjugate Gradient Optimizer) 来完成训练。

  • “画素描”类比 (Leaky ReLU 的本质):

    • 由 Leaky ReLU 构成的神经网络,其输出本质上是一个“分段线性函数” (Piecewise Linear Function)。

    • 讲者将其比喻为“画素描”:用有限数量的“折线” (Straight Lines) 去尝试拟合一个复杂的形状(如建筑的遮挡)。折线的数量取决于 Leaky ReLU 单元的数量。

  • 可接受的漏光 (Acceptable Leaks):

    • 这个方案在室内看是会漏光的(如图所示)。

    • 但这是可以接受的,因为这是“远景GI”,玩家始终是从室外往室内看。

    • 漏光是可预测的:优化器会优先拟合"更亮的地方",因此光 "一定是从更亮的地方往更暗的地方漏",这在远景视觉上是合理的。

5. 最终成果:极低的显存占用

  • 视觉效果: 对比开关(仅有Streaming GI vs 全图GI),效果"非常非常明显"。

  • 显存占用 (核心指标):

    • 这些全图GI数据是非压缩的,直接存入显存。

    • 风暴眼 (Storm Eye): 22 MB

    • 刀锋 (Blade): 11 MB

    • 监狱 (Prison): 8 MB

  • 结论: "这个数据量是没有问题的",对于一个全图GI方案来说是"很合理的"。

七、 PC端方案总结:实现 "高性价比"

在详细介绍了近景和远景GI方案后,讲者对PC端的成果进行了总结,核心是"性价比"。

  • 性能消耗: 以 "攀升" 地图为例(3D80显卡),整套GI方案(远景GI + 近景Streaming GI)的GPU总消耗为 0.35ms

    • 这是一个 "可以接受的代价",其消耗量级与 深度预通道 (Depth Prepass) (0.32ms) 相近。
  • 显存占用: 总体控制在 200MB+

  • 核心理念 (高性价比): 讲者强调,Volume GI 的 "大幅下降的制作成本" 能够真正"有意义",其前提是必须首先解决所有的 "后顾之忧":

    1. 根治漏光(通过0.25m精度 + 制作规范)。

    2. 没有昂贵的运行时Pass(如特殊的防漏光处理)。

    3. 显存可控(通过稀疏存储 + 压缩)。

    4. 性能达标(GPU消耗接近Prepass)。


八、 方案详解:手游端 (Mobile) GI

手游端的挑战与PC完全不同,因此采用了截然不同的技术栈。

1. 总体方案:Light Map 为主,Volume GI 为辅

  • 混合方案: 同样采用 Light Map + Volume GI 的组合。

  • 重大差异: 手游端 Light Map 的使用范围 "确实是更大的"

  • 分工:

    • Light Map: 负责烘焙 人工光 (Artificial Light)天光可见度 (Skylight Visibility)

    • Volume GI: 负责 太阳光的间接光 (Solar Indirect)

  • 核心妥协: 手游的 Volume GI 覆盖范围很小,仅限 "眼前这么 64米"。

    • 效果: 64米外的GI会回退到远景平均值,但由于有 Light Map 提供的天光可见度,房屋的明暗关系 "看起来还是OK的"。

2. 核心架构:CPU 组装 vs GPU 采样

这是手游端方案与PC端最根本的区别,是基于平台瓶颈的深度定制。

  • PC vs Mobile 瓶颈差异:

    • PC端: GPU能力强,可以在Shader中实时 "访问稀疏树 (Sparse Tree)"

    • 手游端: 普遍 GPU瓶颈,无法承受在GPU上访问树结构的 "太耗费" 的操作。

  • 手游端方案: 充分利用手机 "4+4" 多核CPU(尤其是节能小核)的特性。

    • CPU (异步): 在小核心上 "异步组装" 一个包围相机的 规整3D纹理 (Regular 3D Texture)

    • GPU (运行时): 性能消耗极低,只需要采样一次这个3D纹理

3. 数据存储与组装 (折中方案)

为了平衡包体大小CPU组装效率,离线数据存储也做了特殊设计。

  • 核心矛盾:

    1. PC式稀疏存储: 节省包体,但组装时会导致大量 CPU Cache Miss,"CPU不友好"。

    2. 暴力规整存储: CPU访问快,但 "非常耗费包量"(手游第一红线)。

  • 折中方案 (分段连续存储):

    • 离线 (包内): 数据被分块,且每个数据块内部被存储为 "分段连续存储"

    • 通俗理解: 每一 "段" 是一个 "规整的长方体网格"(一个局部的小型3D纹理),只包围其局部空间。

    • 运行时 (CPU组装): CPU找到当前相机周围对应的 "数据块" 和 "分段",将这些小型的规整数据 "填充" (copy) 到那个包围相机的 "绿色的大框" (主3D纹理) 中。

  • 优化:

    • 主3D纹理需要做 Scrolling (滚动更新) 来保持稳定。

    • 数据是 分层分帧上传 到GPU的。

    • 大量使用手机特有的 半精度浮点数 (FP16) 的 SIMD 指令 来加速CPU组装过程。

4. 防漏光:Interior Volume (IV) 方案 (代码量最大)

这是整个GI方案中 "代码量最大的地方"

  • 根本问题: 手游的体素精度为 1米,而墙 "无论如何都不可能做到一米厚"。PC端的“制作规范”方案在此失效

  • 解决方案 (IV - Interior Volume):

    1. 制作: 美术随建筑额外制作一种 "简化的Mesh",称为 IV

    2. 规则: 一个建筑可由多个IV拼成,但每个IV必须是凸多面体 (Convex Polyhedra)

    3. 对齐: IV的"面" (Face) 被精确地 "卡在墙里面"

  • 工作流程:

    • 离线: 识别出"墙外"那些可能导致漏光的体素,并将它们与"墙内"的IV面片进行 "关联"

    • 运行时 (CPU):

      1. 根据 "相机在IV面片的前与后" 的关系,判断相机是在墙内还是墙外。

      2. 如果发现相机在墙的"这一边",而去采样了被"关联"到墙"另一边"的体素,就判定为漏光。

      3. 处理: 将这个"漏光体素"的数值 Fade Out 掉。

  • 妥协:

    • 由于数据是分帧上传的,这个Fade Out效果会有 "滞后更新"

    • 讲者表示,这在快节奏PVP中 "没有人在意",是一个可以接受的妥协。

5. 手游端压缩与成果总结

  • 数据压缩:

    • 方案: 与PC端类似,采用 Probe 拟合 的方案,但 Probe "稀疏很多"

    • 远场: 在远离Mesh的区域,不存储体素块,而是直接采样 "距离它最近的那个Probe" 上的光照。

    • 辅助: 运行时会动态生成一个 Distance Vector Field(距离矢量场),用于快速找到最近的Probe。

  • 包体成果:

    • 以"风暴眼"地图为例,Volume GI的包体为 334 MB

    • 巨大优势: 讲者估算,如果全用 Light Map 方案,包体 "会翻倍五倍不止",且工期 "不太可能"。

  • 手游端结论:

    • 制作代价: 大幅降低。

    • 包体: 大幅下降。

    • 防漏光: IV方案解决了拉扯问题。

    • 妥协: 太阳光的间接光范围很小 (64米),但 "手游上也是确实足够了"。

    • 总评: "总体性价比还是OK的"

九、 其他技术点

  • 手游远景GI:

    • 低配: 使用一个 "平均值" 替代。

    • 高配: 使用一个 "纵向俯拍的2D Texture"

  • SIMD的广泛使用:

    • 讲者强调,方案中 大量使用 SIMD(单指令多数据流)。

    • 并称赞 UE (Unreal Engine) 对 SIMD 的封装非常完善,使用直观,无需手写 "鬼画符" 般的汇编。

十、 方案详解:单人战役 (黑鹰坠落)

对于单人战役,团队采用了与多人模式完全不同的GI方案。

  • 核心方案: Lumen (UE5 原生方案)。

  • 采用原因:

    1. 开发时间极短。

    2. Lumen 无需烘焙等待,美术可以实时调节并立刻看到光照效果。

    3. 这种 "反复调整的(高)效率",使其最终的 "光照品质是更高的"

  • 技术实现:

    • 未做二次开发: 直接使用UE5的原生Lumen。

    • 软/硬件光追选择: 使用 软件光线追踪 (Software Ray Tracing),没有开启硬件光追。

    • 性能考量: 根据团队试验,只有在 3080级别及以上 的显卡,Lumen的硬件光追性能才会超过软件光追。因此,为了 "稍微照顾一下" 玩家的显卡性能,统一选择了软光追。

十一、 讲座核心总结 (Key Takeaways)

最后,讲者对《三角洲行动》的GI方案选型哲学进行了全面总结:

  1. Light Map 必须做取舍:

    • 在性能和效果达标的前提下,应 "更多的使用 Volume GI 去提升制作效率"

    • 追求极致精度(如从0.25m提升到0.1m)的 "边际效应是递减的",用 Volume GI 换效率是更明智的选择。

  2. 防漏光的黄金法则 (Golden Rule):

    • "做好防漏光,是 Volume GI 跳出性价比陷阱的关键。"

    • 在开发 Volume GI 方案时,"应该优先考虑防漏光",然后再去实现所有其他算法。

  3. 不同平台的首要关注点 (Platform Focus):

    • PC 端: 永远要多关注 "显存的控制"

    • Mobile 端: 永远要多关注 "包量"(包体大小)。

  4. 对未来的展望 (Lumen):

    • Lumen 带来了 "巨大的制作效率的提升"

    • 讲者相信 "再过几年",当玩家的最低配置都达到 3080 级别时,Lumen "一定就是市面上非常最普遍的一个方案"。