"Hi. I'm Thomas. I'm a graphics engineer at Activision Central Tech working on lighting for Call of Duty, and today I'm going to be discussing some recent developments and insights from our secondary lighting pipeline."
- 这一篇的舞台是一条跑了三十年的烘焙光照管线:CoD 要跑在从低端手机到本世代主机到几百帧的高端 PC 这一整条硬件谱上,内容从密集室内到 Warzone 的大尺度,所以可伸缩性是核心;烘焙同时承担直接光与间接光,
SECONDARY DIFFUSE里大部分是间接弹射,也含天空、自发光材质与静态/残余光(讲义 slide 3–4)。三处来源分工明确:静态简单物体用 lightmap,参数化困难的用局部光照探针,动态物体从探针网格重采样出局部体积(讲义 slide 5)。 - 最小二乘在球面上会退化:用基函数逼近信号、把平方误差的导数置零,就得到矩 = Gram 矩阵 × 系数;而 SH 在球面上正交归一,球面 Gram 矩阵就是单位矩阵,于是编码退化成「把目标函数与基函数相乘再积分」,蒙特卡洛形式就是「采样方向上求基函数值 × 样本强度再求和」(讲义 slide 7–9)。讲者特别提醒:这只在球面域上最小化误差 —— 这句话是后面那个关键修法的伏笔。
- AHD 的毛病出在混合上:
I(ω) = Ca + max(n·d, 0)·Cd简单好用、从 Quake III 用到 The Last of Us,但它是非线性模型,直接把系数存进 lightmap 再在 texel 之间插值会出过滤伪影与过冲(页内现象是混合后的 IrradZ 比两端都亮);2018 年的 IrradZ 编码改为存并插值标量辐照度 Iz 与环境权重 wa,重建时解回 AHD 参数并保持 Iz 不变,代价只有 2.5 字节/texel(讲义 slide 17–20)。 - 正题是一个「故意做错」的编码问题:对常数环境光做 AHD 编码,第一直觉(环境色 = 环境强度、方向色 = 0)是错的 —— 半球遮挡让辐照度越靠边缘越暗,最优化解出来是
Ca = 1/2、Cd = 1/2、d = nv,正好是一盏半球光;再叠一盏方向光就没有精确解(页内No exact solution!)。于是把重建式里的环境项换成一盏半球光,得到 HHD(讲义 slide 21–25)。 - 求解分线性与非线性两条路:误差取重建辐照度与 SH 辐照度之差;Iz 可烘焙时采样或由辐照度 SH 重建,wa 是线性参数用最小二乘,d 是非线性参数必须搜索(辐照度低频、误差函数行为良好,所以 θ 上做黄金分割、外层再搜 φ)(讲义 slide 26–29)。
- 两处小细节决定了这套求解是对的还是错的:算 wa 必须用半球 Gram 矩阵,用球面 Gram 等于把质量浪费在永远看不到的下半球(页内直觉:只看天的话,地面是绿的与你无关),RMSE 从 0.0473464 降到 0.0165971;而「最优线性方向」不能直接用,因为把 HHD 投影进线性 SH 后 z 分量被半球光污染,高光方向被拉向半球法线、侧倾不够、无法往返(讲义 slide 30–33)。
- 读数减半,但 HHD 不是处处都赢:三组 RGB 读数从 3.795/4.874/5.159 降到 1.514/1.805/1.597;但五个场景的逐场景表显示 AHD 与 HHD 的质量差别相当小,甚至能构造出让任一方赢的场景 —— 讲者的结论是换 HHD 的理由在混合:CoD 里会有可关的动态灯光组,而 HHD 作为合法的半球光照表述可以直接从线性 SH 廉价解回(讲义 slide 37–42)。
- 遮挡被做成一次矩阵乘法:半球遮挡要在 radiance 上先把下半球乘掉,再转成辐照度;低端在顶点着色器里做、高端在像素着色器里用 HLSH(z 基函数的权重恒由 IrradZ 给出)做闭式投影;把半球的积分上限换成锥角就得到
Gα,分量与半球乘法相同、系数变成 cos(α) 的多项式,于是同一套矩阵又能处理运行时 AO 给的可见性锥(讲义 slide 44–62)。讲者收尾的五条里,最可搬走的是那句「如果你的函数定义在半球上,就在半球上算误差」。
1一部 3A 射击游戏的烘焙光照长什么样
一部 3A 射击游戏的烘焙光照长什么样
讲者 Thomas Roughton 是 Activision Central Tech 的图形工程师,在 Call of Duty 上负责光照,这一场他讲的是次级光照(secondary lighting)管线最近的一些做法与体会(讲义 slide 0)。整场报告有底稿,是 2024 年 5 月的一篇 Activision 技术备忘录,编号写在讲义 slide 2 的论文前置页上(这一页按「讲义 slide 2 的论文摘要」口径引用,与本站自己的摘要无关)。
开场之后有一页致谢(讲义 slide 1),页内给的是一份名单:论文合著者 Peter-Pike Sloan、Ari Silvennoinen 与 Peter Shirley,Activision Central Tech 的几位同事,Infinity Ward Poland 的 Michal Drobot,行政与人力上的同事,Naty Hoffman 对论文的反馈,以及 Matt Pettineo 的 The Baking Lab;备注补一句,这一场建立在很多人多年的工作之上。这一页按名单照录,本篇不再展开。
讲义 slide 2 的论文页上列了四条主题,也就是这一场要讲的全部内容:更优的 lightmap 解,用于 lightmap 混合的半球光照模型 HHD(Hemisphere and Highlight Direction,半球与高光方向),SH 上的快速半球遮挡(hemispherical occlusion),以及用运行时 ambient occlusion / AO(环境光遮蔽)做 SH 的快速锥形遮挡。备注说这几条都在同一篇 Activision 技术备忘录里发表过。本章只搭舞台,四条主题从第 3 章起逐条展开,落到第 12 章再合起来收。
他接着摆语境,这一页幻灯区里只有版权行,语境全在备注里(讲义 slide 3)。CoD 是快节奏第一人称射击,要跑在从低端手机、到本世代主机、再到跑几百帧的高端 PC 这一整条硬件谱上;内容盘子从密集室内一直铺到 Warzone 的大尺度。两头一拉,可伸缩性就成了他们最看重的东西。每当要上一种光照技术,他们问的都是同一个问题:它能不能在这个性能范围里伸缩,同时在最新硬件上仍然给出前沿画面。
盘子的另一半在下一页(讲义 slide 4)。他们这条管线的特点是重度依赖 baked lighting(烘焙光照),而且让烘焙同时承担直接光与间接光。页内把漫反射拆成四段:PRIMARY DIFFUSE 与 SECONDARY DIFFUSE,两者合成 TOTAL DIFFUSE,再与反照率、镜面光照与后处理合成 FINAL LIGHTING。备注把第二段的来历说全了:secondary diffuse 这一块全部来自烘焙,其中大部分是间接弹射,里面也包含天空、自发光材质,以及静态光与残余光。也就是说,屏幕上那些看着像环境光的部分,运行时并没有真的在算,它们是烘出来的。备注还圈了一道范围:这两段漫反射的图要与反照率、镜面光照和后处理合成才是最终画面,所以这条管线对烘焙的依赖同时压在直接光与间接光两头。
烘出来的光照不止一张图,它分三处存放(讲义 slide 5)。静态简单物体用 lightmap(光照贴图);lightmap 参数化比较困难的物体改用一叠局部光照探针,讲义写作 surface light probes;动态物体则从探针网格里重采样出一个局部体积,讲义写作 light grid。备注给的分界是参数化难度:只有静态且简单的物体适合铺进一张 lightmap,参数化更困难的改用一叠局部探针;动态物体连固定的探针都留不住,只能每帧从探针网格里重采样出局部体积。三处来源各自服务一类物体,这个分工在后面会反复出现:lightmap 是这篇的主角,体积形式则给了第 10、11 章把遮挡乘进 SH 的场地。
本章可核对的结论有三条。语境是两端:硬件从低端手机排到跑几百帧的高端 PC,内容从密集室内排到 Warzone 的大尺度,可伸缩性是这套管线的核心(讲义 slide 3)。管线重度依赖烘焙光照,且让烘焙同时承担直接光与间接光,其中 secondary diffuse 全部来自烘焙,主要是间接弹射,也含天空、自发光材质与静态/残余光(讲义 slide 4)。烘焙输出分三路,静态简单物体走 lightmap,参数化困难的走局部光照探针,动态物体走从探针网格重采样的局部体积(讲义 slide 5)。下一章补一段数学,它是后面所有解法的共同骨架。
2先补一段数学:SH 与最小二乘
为什么要补这段数学,讲者交代得很直白:探针是用 spherical harmonics(球谐,下称 SH)编码的,lightmap 烘焙也大量用 SH;SH 在外面的名声有点吓人,所以他先给一段数学打底(讲义 slide 6)。这一页的幻灯区只有小节标题 SPHERICAL HARMONICS AND LEAST-SQUARES ENCODING,正文从下一页起。本章按一条线走:基函数与系数,误差与它的导数,正规方程里的矩与 Gram 矩阵,SH 正交归一让 Gram 矩阵退化成单位矩阵,最后落到蒙特卡洛形式的编码。第 4 到第 8 章的每一个解,都是这套骨架的实例。
出发点在讲义 slide 7。这里要逼近的信号可以是 radiance(辐射度)或 irradiance(辐照度),它定义在球面或半球的所有方向上。要逼近的信号记作 f,用一组 basis function(基函数)Ai 与一组系数 ai 去逼近它:
重建的做法就是:查询某个方向时,把该方向上各基函数的取值按系数加权求和。页内附了一段伪代码,循环从 0 到 coefficientCount,把 coefficients[i] 乘 basisFunctions[i].evaluate(direction) 累加进结果。求系数用的是 least-squares(最小二乘):误差取平方差,写成整个球面 Ω 上的积分;对系数向量求导,导数的形状是「基向量乘差值」:
把导数置零,就得到正规方程(讲义 slide 8)。左边是 projected moments(投影矩),也就是目标信号与基函数的投影;右边是 Gram matrix(Gram 矩阵)G 与系数向量 a 的乘积,G 由基函数的乘积在定义域上积分给出:
备注对 G 给了一句通俗解释:它大致告诉你基函数在定义域上重叠了多少。这里出现的三个名字各有分工:矩来自目标信号,Gram 矩阵来自基函数本身,系数向量是待求的量,后面几章反复用的就是这三者的关系。对 a 的求解,就是在矩上乘 G 的逆。这里有一条适用范围要记住:这套做法对任何线性基都成立,只是 G 的逆好不好惹,取决于源函数与积分域。
SH 的特殊之处在讲义 slide 9。SH 在球面上正交归一:同一个基函数的球面积分为 1,不同基函数的球面积分为 0,于是球面 Gram 矩阵退化成单位矩阵 I,最小二乘编码随之退化成投影矩本身:
蒙特卡洛形式读起来很直白:在采样方向上求基函数值、乘样本强度、再求和。备注在这里埋了一句伏笔,本章要把它记住:这只在球面域上最小化误差,后面会用到这一点。第 8 章会回到它,因为那时要在半球上做最小二乘,积分域一换,G 就不再是单位矩阵。
分带与基函数在讲义 slide 10 到 slide 11。SH 分两层:带(band)l 与带内函数 m,每升一带,多项式次数加一。前两带合称 SH2 或线性 SH,共四个系数;前三带合称 SH3 或二次 SH,共九个系数。不带归一化因子时,L0 带只是一个常数,L1 带是输入向量的重排,L2 带是各分量的组合;归一化因子由前面那条正交归一性质推出来。讲义 slide 11 给了一次二次 SH 探针的逐基函数重建,备注补一句:这些函数会取负值,页内用黑色表示。
对光照有用的三条性质在讲义 slide 12。它是线性基,所以混合与插值的行为是合理的,页内用交叉淡化(crossfade)一词。它旋转不变,先投影再旋转等于先旋转再投影。它与任意径向对称函数卷积有闭式,结果只是逐带缩放([SLS05]):要从辐照度 SH 重建辐照度,就把线性带乘 2/3、二次带乘 1/4。页内把辐射度记作 r、辐照度记作 i,两者之间就是这张逐带缩放表;表里还续着更高带的一项 −1/24,那是逐带卷积因子的续项,容易与「线性带几个系数、二次带几个系数」混起来,读的时候分开看。
本章可核对的结论:最小二乘的核心是式 2-3,系数等于 Gram 矩阵的逆乘投影矩;SH 因为球面正交归一,让 G = I,编码退化成矩,蒙特卡洛形式见式 2-4(讲义 slide 7 到 slide 9)。分带上,SH2 是四个系数、SH3 是九个系数(讲义 slide 10)。逐带缩放的读数是线性带 2/3、二次带 1/4,另列更高带 −1/24(讲义 slide 12)。本章埋下的伏笔是备注那句话:球面域上最小化误差这件事,换到半球上就不成立了,第 8 章会兑现它。
3标量不够:方向性 lightmap 与它的模型族
上一章把「用基函数逼近信号,在球面上做最小二乘」这套骨架铺平了,本章回到烘焙光照的另一半(讲义 slide 13)。这一页的幻灯区里只有一个词 LIGHTMAPS,是章节页,备注说接下来先看烘焙解的一半,另一半是探针那一侧。
标量辐照度 lightmap 在讲义 slide 14。lightmap 就是一张存光照信息的纹理,近三十年来最常拿它存 irradiance [CAC+96]。讲者用「近三十年」给它定位:这张纹理是这条管线里最老的一块底子。同一个 texel 只给一个颜色值,对整块表面是常数,这既是它省的地方,也是它撑不住法线贴图的地方。因为辐照度是低频量,lightmap 的分辨率通常可以远低于材质贴图。每个 texel(纹理元素)里存的是辐射度在 hemisphere(半球)上余弦加权的积分,出来是一个颜色值,乘上表面 albedo(反照率)就得到反射辐照度:
注意这里的积分域是上半球 Ω+,与第 2 章式 2-2、2-3 的整个球面 Ω 不同。这一步的含义是:静态表面的全局光照或弹射可以预计算,运行时只采样一张纹理。代价也写在这个积分里:方向在烘焙时就被积掉了,一张纹理的一个 texel 只能给出半球上一个余弦加权的总量。
标量的前提在讲义 slide 15 被拆掉。备注把动机说得很平实:实做中往往需要比标量辐照度 lightmap 能给的更多的细节。实时渲染大量使用 normal map(法线贴图)给粗糙几何加高频细节;朝天的法线本该比朝暗墙的法线亮,而一个 texel 只给得出一个颜色值。于是要把标量 lightmap 升级成能编码半球上这种变化的 directional lightmap(方向性光照贴图)[McTaggart04],重建时改用方向性光照模型。两页的先后关系要看清:标量 lightmap 先有三十年,法线贴图带来高频细节之后才需要升级,被换掉的是存放与重建的方式。
可选的方向性模型不止一种,讲义 slide 16 一口气列了六种,各带自己的文献:Ambient Cube 对 [McTaggart04]、球谐 SH 对 [RH01]、Ambient Dice 对 [IS17]、球面高斯对 [NP15]、H-basis 对 [HW10],以及最简单的 AHD(Ambient and Highlight Direction,环境与高光方向)对 [CDD+99]。备注对这六项的统一说法是它们的取舍各不相同,页内只挑了其中几种列出来,没有逐项对比。其中球面高斯能同时重建漫反射与镜面,是质量更高的一档。备注在这里有一段讲者自陈,需要照录:球面高斯确实质量更好,Neubelt 与 Pettineo 在 SIGGRAPH 2015 上讲过它在 The Order: 1886 里的用法,那一场可以一并找来看;但按他们的可伸缩性需求,他们要的是更紧凑的东西,所以从最简单的 AHD 出发。这一句让步决定了整篇的走向,第 4 章起说的都是 AHD 这条线。
本章可核对的结论:标量辐照度 lightmap 每个 texel 只存半球上余弦加权的积分,式 3-1,积分域是上半球 Ω+,因为辐照度低频,它的分辨率可以远低于材质贴图(讲义 slide 14)。法线贴图要求「朝天的法线比朝暗墙的亮」,标量值给不出这种变化,于是需要方向性 lightmap 与方向性光照模型(讲义 slide 15)。模型清单有六项,讲义把球面高斯放在高质量一档,而他们出于可伸缩性从最简单的 AHD 出发(讲义 slide 16)。还有一处原料上的分工可以从式 3-1 读出来:积分的输入是辐射度 R(ω),反照率乘在积分外面,两者一个是场景给的光,一个是表面自己的属性。下一章看 AHD 长什么样,以及它在混合时出的问题。
4AHD 用了二十年,但它有两个毛病
上一章末尾选了 AHD 作为起点,本章把它摊开。AHD 的全称是 Ambient and Highlight Direction,环境与高光方向,它把光照拆成两部分:一个环境色 Ca,加一盏方向光,方向色记作 Cd、方向记作 d。重建式在讲义 slide 17 给出:
页内把这个和式拆开摆成两格相加:环境项 Ca 一格,方向项 max(n·d, 0)·Cd 一格,末格是两者之和。从式 4-1 也能看出非线性落在哪一项上:环境项与方向无关,方向项对方向不线性,n·d 取到负值的那一半被截到 0。本章后半说的插值问题,根就落在这个截断上。
页内把这段过程排成三格对照,起点是那张环境图,终点是 AHD 的重建结果。这二十年的使用史写在备注里:从 Quake III: Arena 一路用到 The Last of Us,也用在 Activision 自家多款作品上,理由是它简单、求值便宜、质量也不错。「求值便宜」四个字可以从式 4-1 直接读出来:一次重建要一个点积、一次取最大值与两次乘加,没有基函数表要查。这一排对照要问的是:一个只有环境项加一盏方向项的模型,能把这张环境图对应的辐照度还原到什么程度。页内那张环境图来自 polyhaven 的 autumn_field,标注 CC0,这是全篇唯一带 CC 的素材(页内图像的版权另注 Activision)。
毛病出在混合上,讲义 slide 18 把它写成一句话:AHD 是 nonlinear model(非线性模型)。直接把它的系数存进 lightmap,再在 texel 与 texel 之间做插值,就会出 filtering artefact(过滤伪影)与 overshoot(过冲)。这就是本章标题说的两个毛病,它们是同一件事的两面。页内给的现象很具体:混合之后的半球法线方向辐照度,也就是他们叫 IrradZ 的那个量,比两端都亮。把系数直接存进 lightmap、再在采样时混相邻 texel,是这条管线的常规做法,讲义把问题落在这个动作上;这一页沿用的是 2018 年的图,版权行标的是 2018 ACTIVISION PUBLISHING。讲义把 IrradZ 这个名字提前用在这一页,是因为图里要对比的就是「按 AHD 存再插值」与「按 IrradZ 存再插值」两种做法,这个名字的完整定义留到第 5 章。两个毛病合起来指向一个判断:模型本身能用、也够便宜,但「合并 texel」这个动作会越界,把本来两端都合理的值抬到中间去。页内用现象演示的那一面落在过冲上:混合出来的中间值超出了两端。既然过冲出在混合这一步,绕开的办法可以换掉存进去的东西,让混合作用在行为更稳的量上,这条线在第 5 章展开。
本章可核对的结论:AHD 把光照拆成环境色 Ca 与一盏方向光(方向色 Cd、方向 d),重建见式 4-1(讲义 slide 17);它从 Quake III: Arena 用到 The Last of Us 与 Activision 自家多款作品,取的是简单、求值便宜与质量不错。它的毛病在混合:非线性模型直接存系数再跨 texel 插值,会出过滤伪影与过冲,页内给出的现象是混合后的 IrradZ 比两端都亮(讲义 slide 18)。还有一条读法要在这里立住:讲义没有把 AHD 与别的方向性模型做横比,页内出现的对照都在同一套内部管线内,后面第 9 章那几张读数页要按这个口径读。修法在第 5 章,讲的是改成存什么、插值什么,模型本身先留着不动。
5IrradZ:把标量辐照度与环境权重拆开存
上一章的结论停在一处现象上:把 AHD 的系数直接存进 lightmap、再在相邻 texel 之间插值,混合后的 IrradZ 会比两端都亮,页内把这一类后果合称过滤伪影与过冲(讲义 slide 18)。本章要看的修法换掉了被存与被插值的对象,运行时那个模型本身先留着不动,改动集中在一张纹理里放什么。这一章按三步走:先看存下来的三个量,再看它为什么能压住伪影,最后看体积账。
修法在 2018 年发表,页内标作 IrradZ lightmap 编码,文献号 [SS18](讲义 slide 19)。原先的 AHD 在一张 lightmap 里放两个颜色和一个方向:环境色 Ca、方向色 Cd,以及方向 d。IrradZ 把它换成三个量并逐个插值。第一个是标量辐照度 Iz,页内写明它的口径是 luminance(亮度);第二个是一个环境权重 wa;第三个是高光方向 d,改用八面体编码(octahedral encoding)保存。页内把两套插值并排摆在同一张图上,左边标 AHD INTERPOLATION,右边标 IRRADZ INTERPOLATION,中间是两条把 IrradZ 解回 AHD 参数的式子(讲义 slide 19)。
式 5-1 说明份额怎么分:环境色拿走 Iz 的 wa 那一份,方向色拿走剩下的 1 − wa。重建的时候把这两个参数解回来,同时保持 Iz 在整个重建里不变(讲义 slide 19 备注)。解回 Ca 与 Cd 只需要两次乘法,运行时求值的开销与原来的 AHD 处在同一量级(讲义 slide 19)。
保持 Iz 不变带来三条收益,讲座备注把它们逐条讲了(讲义 slide 19 备注)。第一条是修掉插值伪影,混合后的结果不再出现比两端都亮的情况。第二条是保证半球法线或顶点法线方向上的取值始终精确,Iz 取在这个方向上,插值动不了它。第三条是改善这些法线附近的精度,旁边的方向也跟着稳下来。三条放在一起看,改动落在「插值什么」这一层:被插值的是还没混合的中间量,重建那一步才把它们合成颜色。换来的是混合行为,而纹理的字节账几乎没有变化。
机制上还有一层好处。插值发生在 Iz、wa 与 d 这三个量上,三者都随位置平缓变化,线性过滤不会把它们推出各自的取值范围;非线性的那一步留到重建里去做,跨 texel 的混合就碰不到它。上一章那两张对照的差别,来源就在这里。
分量实图占下一页(讲义 slide 20)。页内给出一组四宫格:Iz、d、wa 三张分量图,配右下角合成后的照明结果。三个量里两个是标量、一个是编码方向,纹理又走块压缩(block compression),页内给的总账是每个 texel(纹理元素)平均只占 2.5 字节(讲义 slide 20 与备注)。2.5 字节这个量级说明为什么这条编码能在生产里跑:方向性信息被塞进了与一张普通贴图相当的预算里,烘焙与运行时的带宽都不用为它让路。对一个要在多种硬件上伸缩的管线来说,这个量级是它被采用的前提之一。
本章可核对的结论有三条。IrradZ 编码不再存环境色与方向色,改为存并插值标量辐照度 Iz、环境权重 wa 与八面体编码的高光方向 d,重建时用式 5-1 把 AHD 参数解回来并保持 Iz 不变(讲义 slide 19)。收益是修掉插值伪影、保证半球或顶点法线方向的取值精确、改善其周围法线的精度(讲义 slide 19 备注)。体积上的读数是块压缩后每个 texel 平均 2.5 字节(讲义 slide 20)。下一章回到编码本身:环境项要写成什么形状,才能让「环境加一盏方向光」也解得开。
6把环境项换成一盏半球光
上一章把 IrradZ 的存法交代完,重建时解回的仍是一组 AHD 参数,其中环境项的形状是一块常数色。本章问另一件事:如果运行时模型选定 AHD,光照该怎么编码进去。讲座从最简单的情形起手(讲义 slide 21)。这一章的推理是一条直线:先用直觉给出一套编码,再看直觉错在哪,最后由解出来的参数定下新模型。
最简单的情形是常数环境光。第一直觉是把环境色直接设成环境强度、方向色设成 0,以为这样就能得到一块常数色。页内紧接着指出,真实的辐照度不长这样(讲义 slide 21)。要弄清差在哪里,得先知道光被表面挡掉多少。
下一页给出这件事(讲义 slide 22)。法线越偏离半球法线,被表面挡掉的光越多。页内把这个现象叫半球遮挡(hemispherical occlusion),它让辐照度出现一条越靠边缘越暗的梯度。常数色接不住的就是这条梯度:把一个方向上的常量摊到整个半球上,边缘那一段亮度就没有着落。
对这个带梯度的辐照度求最合适的 AHD,结果写在下一页(讲义 slide 23):环境色取一半,方向色也取一半,高光方向取顶点法线。
把三个参数代回重建式,得到 I(n) = Ca·(1 + n·nv)/2。备注说,这正好是半球光的式子(讲义 slide 23 备注)。页内在这一页把这个结果与「一盏半球光的辐照度」画上等号。环境色与方向色各分到一半,是把那条边缘变暗的梯度表达成一个朝 nv 的方向项的直接结果:方向项负责按 n·nv 拉开明暗,环境项负责抬起底子。
把难度加一格,模型的边界就露出来了(讲义 slide 24)。这一次是常数环境叠一盏指向 +X 的方向光,辐照度写成 R(ω) = 1 + max(n·[1 0 0], 0)。在这个输入上 AHD 找不到精确解:页内在 IrradZ 约束下给出最优的 Ca = 0.1191、Cd = 2 − Ca、d = [0.3346, 0, 0.9424],并在同一页明写一句「No exact solution!」。备注把话说完,环境加一盏方向光的辐照度,AHD 模型根本没法精确表示(讲义 slide 24 备注)。
三个最优参数本身能读出这处失败的样子。Ca 只有 0.1191,方向色拿走 2 − Ca 的绝大部分;方向也从输入的 +X 被拉到 [0.3346, 0, 0.9424],朝半球法线一侧偏了一大截。参数在往「半球」那个形状上靠,说明 AHD 那两块拼板装不下这组输入。页内把最优解与一句 No exact solution! 摆在同一页,说明即便把参数调到最好,重建出来的辐照度在这组输入上仍合不拢(讲义 slide 24)。这就是全篇的动机:既然「环境加一盏方向光」是常见输入,模型就得换一个环境项的形状(讲义 slide 24 到 slide 25)。
讲座把重建里的环境项换成一盏半球光,得到 HHD(Hemisphere and Highlight Direction,半球与高光方向)。Ca、Cd、d 三个量仍然全部由 IrradZ 的 Iz、wa、d 推出,编码这一侧没有改动。
页内注明,式中的 nv 是顶点法线或半球法线(讲义 slide 25)。备注说,把环境项换成半球光之后,「常数环境 + 一盏方向光」的编码既平凡又精确(讲义 slide 25 备注)。这一句回头把上一页的失败解掉了:同一组输入换一种环境项形状就能精确表示,而三个参数的来源没有变,IrradZ 的存法也不用重做。
本章可核对的结论有四条。把常数环境光的辐照度按 AHD 编码时,第一直觉与真实辐照度不符,因为半球遮挡让辐照度带上越靠边缘越暗的梯度(讲义 slide 21 到 slide 22);对这个辐照度求最优 AHD 得到 Ca = 1/2、Cd = 1/2、d = nv,代回就是 I(n) = Ca·(1 + n·nv)/2,正好是一盏半球光(式 6-1、讲义 slide 23)。再叠一盏指向 +X 的方向光就不存在精确解,页内 IrradZ 约束下的最优解是 Ca = 0.1191、Cd = 2 − Ca、d = [0.3346, 0, 0.9424],并明写 No exact solution!(讲义 slide 24)。把环境项换成一盏半球光即得 HHD,三个参数仍从 Iz、wa、d 推出,重建为式 6-2,此时该编码既平凡又精确(式 6-2、讲义 slide 25 与备注)。下一章先看 HHD 两项的分量,再看这盏半球光顺手带来的自反弹,以及三个参数各自怎么解。
7自反弹,以及三个参数怎么解
上一章把重建式换成 HHD,环境项由一盏半球光承担,动机是「环境加一盏方向光」在 AHD 里没有精确解。本章先把两项拆开看一眼分量,再看半球光顺手带来的一项物理,最后把三个参数各自的解法写全。
先说分量(讲义 slide 26)。HHD 的重建由两项相加:半球项 (1 + nv·n)/2·Ca 与方向项 max(n·d, 0)·Cd。讲座把两项分开显示,并另附一张半球项的放大图,备注说放大后能看到表面遮挡带来的细微方向变化(讲义 slide 26 备注)。这张放大图说明换上去的那盏半球光自带一条与法线相关的坡度,它承担的不只是一块底色的作用。
再说自反弹(self-bounce)(讲义 slide 27)。台阶是这样的:可见半球那一侧的辐照度由一盏半球光给出,那么被挡住的另一侧应当是 1 减去它。页内据此写出半球挡掉的光量,并把反射出来的这一项近似成 IrradZ 乘材质反照率 α。
备注给了这项近似为什么划算:IrradZ 的值本来就在 lightmap 里,取用不需要额外的采样或存储,所以这是一处极便宜的修正,对高反照率材质差别很大;Enlighten 的辐射度系统在 2010 年代初用过同一个技巧(讲义 slide 27 备注)。页内配了两张结果,标着 WITHOUT SELF-BOUNCE 与 WITH SELF-BOUNCE,用来说明这条近似在画面上补回了什么(讲义 slide 27)。反照率 α 是逐材质的常数,这条修正只在有反照率数据的地方多出一次乘加。
有了模型,接下来是编码(讲义 slide 28)。烘焙时至少有半球上的辐射度以 SH 存下来,要找出它的辐照度作为 HHD 的最好逼近。误差取重建辐照度与 SH 辐照度之差。
式 7-2 的积分域是上半球 Ω+,与第 2 章那条在整个球面上最小化误差的写法不同,这一点下一章还要用到。页内同时给出烘焙存下来的二次 SH 辐射度与辐照度系数之间的逐带缩放关系,这一条留到下一章与 Iz 的两种取法一起写(式 8-1、讲义 slide 28 与 slide 29)。
把重建函数展开,会有三个待求量:半球法线上的辐照度 Iz、在半球光与方向光之间线性混合的环境权重 wa、以及高光方向 d。讲座给三者各配一条路线(讲义 slide 28 备注、slide 29)。
Iz 的路线有两条:烘焙时直接采样,或由辐照度 SH 重建。页内注明两条路各自的适用写法,一条是在半球上采样的切空间 SH,一条是用于曲面的世界空间 SH(讲义 slide 29)。具体式子见下一章式 8-1。
wa 是线性参数,用线性最小二乘解。
式 7-3 里各记号的分工要读清:a 与 d 分别是半球光与方向光的辐照度在 SH 里的向量,G 是 Gram 矩阵,i 是烘焙得到的辐照度 SH 系数向量,Iz 是标量辐照度。这里要把 Iz 与 i 分开,前者是一个标量(口径是 luminance 的辐照度),后者是一组 SH 系数,两者在后面的式子里各占一个位置,混用会把量纲带错。
d 是非线性参数,只能搜索。备注交代了为什么搜得动:辐照度低频,误差函数行为良好,于是可以在 θ(也就是 dz 这一维)上做黄金分割搜索,每一步算一次 wa 与误差(讲义 slide 29 备注)。为了再压一点误差,外面还套一层搜索 φ,对每个 φ 找出使误差最小的 θ(讲义 slide 29)。搜索的起点取「最优线性方向」,那个方向能不能直接用,下一章会单独交代。
页内另给出两条 SH 侧的构造,用来把两种基光的辐照度写进 SH:a = SHConvCosine([π, 0, 3π/2, 0]) 对应半球光的辐照度,d = SHConvCosine(π/dz · Y(d)) 对应方向光的辐照度(讲义 slide 29)。这两条构造把两种基光的辐照度直接写成 SH 系数;有了 a 与 d,式 7-3 的分子分母才都是 SH 域里的量。
本章可核对的结论有四条。半球挡掉的光量是 1 − (1 + nv·n)/2,反射的自反弹近似为 α·Iz·(1 − nv·n)/2,用到的量已经在 lightmap 里,所以代价极低、对高反照率材质差别大(式 7-1、讲义 slide 27)。误差函数取重建辐照度与 SH 辐照度之差,积分域是上半球 Ω+(式 7-2、讲义 slide 28)。三个参数走三条路,Iz 采样或由辐照度 SH 重建、wa 用线性最小二乘(式 7-3)、d 走搜索,θ 上黄金分割、外层再搜 φ(讲义 slide 29 与备注)。页内另把半球光与方向光的辐照度分别写成 SH 侧的构造 a 与 d(讲义 slide 29)。下一章把这张表里最容易写错的两处前提补上。
8两个容易被忽略的细节
上一章把三个参数的解法摊开,备注收尾提了一句还有两处细节。本章把这两处前提写完,它们一处决定误差在哪个定义域上最小化,一处决定高光方向能不能直接算出来。写之前先补上这套求解依赖的一条 SH 侧关系。
烘焙下来的是二次 SH 辐射度,记作 r;由它得到辐照度 SH 系数 i 要做一次逐带缩放,线性带乘 2/3、二次带乘 1/4。标量辐照度 Iz 的取法有两条:直接在烘焙里采样上半球上的余弦加权积分,或由上一步的辐照度 SH 用 Y(nv)·i 重建。
式 8-1 里两个记号的分别要再点一次:Iz 是标量辐照度(口径是 luminance),i 是辐照度 SH 的系数向量,式 8-1 的后半段给出的是两者之间的关系。这里的积分域同样是上半球 Ω+。逐带缩放里的 2/3 与 1/4,与第 2 章那条「线性带乘 2/3、二次带乘 1/4」是同一组因子(讲义 slide 12、slide 28 到 slide 29)。下面两处细节都建立在式 8-1 之上。
第一处细节是环境权重该配哪个 Gram 矩阵(讲义 slide 30)。页内把话说得很硬:算 wa 的时候必须用半球 Gram 矩阵。它的定义是把两个基函数的乘积在半球上积分;对 SH 来说,两个因子都取基函数向量 Y(ω)。页内随后列出二次 SH 的半球 Gram 矩阵,这九个元素在讲义里按列散排,行列位置未经人工核对,本章只引它的结构,不逐元素抄。
用错矩阵的代价可以算出来(讲义 slide 31)。页内并排两组结果:用球面 Gram 时,AHD 辐照度误差的 RMSE 是 0.0473464;换成半球 Gram 之后降到 0.0165971。同一页还给出参考辐照度、参考辐射度与两组 AHD 辐照度及各自的误差图,页脚标出环境图来自 polyhaven 的 autumn_field,许可是 CC0(讲义 slide 31)。备注给了一条直觉:只看天的话,地面是绿的也与你无关,环境色里不该带上它,要收进来的是天是蓝的这一件事(讲义 slide 30 备注)。把这条直觉翻成求解语言,就是误差只在看得见的那个半球上算。
第二处细节是高光方向能不能从 SH 直接拿(讲义 slide 32)。过去的做法叫「最优线性方向」,构造办法是把 SH 线性带的系数归一化并换位。
页内在这一页把问题直接抛出来:为什么不能这样用(讲义 slide 32)。
答案在下一页(讲义 slide 33)。把 HHD 投影进线性 SH,页内给出的线性带系数里,横两个分量都带 Cd 与 dy、dx 的乘积,而纵那一个分量混进了 Ca 的一份贡献。这就是「半球光污染了线性带」的具体形状:本该只表示方向光的那组系数里,混进了一个由常数半球项带来的量。顺着式 8-2 取最优线性方向,方向就被拉向半球法线。备注把后果列全:方向光侧倾不够,无法往返(round-trip),误差更高(讲义 slide 33 备注)。备注另补一句,更复杂的例子里高阶带里的能量也会影响高光方向(讲义 slide 33 备注)。搜索之所以必要,就出在这条污染上,θ 那一维的起点要避开被污染的方向。
本章可核对的结论有三条。辐照度 SH 与标量辐照度之间靠式 8-1 相连,i 由烘焙的二次 SH 辐射度逐带缩放得到(线性带 2/3、二次带 1/4),Iz 可由上半球 Ω+ 上的积分采样,或由 Y(nv)·i 重建(讲义 slide 28 到 slide 29)。第一处细节要求 wa 的最小二乘改用半球 Gram 矩阵,改用之后 AHD 辐照度误差的 RMSE 从 0.0473464 降到 0.0165971(讲义 slide 30 到 slide 31)。第二处细节说明「最优线性方向」不能直接用,HHD 投影进线性 SH 后 z 分量被半球光污染,方向被拉向半球法线、侧倾不够且无法往返(讲义 slide 32 到 slide 33)。下一章用几组并排读数把这两处改动合起来的收益钉下来。
9误差减半,但 HHD 不是处处都赢
上一章停在一个问句上:为什么不能直接拿「最优线性方向」当高光方向。答案是,把 HHD 投影进线性 SH 之后,线性带里的 z 分量被半球光污染,高光方向被拉向半球法线,方向光因此侧倾不够、无法往返,误差也更高。本章把这条定性判断换成几组能并排看的读数,再给出比「谁更准」更要紧的转换理由。
讲者先摆三张并排画面(讲义 slide 34 到 slide 36)。第一张用最优线性方向配球面 Gram 矩阵,他说这是很多游戏、也包括他们自己过去发货时的做法;第二张换成搜索到的方向配半球误差;第三张是二次 SH 的参考。他让听众盯住这几颗球的左边缘(讲义 slide 34 备注);换成搜索方向与半球误差之后,边缘被提亮,与参考更吻合(讲义 slide 35、36 备注)。
读数在下一页并排给出(讲义 slide 37)。最优线性方向配球面误差这一组,RGB 三个通道的 RMSE 是 3.795、4.874、5.159;搜索到的方向配半球误差这一组是 1.514、1.805、1.597。讲者的一句话总结是,改用搜索到的方向与半球 Gram 矩阵之后,重建误差降到了原来的一半以下(讲义 slide 37 备注)。
紧接着是那处把结论按住的内容(讲义 slide 38)。页内列出五个场景名:Vienna Garage、Hallstatt、Linz、Schoenbrunn、Wells,并把 AHD 与 HHD 的 RMSE 并排。AHD 一组五个值,0.0865、0.0866、0.0102、0.0241、0.0857;HHD 一组同样五个,0.0567、0.1003、0.0136、0.0205、0.0933。五列场景与五组读数一一对应,页内没有交代缺哪个场景。
讲者在这页的备注里把话说得很直:这套求解策略对 AHD 与 HHD 都适用,两者在不同环境下的质量差别其实相当小,甚至能构造出让任一方赢的场景(讲义 slide 38 备注)。于是真正的问题变成,换成 HHD 究竟值在哪。
答案是混合(讲义 slide 39)。CoD 的光照并不全是静态的,他们支持多组灯光数据在运行时动态混合,比如一盏灯的开与关,或者一扇门的开与关。这些动态更新与运行时采样是解耦的:多张 lightmap 先混合成一张,再在运行时采样。讲者点名同事 Peter-Pike Sloan 在 2020 年 Advances 上讲过这套系统的细节。
混合这件事上,HHD 有 AHD 比不了的优势(讲义 slide 40)。HHD 仍是非线性模型,直接拿混合后的参数去重建,结果与参考的混合光照差得很远;先投影到线性 SH 这类线性模型、在那边混合,之后再解回 HHD,吻合程度就高得多。
解回的过程在下一页(讲义 slide 41)。页内先指出可以从线性 SH 重建 HHD,自由参数个数相同;再给出把投影反过来的一组系数,由它解一个二次式拿到环境色,从方向色与高光方向里减出去,标量辐照度 Iz 可以直接从线性带取。讲者强调,对 AHD 在运行时做这件事太贵,而 HHD 本身就是一个合法的半球光照表述,所以只要有半球数据,就能从线性 SH 直接而廉价地解回 HHD,混合着色器因此保持轻量(讲义 slide 41 备注)。
效果在下一页(讲义 slide 42)。页内把 [Sloan and Silvennoinen 2020] 与本文方法并排,讲者说差别在陡峭法线上尤其明显:这套求解把能量从发散的方向项搬进半球项,高光方向因此能保持更掠射。他在这页的备注里同时重申,HHD 仍是非线性模型(讲义 slide 42 备注)。
本章可核对的结论有四条。这套求解对 AHD 与 HHD 都适用,两者质量差别相当小,页内 AHD 与 HHD 各给了五组读数,五列场景与五组读数一一对应(讲义 slide 38)。改用搜索方向与半球 Gram 矩阵之后,重建误差降到一半以下(讲义 slide 37)。换 HHD 的理由落在混合上,与重建精度无关:它能从线性 SH 直接而廉价地解回,AHD 在运行时做同样的解太贵(讲义 slide 39、41)。相对 [Sloan and Silvennoinen 2020],这套方法在陡峭法线上的差别尤其明显(讲义 slide 42)。
10把遮挡乘进去:半球乘法与 HLSH
上一章把 HHD 的理由落在混合上,而到此为止,讲者讲的只是烘焙光照的一半。他在讲义 slide 43 把话头转过来:动态物体,或者没有良好 lightmap 参数化的物体,光照来自光照探针,不经过 lightmap,探针上每个采样点的光照用球谐表示。另一半是球谐与遮挡,本章写这一段。
从 SH 重建辐照度是已知的做法,把各带按余弦卷积系数缩放之后重建即可(讲义 slide 44 备注)。麻烦出在法线贴图上。只按法线方向重建辐照度,会遇到与 AHD 同一个毛病:没有把半球遮挡算进去(讲义 slide 45 备注)。页内对照给出后果:漏光,以及被正确遮挡的 lightmap 表面与用 SH 探针的表面明显不一致;换成半球遮挡之后,法线贴图上大部分刺眼的漏光消失(讲义 slide 45、46)。
要施加半球遮挡,就必须在把辐射度转成辐照度之前,先把下半球乘掉(讲义 slide 47)。页内把它等价成乘上半球 Gram 矩阵,矩阵作用在切空间里。这里另有一笔代价:二次 SH 的旋转很贵,页内引 [Hable14] 给出 −57 次乘法/FMA 这个量级。讲者由此提出一个省法,能不能让二次 SH 的输入只输出线性 SH,系数少了,旋转也就能整个绕开(讲义 slide 47 备注)。
省法在下一页展开(讲义 slide 48)。他们把切空间那张半球乘法矩阵拆开:常数项由输入的 L0 带与切空间的带状 L1 系数算出,后者是线性带与一个重排过的法线向量做点积;线性带稍复杂,切空间的带状分量是半球法线方向上的缩放辐照度,非带状分量各自缩放,最后加上二次带投影过来的分量。讲义的说法是这些分量可以在一个有向标架里提取出来,于是得到一个高效的「二次到线性」半球乘法。页内另给出一组系数矩阵,本章只写用途,不逐元素抄。
于是实现分两档。低端平台在顶点着色器(vertex shader)里做(讲义 slide 49):先从 SH 网格采样,做半球乘法降到线性 SH,再解到亮度 HHD,把 Iz 与 Cdd(世界空间)传给像素着色器(pixel shader);像素里先按 Ca = Iz − max(Cdd · nv, 0) 求出环境项,再算 I(n) = Ca(1 + n · nv)/2 + max(Cdd · n, 0),其中 nv 是顶点法线。讲者说这么做的用意是降低照明成本,同时仍保留法线贴图带来的变化(讲义 slide 49 备注)。记号上,Cdd 是世界空间的带亮度方向色,Cd 是模型里的方向色,照讲义分开写。
高端平台在像素着色器里直接做(讲义 slide 50)。他们把线性 SH 改造成一套带 IrradZ 约束的版本,叫 HLSH:z 基函数的权重恒由 IrradZ 给出,基函数是 [z, 1 − z, x, y],重建写成一个线性式 I(n) = Iznz + Ca(1 − nz) + cxnx + cyny。页内还给出把二次 SH 投影到 HLSH 的系数矩阵;讲者说明,生成 HLSH 的这次乘法用的是前面优化过的半球乘法同源的二次 SH 分量,所以同一套技术可以在世界空间里做投影(讲义 slide 50 备注)。
三方对照在下一页(讲义 slide 51):左边是二次 SH 无遮挡,中间是二次 SH 的完整半球乘法,右边是 HLSH。讲者说明,因为保留了 IrradZ 约束,半球法线方向的取值在完整半球乘法与这个近似之间完全一致;近似丢掉了完整二次 SH 能有的一部分倾斜,其余部分吻合得相当近,振铃也没有那么重(讲义 slide 51 备注)。
讲义另在 ShaderToy 上给出一份实现(讲义 slide 52、53)。代码里多出一个 cosAlpha 参数,讲义说做半球时把它置零(讲义 slide 52 备注),这个参数是下一章锥形乘法的入口;代码只作演示出处,本章不逐行解释。
本章可核对的结论有四条。这一半的烘焙光照走光照探针,探针上的光照用 SH 表示(讲义 slide 43)。只按法线方向重建辐照度会漏光,因为没在把辐射度转成辐照度之前把下半球乘掉(讲义 slide 45、47)。低端路的落点是顶点着色器,把线性 SH 解成亮度 HHD 之后交给像素着色器重建;高端路的落点是像素着色器,在那里做 HLSH(讲义 slide 49、50)。三格里 HLSH 与完整半球乘法在半球法线方向完全一致,差别落在倾斜与振铃上(讲义 slide 51)。二次 SH 旋转的代价是 −57 次乘法/FMA 这个量级,页内引 [Hable14](讲义 slide 47)。
11AO 给的锥形可见性也能乘
上一章的半球乘法把法线贴图的漏光压了下去,遮挡这件事却不止半球。运行时给出的环境光遮蔽(ambient occlusion / AO)是一个可见性锥(visibility cone),页内把它的两个成分写成方向均匀加权、可见度按余弦加权 [JWPJ20](讲义 slide 54)。地平线以上的球形光源或锥,其辐照度(可见度)为 sin2(α)cos(θ) [Snyder96],锥角 α 由 cos(α) = (1 − visibility)/cos(θ) 给出。
讲者补了动机:AO 是间接光照里的另一个动态分量,它同时给出一个标量辐照度的遮挡因子与一个平均的未遮挡方向;一束辐射度锥与一盏球形光源等价,所以可以把余弦加权的可见度解析地换算成锥角。过去常用弯曲法线(bent normal)来代表这个方向,那是相当粗糙的近似;他提出把球面光照直接乘上这个可见性锥(讲义 slide 54 备注)。
做法是把半球的积分上限换掉(讲义 slide 55)。页内给出锥形 Gram 矩阵,把锥上的积分写成从 0 到 2π、再从 0 到锥角 α 的 Y(θ, φ)YT(θ, φ)sin(θ) 的积分;矩阵的对角元素是 cos(α) 的多项式,讲义特意注明它与半球乘法的分量相同,只是系数换成了 cos(α) 的多项式。讲者的说法更直接:半球乘法是在 θ 上积到 π/2,若假设可见性锥与半球法线同向,把积分上限换成锥角就得到锥形矩阵(讲义 slide 55 备注)。把矩阵换掉,半球乘法就成了锥形乘法。这张矩阵的行列对应讲义没有交代,本章按它的结构性质与用途写。
效果在讲义 slide 56。页内把 cos(α) 从 0 依次取到 0.875,并排 SH 锥形乘法与 HLSH 锥形乘法的画面。讲者说明,用 HLSH 做锥形乘法,画面与完整二次 SH 乘法相当接近;cos(α) 越大锥越窄,取 0 就是半球;乘法用的法线始终取锥心,锥心背离半球法线时这个近似会变差,但 HLSH 行为良好,误差在画面上并不刺眼;与只用标量辐照度做 AO 相比,它能带来相当明显的画面改善(讲义 slide 56 备注)。
四张成对对照把这件事落到底(讲义 slide 57 到 slide 62)。先摆无遮挡那张(讲义 slide 57);加上半球遮挡之后大部分漏光被清掉,但仍留两处不真实的辉光(讲义 slide 58 备注);只把辐照度按 AO 可见度缩放那张没有用,漏光仍旧从法线贴图里返回来(讲义 slide 59 备注);换成锥形遮挡之后就明显改善,光照与旁边被 lightmap 照明的墙看起来是一体的(讲义 slide 60 备注)。另一处场景的并排里,光照从左上打来,AO 缩放看起来主要就是角落变暗,锥形乘法则有更好的方向性(讲义 slide 61 备注)。
最后一张收尾对照里,讲者让人看显示器与箱子后方多出来的接地阴影,以及背板与墙面更细致的融合(讲义 slide 62 备注)。
本章可核对的结论有四条。AO 给的是一个可见性锥,它的方向均匀加权、可见度按余弦加权 [JWPJ20],地平线以上的球形光源或锥的辐照度(可见度)为 sin2(α)cos(θ) [Snyder96],锥角由 cos(α) = (1 − visibility)/cos(θ) 给出(讲义 slide 54)。把半球的积分上限换成锥角就得到锥形 Gram 矩阵,它的分量与半球乘法相同,系数是 cos(α) 的多项式(讲义 slide 55)。HLSH 锥形乘法与完整二次 SH 乘法的画面相当接近,锥心偏离半球法线时近似变差,但误差在画面上不刺眼(讲义 slide 56)。四张成对对照里,只按 AO 可见度缩放辐照度没有用,仍会从法线贴图漏回来,换成锥形遮挡后改善明显(讲义 slide 59、60)。
12结论与它没解决的问题
上一章末尾那张收尾对照(讲义 slide 62)是整篇最后一次画面交代。把它放在本章开头当作结论前的最后一眼,画面里该分辨的东西,上一章已经点过。
结论在讲义 slide 63,五条。第一条,半球遮挡很重要,你不希望法线贴图发光。第二条,线性基与最小二乘是有用的工具,这里的数学大部分只是线性代数与基础的多元微积分,自己试别的基函数、或者自己推导,都不难。第三条,如果你的函数定义在半球上,就在半球上算误差。第四条,能在线性空间里混合就在线性空间里混合,行为会好得多。第五条,如果你在用球谐,就用他们的 HLSH 锥形/半球乘法,这是提高画质的一条省事路径,代码都在 ShaderToy 上(讲义 slide 63 备注)。
这五条按他的排法有次序。第一条回答要不要做,第二条与第三条回答怎么做才不出错,第四条给出一条与模型无关的建议,第五条落到他们自己交付的那套工具上。他顺带说,这里大部分数学只是线性代数与基础的多元微积分,别人完全可以拿自己的基函数来试,或者自己推一套去替换第 5 章到第 8 章那条链(讲义 slide 63 备注)。这也是整篇的自我定位,它交付的是一条能从线性 SH 一路算到半球或锥形遮挡的数学路径。
同一页还贴了一张四列对照,NO OCCLUSION、HEMI OCCLUSION、CONE OCCLUSION、REFERENCE,两行分别是 AHD SPHERICAL ERROR 与 AHD HEMISPHERICAL ERROR。四列与两行之间的关系,讲义只用画面交代,行列对应没有给出文字说明,本章不代它下结论。
讲者在讲义 slide 64 收在提问页。讲义 slide 65 是约三十条参考文献,本章只把它作出处,不展开;与环境探针相关的那条在后面边界里另说。
本章可核对的结论是把五条摆平:半球遮挡很重要;线性基与最小二乘是有用的工具;函数定义在半球上就在半球上算误差;能在线性空间里混合就在线性空间里混合;用球谐的话就用他们的 HLSH 锥形/半球乘法,代码在 ShaderToy 上(讲义 slide 63)。讲者没有再给一份未来工作清单,他划下的几处限定与登记事项,按本章的口径收在下面八条里。
边界 1: 这套求解对 AHD 与 HHD 都适用,而两者的质量差别相当小(讲义 slide 38 备注)。页内五场景表的两组读数一一对应,已逐格核对。换 HHD 的理由落在混合行为上,与重建精度无关。
边界 2: HHD 仍是非线性模型(讲义 slide 42 备注)。它的优势是本身就是一个合法的半球光照表述,因此可以直接从线性 SH 廉价地解回 HHD(讲义 slide 41),不必在运行时做 AHD 那样的昂贵求解。
边界 3: HLSH 是近似(讲义 slide 51、56)。它用近似换到实时可用的成本;锥心偏离半球法线时误差会变大,只是行为良好、在画面上不刺眼。
边界 4: 页内矩阵的行列对应无法自动核对:讲义 slide 30 与 slide 55 的 Gram 矩阵、slide 50 的 HLSH 投影矩阵、slide 48 的二次到线性乘法矩阵、slide 41 的反向投影式,在 PDF 里都按列散排,能读出有哪些元素,读不出它们在矩阵里的位置。本章只引这些矩阵的结构性质与讲者结论,不逐元素抄;slide 38 的场景表已逐格核对(五列场景、两组读数一一对应)。
边界 5: 低端与高端走两条实现路(讲义 slide 48 到 slide 50)。低端在顶点着色器里做半球乘法再解到亮度 HHD,为的是降成本并仍保留法线贴图变化;高端在像素着色器里做 HLSH。两条路的带宽与精度画像不同,不可混谈。
边界 6: 页内唯一带 CC 的素材是环境图:讲义 slide 17 与 slide 31 的 autumn_field 来自 polyhaven,CC0;讲义 slide 38 的环境探针来自 dativ.at 的 lightprobes 页并标注 LIGHT PROBES © Bernhard Vogl。两者都是页内素材,不改变讲义整体的非 CC 口径。
边界 7: 讲义逐页印着保留所有权利的版权行(幻灯区内):© 2024 SIGGRAPH ADVANCES IN REAL-TIME RENDERING IN GAMES course. ALL RIGHTS RESERVED.,另有大量页标注 IMAGES © 2024 ACTIVISION PUBLISHING, INC.;残留风险高于同系列各篇,其中含未发货作品与内部管线画面。
边界 8: 本篇带一篇正式技术备忘录(讲义 slide 2 给出 Technical Memo ATVI-TR-24-01 与 research.activision.com,作者 Thomas Roughton、Peter-Pike Sloan、Ari Silvennoinen、Peter Shirley,© 2024 Activision Publishing, Inc.);正文的公式与读数都以讲义页内口径写,讲义未编号的式子按「讲义原文未编号」标注,不代为编号到论文式号上。
13贡献块
三条可搬走的做法与站内互读
一场讲「怎么让方向性 lightmap 混合时不炸掉、又让法线贴图不漏光」的讲座,能留下的东西集中在三处:把环境项换成一盏半球光、把误差放回它该在的那个域上算(并为此把方向改成搜索)、以及把遮挡写成一次矩阵乘法。三处都没有新数学,用的是线性代数与基础多元微积分加上一次「把定义域看清楚」的判断;本篇因此更适合当作一份在既有烘焙管线上做局部改写的工程记录来读 —— 讲者自己也把结论落在「大部分数学只是线性代数」这句话上。
贡献 1:把重建式里的环境项换成一盏半球光。 这一步的入口是一个看似平凡的问题:常数环境光该怎么编进 AHD?直觉的答案(环境色取环境强度、方向色取 0)与真实辐照度不符,因为半球遮挡让辐照度越靠边缘越暗;对这个辐照度求最合适的 AHD,解出来恰好是 Ca = 1/2、Cd = 1/2、d = nv,也就是一盏半球光(讲义 slide 23)。顺着这个发现把环境项整体换掉,得到的 HHD 让「常数环境 + 一盏方向光」的编码既平凡又精确(讲义 slide 25),而这本来在 AHD 下是没有精确解的(讲义 slide 24 页内明写 No exact solution!)。可搬走的是这条方法:当一个模型在某类输入上反复解不干净时,先去看它的基函数形状是不是与输入的结构不匹配,而不是继续加项去拟合。
贡献 2:把误差放回它该在的那个域上算,并为此把方向改成搜索。 SH 在球面上正交归一,所以球面 Gram 矩阵是单位矩阵,最小二乘编码退化成投影矩 —— 这套推导在第 2 章就铺好了,代价是它只在球面域上最小化误差(讲义 slide 9 备注原话)。而光照函数定义在半球上:因此算环境权重时必须换成半球 Gram 矩阵,否则就是把质量浪费在永远看不到的下半球(页内直觉:只看天的话,地面是绿的与你无关),RMSE 从 0.0473464 落到 0.0165971(讲义 slide 30–31)。与之配套的是高光方向不能再取解析的「最优线性方向」 —— 把 HHD 投影进线性 SH 后,线性带的 z 分量被半球光污染,方向被拉向半球法线、侧倾不够、无法往返(讲义 slide 33),所以改成在 θ 上做黄金分割搜索、外层再搜 φ(讲义 slide 29)。两条合起来把三组 RGB 重建误差从 3.795/4.874/5.159 压到 1.514/1.805/1.597(讲义 slide 37)。可搬走的是那句被讲者收进结论的话:如果你的函数定义在半球上,就在半球上算误差。
贡献 3:把遮挡写成一次矩阵乘法,然后换个积分上限复用它。 施加半球遮挡的正确位置是转成辐照度之前的 radiance(讲义 slide 47),而实现被做成一次矩阵乘法:高端平台在像素着色器里用 HLSH(把线性 SH 改造一套被 IrradZ 约束的基,z 基函数的权重恒由 IrradZ 给出)做闭式投影(讲义 slide 50),低端平台在顶点着色器里做半球乘法再解到亮度 HHD(讲义 slide 49)。真正省事的一步在后面:把半球的积分上限换成锥角就得到 Gα,而它的分量与半球乘法完全相同、只是系数变成 cos(α) 的多项式(讲义 slide 55)—— 于是运行时 AO 给的可见性锥可以复用同一套矩阵,而讲者特意对比了过去常用的弯曲法线是相当粗糙的近似(讲义 slide 54),并在对照里指出只把辐照度按 AO 可见度缩放没有用、仍会从法线贴图漏回来,换成锥形遮挡后改善明显(讲义 slide 59–62)。可搬走的是这条工程判断:当同一套数学在两个定义域上只差一个积分上限时,把它参数化,而不是写两遍。
站内可以接着读的几篇:篇目 11(DDGI)与篇目 34(Neural Light Grid)与本篇处理的是同一个问题的三条不同路线 —— 那两篇都围绕辐照度体积/探针场(一篇用可见性与八面体探针图集、一篇用学出来的权重函数),本篇走的是 lightmap 侧的方向性模型;三篇合起来正好是「辐照度怎么存、怎么查、怎么修」的一族,但各自的重建口径与误差度量都不同(本篇算的是半球域上的 RMSE),读数不可直接横比。篇目 22(CMU 延迟着色)给了前向/延迟两条管线的基本盘,可以用作「辐照度查表发生在管线哪个位置」的对照。篇目 37(HypeHype 的随机 tile 照明)与本篇同年、同一门课程,两篇都在回答「怎么在最弱的那档设备上把光照成本压住」:那篇的做法是换采样的单位(逐像素改逐 tile),本篇的做法是换模型的形状并让遮挡变成一次乘法,加上本篇明确写了低端与高端两条实现路(顶点着色器/像素着色器),两篇的移动端取向可以对读。本篇讲义未给代码仓库或开源链接;页内提到的 ShaderToy 演示(讲义 slide 40、52、53)是演示出处,不是许可;讲义 slide 1 提到的 The Baking Lab 是第三方开源仓库。
14原文出处块
原文出处与引用口径
出处:SIGGRAPH 2024 · Advances in Real-Time Rendering in Games course · 2024-08 · 讲者 Thomas Roughton(Activision Central Tech)· 官方讲义《Hemispherical Lighting Insights — From the Call of Duty Production Lessons》,66 页,1024×768 pt(4:3),来源 PDF 2024-siggraph-advances-hemispheres.pdf
底稿:本篇演讲基于 2024 年 5 月的 Activision 技术备忘录 Technical Memo ATVI-TR-24-01(讲义 slide 2 给出编号与 research.activision.com),作者 Thomas Roughton、Peter-Pike Sloan、Ari Silvennoinen、Peter Shirley(© 2024 Activision Publishing, Inc.)。讲义 slide 1 的致谢另列 Peter-Pike Sloan/Ari Silvennoinen/Peter Shirley 为论文合著者,以及 Activision Central Tech 与 Infinity Ward Poland 的同事、Naty Hoffman 的论文反馈与 Matt Pettineo 的 The Baking Lab
材料:官方讲义 66 页,其中 65 页带讲者备注(仅 slide 65 的参考文献页无备注);幻灯区有实时文本层(66/66 页的标题、图注、公式与逐页版权行都可选),本篇事实同时取自页内文字与讲者备注;页码为 PDF 页序(从 0 起),引用写作「讲义 slide N」。正文的 14 条式子由本站按讲义页内原式用 HTML 重排,按「讲义原文未编号」标注(讲义未给式号)
许可:讲义逐页在幻灯区内印着保留所有权利的版权行 —— © 2024 SIGGRAPH ADVANCES IN REAL-TIME RENDERING IN GAMES course. ALL RIGHTS RESERVED.,另有大量页标注 IMAGES © 2024 ACTIVISION PUBLISHING, INC.(如 slide 4/5/15/16/20/26/27/43/46/58–62),slide 15 起还出现 © 2018 ACTIVISION PUBLISHING, INC.(沿用 2018 年 IrradZ 的图);未检到任何 Creative Commons 声明。页内唯一带 CC 的素材是 slide 17 与 slide 31 的环境图 polyhaven.com/a/autumn_field(CC0),slide 38 的环境探针来自 dativ.at/lightprobes/ 并标注 LIGHT PROBES © Bernhard Vogl —— 两者都只是页内素材,不改变讲义整体的非 CC 口径。故 24 件图按分区非 CC 口径逐件署名(图号 + slide 号 + 出处 + 「未修改引用」),并在构建记录标注残留风险(讲义未授权转载,条款以官方发布为准),残留风险高于同系列各篇(逐页 © 明示 + 图像版权归 Activision,其中含未发货作品与内部管线画面)。不得写成 CC 或可自由转载。
引用口径:读数按页内原值写,不改写、不改位数 —— slide 20 的 2.5 字节/texel;slide 24 的 Ca = 0.1191、Cd = 2 − Ca、d = [0.3346, 0, 0.9424](页内明写 No exact solution!);slide 31 的 RMSE 0.0473464(球面 Gram)→ 0.0165971(半球 Gram);slide 37 的 RGB RMSE 3.795/4.874/5.159(最优线性方向 + 球面误差)→ 1.514/1.805/1.597(搜索方向 + 半球误差),备注说误差降到一半以下;slide 38 的五场景逐场景表(Vienna Garage、Hallstatt、Linz、Schoenbrunn、Wells 五列,各对应 AHD 与 HHD 两组读数,已逐格核对)。页内矩阵与表格的行列对应一律未经人工过图核对:slide 30 的二次 SH 半球 Gram 矩阵、slide 55 的锥形 Gram 矩阵、slide 50 的 HLSH 投影矩阵、slide 48 的二次到线性乘法矩阵、slide 41 的反向投影与解二次式的式子 —— 正文只写它们的结构与用途,不逐元素抄。讲者自陈的让步与限定一并保留:slide 16 明说球面高斯质量更好但为可伸缩性选了最简的 AHD;slide 38 承认AHD 与 HHD 的质量差别相当小、甚至能构造出让任一方赢的场景,所以换 HHD 的理由是混合;slide 42 承认 HHD 仍是非线性模型,其优势是本身为合法的半球光照表述、因而能从线性 SH 廉价解回;slide 51 与 56 承认 HLSH 是近似,锥心偏离半球法线时误差会变大(只是行为良好、画面上不刺眼);slide 49 说明低端平台走顶点着色器是为降低成本,同时仍保留法线贴图的变化。不与任何商用方案横比:页内所有对照(AHD vs HHD、【Sloan and Silvennoinen 2020】、无遮挡/半球/AO 缩放/锥形)都是同一套内部管线内的对照。篇幅说明:正文按 15,000–20,000 汉字写,事实全部来自幻灯区文本与讲者备注;讲义 slide 2 是论文前置页(TOPICS + 摘要 + Fig. 1/Fig. 2 图注 + CCS + 关键词 + 备忘录编号),本站只按「讲义 slide 2 的论文摘要」口径引用。