Games104学习笔记(5)
GAMES104:渲染中光和材质的数学魔法
第 5 讲|主题:Lighting、Materials and Shaders
视频时长:约 2 小时 08 分 36 秒
说明:本文按本地视频的课件和讲解脉络整理,不是逐字稿;时间点均为近似值。 这一讲我几乎是完全听不懂。
一句话理解
实时渲染的目标不是直接、完整地求解光在场景中的所有传播,而是在有限的帧时间内,围绕光照可见性、积分近似和递归光传输三类困难,组合使用 PBR、阴影贴图、预计算全局光照、光照/反射探针、IBL 与 Shader 管理,得到稳定、可控且足够可信的画面。
本讲学习目标
- 用渲染方程理解“光、材质、Shader”各自负责什么。
- 说明实时渲染为何难在可见性、积分与间接光,而不只是“算公式很复杂”。
- 理解 Blinn-Phong、Shadow Map、Lightmap、Light Probe、IBL 与 PBR 的使用边界。
- 掌握微表面 BRDF 的
D、F、G三项分别描述什么。 - 知道大世界阴影与复杂材质为什么会把问题延伸到级联阴影和 Shader 变体管理。
1. 渲染计算由谁参与
视频开头把渲染问题概括为三位参与者:
| 参与者 | 关注的问题 | 在引擎中的对应物 |
|---|---|---|
| Lighting(光照) | 光从哪里来、如何传播、是否被遮挡 | 光源、环境光、阴影、全局光照数据 |
| Material(材质) | 表面遇到光后如何吸收、散射、反射或透射 | 材质参数、纹理、BRDF/BSDF 模型 |
| Shader(着色器) | 如何在 GPU 上组织大规模并行计算 | Vertex/Pixel/Compute Shader、资源绑定与变体 |
一个有用的分工视角是:光照提供入射能量,材质规定响应规律,Shader 把这套规律变成可执行的 GPU 程序。
2. 渲染方程:所有近似的起点
课程以 Kajiya 的渲染方程为主线:
$L_o(x,\omega_o) = L_e(x,\omega_o) + \int f_r(x,\omega_o,\omega_i)\cdot L_i(x,\omega_i)\cos\theta_i,d\omega_i$
可以先按含义阅读,而不是急于推导:
L_o:从点x朝观察方向ω_o离开的辐亮度,也就是最终进入相机的光。L_e:该点自身发出的光,例如发光材质。L_i:从入射方向ω_i到达该点的光。f_r:BRDF,描述表面如何把入射光分配到出射方向。cosθ_i:斜入射的有效投影面积变小。- 积分:把半球上所有可能入射方向的贡献加总。
2.1 三个核心挑战
课件将实时求解拆成三个问题:
- 可见性:给定一个入射方向,如何知道该方向的光能否抵达当前点?
- 积分:半球积分涉及连续方向,怎样以可承受的代价估计它?
- 递归:
L_i本身又可能来自其他表面的反射、散射,渲染方程具有递归性。
这三个问题分别推动了不同技术的发展:阴影解决一部分可见性,采样/解析近似解决积分,预计算和实时 GI 技术处理多次弹射或其近似。
2.2 不要把“真实”误解为单一算法
真实感来自一组近似之间的一致性:直接光要有遮挡,材质要有合理能量分配,间接光要补足环境贡献,最终还要满足帧时间与显存预算。某个局部算法再精确,若与其余环节的假设不一致,画面仍会显得不可信。
3. 从简单光源到 Blinn-Phong
3.1 简单光源组合
在较传统的实时光照中,常把光拆为:
- 主光源:方向光、点光或聚光灯,负责较明确的方向性和高光。
- 环境光:补足低频、全方向的环境亮度。
- 附加局部光:只影响局部区域,用于丰富重点对象或室内照明。
这种拆法适合 GPU 的并行计算,但它隐含了一个重要前提:入射光分布被大幅简化了。
3.2 Blinn-Phong 的价值与局限
Blinn-Phong 通过环境光、漫反射和高光等项,提供了直观而廉价的外观控制。它在早期实时渲染里非常重要,但课程明确指出其限制:
- 不严格能量守恒:反射出的能量可能不受物理约束。
- 与光线追踪等方法衔接不稳定:当多个反射路径叠加时,误差和噪声更突出。
- 复杂真实材质难以统一表达:仅靠漫反射颜色与高光指数难以稳定描述金属、粗糙表面等。
因此,PBR 不是“让画面自动变好”的开关,而是用更一致的材质与光照假设,减少不同光照条件下的外观漂移。
4. 阴影:先回答“光能不能到”
4.1 Shadow Map 的基本思路
阴影贴图从光源视角先渲染场景深度。随后在主视角着色时,将当前表面点变换到光源空间,比较它到光源的深度与阴影贴图中记录的最近深度:
- 当前深度更大:点位于遮挡物之后,通常认为处于阴影中。
- 深度接近或更小:光可见,允许直接光照贡献。
它把“向光源发射光线”的可见性查询,转换成一次深度纹理查询,因此适合实时 GPU。
4.2 Shadow Map 的两个根本限制
课程特别强调:
- 分辨率受限于纹理:一张有限大小的 Shadow Map 必须覆盖一定范围,远近区域会发生采样密度失配。
- 深度精度也受限于纹理/投影:量化与深度比较会导致 acne、peter-panning 等伪影,需要 bias 等策略权衡。
阴影问题不是单纯“提高贴图分辨率”即可解决;覆盖范围、投影方式、过滤方式、稳定性和性能需要一起考虑。
4.3 廉价、鲁棒、易修改
在阴影之后,视频用“Cheap, Robust and Easy Modification”概括游戏渲染的工程目标。这里的意思不是忽视质量,而是:一个可量化、稳定、能被内容团队调参的近似,常比理论上更完整却难以落地的算法更适合引擎。
5. 预计算全局光照:把昂贵问题移到离线阶段
直接光只处理“光源到当前点”的一次可见性;而墙面、地面、天空等互相反射的能量属于间接光。实时计算它通常成本很高,于是课程转向 Pre-computed Global Illumination。
5.1 为什么要预计算
预计算的核心取舍:
- 在内容制作或烘焙阶段,用较长时间计算复杂光照。
- 运行时读取压缩后的结果,以很低成本近似间接光。
适用前提是场景中至少有一部分几何、材质或灯光保持稳定;若世界频繁变化,预计算结果会失效或需要额外补偿。
5.2 用球谐函数表示低频间接光
间接光本质上是“球面方向上的函数”。课程以 Fourier Transform 引出球谐函数(Spherical Harmonics, SH):它用一组球面基函数表示方向分布。
关键直觉:
- 复杂的高频光照分布需要更多系数。
- 漫反射会把入射光做余弦卷积,高频细节被显著平滑。
- 因此,对于漫反射间接光,低阶 SH 往往已经足够实用。
这也解释了为何 SH 很适合存环境漫反射,却不擅长保存锐利镜面反射或细碎遮挡。
5.3 卷积与运行时着色
若能把光照分布与材质响应分别编码,运行时就可以通过系数运算完成近似积分。课件给出“Store and Shading with SH”的思路:将少量 SH 系数编码进纹理或探针数据,运行时以简单的 RGB/RGBA 纹理读取完成漫反射着色。
要点不是记住某一种打包格式,而是理解:把高成本半球积分转成少量可查表、可点乘的数据,是实时渲染中常见的降维策略。
6. Lightmap 与 Light Probe:把间接光存在哪里
6.1 Lightmap
Lightmap 将静态几何上的光照结果烘焙到纹理中。使用时,网格需要一套用于烘焙的 UV 展开;多个物体的图块通常会被打包进 atlas。
| 优点 | 局限 |
|---|---|
| 运行时非常高效 | 烘焙时间长、内容迭代成本高 |
| 可保存丰富的静态场景 GI 细节 | 主要适用于静态场景与静态光 |
| 着色阶段只需采样纹理 | 占用包体与 GPU 存储,受 UV 与图块分配影响 |
视频还指出 Lightmap 可与短程、高频效果(如局部细节类补偿)配合,而非独自承担全部光照。
6.2 Light Probe
Light Probe 不把光照绑定到某块表面 UV,而是在空间中放置采样点,存储该位置的环境照明信息。动态物体可从附近探针插值,获得与静态环境较一致的漫反射和环境色。
它的优势是:
- 运行时高效。
- 能用于静态环境中的动态物体。
- 同时可承载漫反射与一定的镜面环境信息。
它的局限也很明确:探针需要预先布置或生成,难以表达极高频的 GI、精确硬阴影,且在复杂遮挡边界附近容易出现泄漏或过度平滑。
6.3 Reflection Probe
反射探针通常存储周围环境的立方体贴图或其预过滤版本,为具有一定粗糙度的镜面反射提供环境来源。可以把它理解为“从某个空间位置看到的环境”,而不是屏幕空间的即时反射。
7. PBR:用微表面统一描述材质
7.1 微表面 BRDF 的结构
课程采用微表面模型理解镜面反射。一个常见写法为:
$f_r = f_{\mathrm{diffuse}} + f_{\mathrm{specular}}$
其中镜面部分通常可概括为:
$f_{\mathrm{specular}} = \frac{D(h)F(v,h)G(l,v,h)}{4(n\cdot l)(n\cdot v)}$
不必执着于符号形式,先记住三个物理/几何含义:
| 项 | 名称 | 回答的问题 |
|---|---|---|
D |
Normal Distribution Function,法线分布函数 | 有多少微表面朝向半程向量,能把光反射到观察方向? |
F |
Fresnel,菲涅耳项 | 在这个视角下,有多少能量发生反射而非透射? |
G |
Geometric Attenuation,几何衰减/遮蔽项 | 微表面之间是否互相遮蔽或掩蔽? |
7.2 粗糙度真正控制什么
粗糙度不是“把高光调模糊”的纯美术参数。它改变微表面法线的分布:
- 粗糙度低:法线更集中,反射峰更尖锐。
- 粗糙度高:法线分布更分散,镜面能量在更大角域中展开。
因此,粗糙度会同时影响高光宽度、环境反射的模糊程度以及预过滤环境贴图应选择的 mip/层级。
7.3 菲涅耳效应
菲涅耳项说明:观察方向越接近掠射角,表面越倾向反射环境。水面、金属边缘、塑料边缘在斜看时更亮,并非单纯“加一圈边缘光”,而是反射比例随角度变化的自然结果。
7.4 Disney Principled BRDF 的工程价值
课程引用 Disney 的 Principled BRDF 思想:材质参数应优先做到直观、范围合理、边界稳定、组合后仍可信。
对引擎/工具设计的启发是:
- 参数不要只为公式服务,也要为内容创作者服务。
- 不同参数的有效范围应该有清晰约束,避免轻易产生不合理结果。
- 允许材质族覆盖多种外观,但不能把每种特殊材质都硬塞进同一套简单假设。
8. PBR 工作流:Specular-Glossiness 与 Metallic-Roughness
8.1 Specular-Glossiness
在 Specular-Glossiness 工作流中,通常分别保存:
- Diffuse/Base 颜色。
- Specular 反射颜色。
- Glossiness(与粗糙度方向相反的参数)。
它具有较直接的控制力,但参数之间的约束更依赖内容规则,容易产生不符合材料常识的组合。
8.2 Metallic-Roughness
Metallic-Roughness 工作流用金属度与粗糙度组织大多数常见材质:
- 非金属:以漫反射为主,镜面反射通常由介电材料的基础反射率控制。
- 金属:漫反射显著减弱,镜面反射颜色更多来自基色。
- 粗糙度:控制微表面分布及环境反射的预过滤程度。
它的价值在于减少不合理参数组合,使材质库、导入管线和运行时 Shader 更容易保持一致。
8.3 sRGB 与线性空间
课件在工作流图中区分了 sRGB 与 Linear。学习时应牢牢记住:
- 颜色贴图通常按 sRGB 编码/采样后转换到线性空间参与计算。
- 粗糙度、金属度、遮罩等“数值数据”通常应按线性值读取。
- 光照累积、BRDF 计算、混合等应在线性空间完成;最后再进行显示编码。
空间混用会使能量、渐变与材质响应看起来不对,即使公式本身没有写错。
9. IBL:让材质真正反射环境
9.1 IBL 的基本困难
Image-Based Lighting(IBL)把环境图作为来自各个方向的入射光。直接对环境图做半球积分需要大量采样,尤其镜面反射还随粗糙度和视角变化,不能在每个像素实时暴力计算。
9.2 把积分拆成可预计算部分
视频给出常见的拆分思路:
- Diffuse Irradiance Map:将环境图卷积为低频漫反射辐照度。
- Pre-filtered Environment Map:按照粗糙度预过滤环境图,为镜面反射提供不同模糊层级。
- BRDF LUT:预计算部分与视角、粗糙度相关的 BRDF 积分项。
运行时,材质只需根据法线、反射方向、粗糙度和视角,从这些预计算资源中采样并组合。其本质仍然是:用存储和预处理换取帧内时间。
9.3 IBL 与 PBR 是一对系统设计
PBR 给出表面如何响应入射光;IBL 给出环境入射光的近似。两者必须使用一致的颜色空间、粗糙度定义、预过滤规则和能量约束。只换一个 PBR Shader 而没有合理环境光,材质往往会显得灰、暗或像在真空中。
10. 大世界阴影:Cascade 与软阴影
10.1 Cascade Shadow Map
方向光需要覆盖很远的可见区域。一张 Shadow Map 同时覆盖近景与远景时,近景纹素密度不够,远景又浪费精度。级联阴影的解决方式是:
- 将相机视锥划分成多个深度区间。
- 为每个区间分别渲染 Shadow Map。
- 像素着色时,根据深度选择对应级联。
这样可以把更多分辨率分配给近处画面,符合人眼和屏幕空间的需求。
10.2 级联交界的处理
相邻级联的投影与分辨率并不完全一致,交界处容易出现突然变线、闪烁或亮度断层。课程展示了在重叠区域进行混合的思路:不要只依据“某一像素当前属于哪一层”硬切换,而应在过渡带平滑插值。
10.3 PCSS / VSSM 的位置
课件还讨论了软阴影近似,例如 PCSS(Percentage-Closer Soft Shadows)通过 blocker 与 receiver 的相对几何关系估计过滤半径;VSSM 等方法则将可见性近似转换为更易过滤的数据形式。
共同目标是让阴影边缘随遮挡关系呈现合理软化,而不是恒定宽度的硬边。代价通常是更多采样、过滤成本和稳定性处理。
11. 课程中归纳的 AAA 渲染组合
约 103 分钟处的总结页给出一种常见组合:
Lightmap + Light Probe
PBR + IBL
Cascade Shadow + VSSM
这不是唯一渲染架构,而是一组职责互补的工程拼图:
- 静态环境的高质量间接光交给 Lightmap。
- 动态对象的环境过渡交给 Light Probe。
- 物体外观统一到 PBR 材质模型。
- 环境反射和漫反射环境光由 IBL 补足。
- 主方向光的大范围遮挡由级联阴影处理,并以软阴影技术改善边缘。
理解“谁负责哪一部分”比死记每个缩写更重要。
12. 实时 GI、复杂材质与 Shader Management
12.1 GPU 能力增长带来的选择
视频后段提到 Compute Shader、Mesh Shader、Ray Tracing Shader 以及更现代的 GPU/图形 API。硬件演进扩大了可行算法的边界,例如屏幕空间 GI、基于距离场/体素的 GI、光追 GI 等。
但“可以实时”不等于“总该实时”。引擎仍要根据平台、场景动态程度、内容规模、帧预算和画面目标,在烘焙、探针、屏幕空间近似与更昂贵方法之间组合。
12.2 复杂材质不能被一个简单模型完全覆盖
课程用头发、皮肤等例子提醒:标准 PBR 对普通不透明表面很有效,但对各向异性头发、次表面散射皮肤等现象,需要 BSDF、BSSRDF 或额外的专用近似。正确做法不是否定统一材质模型,而是承认它有适用域,并为特殊材质保留扩展路径。
12.3 Uber Shader 与变体爆炸
Shader Management 是引擎中容易被低估的系统问题。一个通用的 Uber Shader 会依据:
- 光照类型与数量;
- 材质特性(法线贴图、金属度、透明、皮肤等);
- 渲染通道;
- 平台与质量等级;
- 预处理宏;
生成大量 Shader Variant。课件展示的真实游戏例子中,少量 Uber Shader 可扩展为数量极大的运行时着色器组合。
因此,引擎需要管理:变体裁剪、离线编译、缓存、按需加载、预热、回退路径和统计诊断。Shader 变体不是“美术参数多一点”的问题,而是构建时间、包体、内存、加载卡顿与渲染状态切换共同组成的系统成本。
13. 复习用速记
13.1 一条因果链
渲染方程难以直接实时求解
→ 可见性用 Shadow Map 等方法近似
→ 半球积分用解析、采样、SH、环境卷积等方式降维
→ 间接光用 Lightmap/Probe/IBL/实时 GI 分担
→ 材质用 PBR 保持光照变化下的一致性
→ 规模化实现依赖 Shader 变体与资源管理。
13.2 最容易混淆的三组概念
| 概念 | 主要存什么 | 主要服务谁 |
|---|---|---|
| Lightmap | 静态表面上的烘焙光照 | 静态几何 |
| Light Probe | 空间采样点的环境光照 | 动态物体、跨区域过渡 |
| Reflection Probe | 某位置周围的环境反射 | 镜面/粗糙镜面反射 |
| 概念 | 解决的主问题 |
|---|---|
| PBR | 表面如何合理响应光 |
| IBL | 环境从各方向提供多少入射光 |
| Shadow Map | 光源到表面是否被遮挡 |
| 微表面项 | 直觉 |
|---|---|
| D | 朝向恰好合适的微面有多少 |
| F | 当前角度反射比例有多高 |
| G | 微面之间有多少互相挡住 |
14. 自测题
- 渲染方程中
L_e、L_i、L_o分别表示什么? - 为什么课程把实时渲染困难归为可见性、积分和递归?
- Shadow Map 如何把可见性查询转换为纹理比较?
- Shadow Map 的分辨率问题和深度精度问题为何是两类不同问题?
- 为什么低阶 SH 适合表示漫反射环境光,却不擅长锐利镜面反射?
- Lightmap 与 Light Probe 分别适合哪些对象?
- 在微表面 BRDF 中,
D、F、G各自描述什么现象? - 粗糙度为何会影响预过滤环境贴图的采样层级?
- 为什么颜色贴图与粗糙度贴图不能以相同的色彩空间规则读取?
- IBL 中的 irradiance map、prefiltered environment map、BRDF LUT 如何分工?
- 级联阴影为什么比单张超大 Shadow Map 更适合方向光的大世界场景?
- 复杂材质为什么需要在统一 PBR 之外保留专用模型?
- 什么是 Shader Variant Explosion?它会影响哪些工程指标?
15. 术语表
| 术语 | 含义 |
|---|---|
| BRDF | 双向反射分布函数,描述不透明表面从入射方向到出射方向的反射分配 |
| BSDF | 更一般的散射函数,除反射外还可包含透射 |
| BSSRDF | 描述次表面散射等“光在表面下方传播后再离开”的现象 |
| PBR | 基于物理的渲染;强调材质和光照假设的一致性 |
| Shadow Map | 从光源视角存深度,并用深度比较判断遮挡的技术 |
| Lightmap | 绑定到静态几何 UV 的烘焙光照纹理 |
| Light Probe | 存储空间采样点环境光的结构,常用于动态物体 |
| Reflection Probe | 存储某位置周围环境反射信息的探针 |
| SH | 球谐函数;用于压缩和表示球面方向函数的基函数系统 |
| IBL | 基于图像的光照,将环境图作为入射光源 |
| NDF | 法线分布函数,微表面模型中的 D 项 |
| Fresnel | 描述反射率随观察/入射角变化的效应 |
| CSM | 级联阴影贴图,将视锥分段以提高近处阴影分辨率 |
| PCSS | 近似软阴影的一类方法,根据遮挡物与接收面关系调整过滤范围 |
| Uber Shader | 通过大量分支、宏或变体覆盖多种材质/光照条件的通用着色器 |
17. 参考资料
- B 站课程视频页(课程目录中可选择第 5 节):GAMES104:现代游戏引擎:从入门到实践
- GAMES104 课程主页:GAMES104
- 课程讲义与视频索引:GAMES104 Slides
- 进一步阅读:Matt Pharr、Wenzel Jakob、Greg Humphreys,《Physically Based Rendering: From Theory to Implementation》。