一、Clearcoat 清漆(C7-01)
做了什么
渲染一个刷了清漆的柳条球(ClearcoatWicker)。核心是两层反射模型:物体表面有一层薄而透明的膜,光先打这层膜(反射成白色窄高光),剩下的穿过膜打到下层的色漆层。
车漆是最典型的例子,实际上木器、上釉陶瓷、光面塑料、覆膜印刷品都是这种"表面两层结构"。
知识点
- 三个参数:
clearcoatFactor(清漆强度)、clearcoatRoughness(清漆层粗糙度)、clearcoatNormal(清漆法线贴图)。 - 清漆 F0 用折射率算 :
F0 = pow((ior-1)/(ior+1), 2),默认 ior=1.5 算出约 0.04。C6 里写死的非金属 0.04,这里终于看到它的物理来源。 - 清漆高光复用 C6 的
getIBLRadianceGGX,只是换成清漆自己的法线 / 粗糙度 / F0------清漆本质就是"一套更窄的 GGX 高光"。 - 最关键的合成行 :
color = color*(1 - clearcoatFactor*clearcoatFresnel) + clearCoatContrib。清漆反射掉多少,下层就扣多少;factor=0 时1-0=1,退回普通 PBR。
实践是改 gltf 里的 factor 和 roughness:factor 从 1 改成 0,高光消失退回普通 PBR;roughness 调大,高光变宽。
二、Sheen 布料光泽(C7-02)
做了什么
渲染一把丝绒椅子(SheenChair),表现天鹅绒、绒布那种边缘一圈柔和亮边。布料表面有一层竖立的细绒毛,光在绒毛之间散射,斜角看过去绒毛侧面把光反射进眼睛,形成亮边。
知识点
- D_Charlie 分布函数,核心是 sin :
pow(sin²θ, ...)。对比 GGX 核心在 cos(H≈N、正面亮),Charlie 核心在 sin(H 贴着表面、掠射角亮)。cos 正面亮、sin 边缘亮,这就是全部区别,一下就记住了。 - IBL 查 Charlie 环境表 ------就是 C6-03 预过滤生成的第三张表(prefilter/irradiance/charlie);BRDF LUT 用的是 .b 通道(GGX 用 .r/.g)。
- 两个参数:
sheenColorFactor(光泽颜色,会染色 )、sheenRoughnessFactor(光泽粗糙度)。 - 高光直接加在最终颜色顶层。
- 和清漆对比:清漆是白色、锐利、正面 的高光;布料是彩色、柔和、边缘的高光。
三、Transmission 透射(C7-03)
做了什么
这章是 C7 里最复杂、也最有收获的一章,表现光真的穿过整个物体(玻璃、透明瓶子)。核心技巧是屏幕空间透射,分两 pass 渲染:
- Pass 1:先把整个场景(不透明物体)渲染到一张离屏纹理;
- 把屏幕拷贝到离屏纹理、生成 mip;
- Pass 2:加载已有画面,画玻璃时把离屏纹理当输入,采样它就拿到"玻璃背后已经画好的场景"。
知识点
- 这是真实引擎(UE/Unity)做屏幕空间折射的标准做法:先画背后,再让透明物体采样。
- 折射方向用内置函数
refract(-v, n, 1.0/ior)------按斯涅尔定律算,eta=1/ior。 - thickness 厚度:折射方向 × 厚度,决定光在物体内部走多远、从背面哪里出来。这就是"透过玻璃看东西是弯的"。
- 重投影:把 3D 折射出射点用 viewProj 投影、透视除法、NDC 转 UV、y 翻转,得到背后是屏幕上的哪个像素。
- 磨砂玻璃 = mip 采样:roughness 越大,采样的 mip 越高(越糊),看到的背后越模糊。
- 合成用
mix(diffuseColor, transmission, transmissionFactor)------透射光替换漫反射(光穿过去,就不漫反射了)。 - 反射看环境图(光弹走),折射看屏幕图(光穿过去、先渲染)。
四、Volume 体积(C7-04)
做了什么
C7-03 解决了光穿过、折射,这章解决光在物体内部走的时候发生了什么------被吸收、染色。渲染一条龙(DragonAttenuation),表现琥珀、有色玻璃、水这类介质。
知识点
- Beer-Lambert 定律 :
T(d) = exp(-σd),光走得越远,剩下的越少(指数衰减)。 - σ 怎么来的:已知"走 attenuationDistance 后透过率 = attenuationColor",两边取 log 反推:
σ = -log(attenuationColor)/attenuationDistance。 - 三个通道独立衰减,所以介质会呈现"衰减最慢的那个颜色"。蓝光先掉、红光最后,介质就是黄色。
- 三个参数:
thicknessFactor(光走多远,可贴图)、attenuationColor(走 attenuationDistance 后剩的颜色)、attenuationDistance(衰减距离,越小衰减越快)。 - Volume 不能单独用,必须配合 Transmission------Transmission 负责穿过、折射,Volume 负责内部吸收、染色。
五、IOR 折射率(C7-05)
做了什么
渲染琥珀里的蚊子(MosquitoInAmber)。这章是概念整合章,把折射率单独拎出来讲------IOR 一个数同时管两件事:反射多少、折射弯折多少。
知识点
- 反射量:
F0 = ((ior-1)/(ior+1))²;折射弯折:refract(..., 1/ior)。两件事是同一物理现象的两面,都由 ior 决定。 - 常见值:空气 1.0、水 1.33、玻璃 1.5、琥珀 1.55、钻石 2.42。
- ior 对应的 F0:水 2%、玻璃 4%、琥珀 4.65%、钻石 17.2%。
- 钻石为什么那么闪:ior 高 → F0 高(反射强)+ 弯折大(光在内部乱弹)。
- ior=1.0 时,光不弯折、F0=0,物体在光学上等于空气、看不见。
- ior 在代码里有四个用途:基础 F0、折射方向、磨砂折射散开、清漆 F0。
六、Specular 镜面强度(C7-06)
做了什么
渲染一个丝绸坐垫(SpecularSilkPouf)。普通 PBR 里非金属 F0 被 ior 锁死成 0.04,没法自由调,这个扩展让美术独立控制镜面高光的强度和颜色。
知识点
- 两个参数:
specularFactor(高光强度,对应specularWeight)、specularColorFactor(高光颜色,可超 1 走 HDR)。 specularWeight贯穿所有镜面和漫反射函数:镜面直接乘它,漫反射是(1 - specularWeight × F)。调小高光,漫反射相应变亮,总能量不变。- 与 IOR 的区别:IOR 是"物理地"调(连折射弯折一起变),Specular 是"美术地"调(只动高光、不碰折射)。
- 模型同时用了 sheen 和 specular:丝绸 = 边缘柔亮(sheen)+ 彩色高光(specular)。
七、EmissiveStrength 自发光强度(C7-07)
做了什么
渲染一组发光强度对比的物体(EmissiveStrengthTest)。普通 emissive 颜色最大 1,1,1,只是"普通亮度",但灯、屏幕、太阳应该非常亮------这个扩展给自发光一个倍数,让它进 HDR。
知识点
- 发光链:
emissiveTexture × emissiveFactor × emissiveStrength。 - 倍数在 CPU 端加载材质时就预乘进 emissiveFactor,shader 完全不用改。
- 颜色超过 1 表示"比白光还亮":色调映射时被压到接近白色,bloom 后处理提取超过阈值的亮像素做模糊,形成辉光。超过 1 的亮度就是 bloom 的来源。
- 自发光不依赖环境,直接加在最终颜色里。
八、AnalyticalLight 解析光源(C7-08)
做了什么
渲染一盏台灯(LightsPunctualLamp,五个不同颜色 / 强度的点光)。这章补上正式的场景光源,把前面每章里"直接光"的部分闭环。
知识点
- 三种解析光源:
- 方向光 Directional:太阳,平行光、只有方向、不随距离衰减;
- 点光 Point:灯泡,向四面八方、按 1/d² 衰减;
- 聚光灯 Spot:手电,锥形光、距离衰减 + 锥形衰减。
- 距离衰减:无限 range 用 1/d²,有限 range 用
(1-(d/range)⁴)/d²平滑衰减到 0。 - 聚光灯锥形:外锥之外 0、内锥之内 1、中间 smoothstep 过渡(由 innerConeCos/outerConeCos 定义)。
- 直接光流程:遍历每个光源 → 按类型算方向(方向光用 -direction、点光用 position-worldPos)→ 算强度(距离 × 锥形衰减)→ 累加漫反射和镜面。
- IBL 查纹理、解析光算数学:环境光四面八方、便宜、做填充;直接光位置明确、实时算、做主光。
回头看的几点
- 能量守恒贯穿全章 :每个扩展都在解决"光该分给谁"------上层反射多少、下层就扣多少(
1-x、mix、specularWeight),总能量不变。 - 两个材质家族:玻璃家族(Transmission + IOR + Volume,负责穿过、弯折、吸收,模型往往三合一);布料家族(Sheen + Specular,负责边缘光和彩色高光)。
- 反射 vs 折射:反射看环境图(光弹走),折射看屏幕图(光穿过去、先渲染场景);方向光是正面亮(cos),布料是边缘亮(sin)。
- 贵的预计算、便宜的查表:IBL 用 C6 生成的表(LUT、prefilter、Charlie),直接光实时算 F・G・D。
- 扩展的套路是固定的:PBRInfo 加字段 → 写采样 / 公式函数 → 在最终合成里按能量守恒加进去。看懂第一个,后面都是同一个模式。
八章走下来,从"标准 PBR 只能渲金属 / 非金属"到"车漆、布料、玻璃、琥珀、发光体、场景灯光"都能表达,PBR 材质这块的地图算是完整了。