Chapter 28: BRDF and Material Systems
本章讨论一个直接出现在每帧里的问题:当同一个 mesh、同一盏灯、同一个相机姿态保持固定时,材质参数如何决定像素颜色、反射方向分布和引擎中的资源组织。读完本章后,读者应能追踪一个 fragment 从法线、视线、入射光、材质纹理到最终颜色的路径,并能判断材质外观差异来自 BRDF 模型、参数贴图、颜色空间、shader variant 还是资产管线转换。
贯穿材料是一组放在同一场景里的四个球体:哑光白墙、粗糙塑料、拉丝感较弱的金属、带 clearcoat 的涂层表面。四个球体使用同一套几何、同一张 HDR 环境贴图、同一盏方向光和同一个 fragment shader;改变的只有材质对象里的 baseColor、roughness、metallic、normal、emissive、clearcoat 以及对应纹理槽。这个材料矩阵能把 BRDF 的数学意义、shader 中的输入输出、GPU 资源绑定和资产格式差异放在同一条可观察路径上。
BRDF 在实时渲染里承担的角色是“给定光从哪里来、眼睛从哪里看、表面朝向哪里,表面把多少光送到相机方向”。材质系统承担的角色是“把艺术资产中的参数、纹理、开关和平台约束整理成 shader 可读取的数据”。二者连接起来之后,PBR 材质才具备可迁移的判断方式:先判断表面模型,再检查参数含义,再检查纹理编码,再检查 shader 评估路径,最后用图像结果和工具捕获验证。
这一章只建立 BRDF 与材质系统的主干关系。微表面项、Fresnel 项、IBL 预积分和复杂分层材质会在后续章节继续展开;当前章节的目标是让读者先把“材质参数为什么会变成某种高光、漫反射和资源结构”讲清楚。
28.1 BRDF 基础理论与物理意义
BRDF(Bidirectional Reflectance Distribution Function,双向反射分布函数)描述同一个表面点上入射方向与出射方向之间的反射关系。它的输入通常写成入射方向 、出射方向 和表面法线 ;在 shader 里,这三个量分别对应 light vector、view vector 和 normal。BRDF 输出的量用来缩放入射辐射亮度,使 fragment shader 得到朝相机方向离开表面的反射亮度。
最小的直接光照路径可以写成 $L_o = L_i \cdot f_r(\omega_i, \omega_o) \cdot \max(0, n \cdot \omega_i) \cdot V$。这里 是光源到达表面的入射亮度, 是 BRDF, 是入射方向在表面上的投影, 是可见性或阴影项。这个公式对应到贯穿材料时,四个球体共享 、几何法线和阴影项,外观差异主要来自 以及它读取的材质参数。
BRDF 的第一个约束是能量守恒。对于一个没有自发光的表面,离开表面的反射能量应受入射能量限制。实时渲染通常不会在每个 fragment 上做完整半球积分,而是在模型设计和参数范围上维持这个约束。例如 Lambert 漫反射把漫反射项写成 albedo / pi,使漫反射在半球上的积分保持在可控范围内;Cook-Torrance 类模型把法线分布、遮蔽项和 Fresnel 项组合起来,使高光随粗糙度变化时仍能保持可解释的能量分配。
BRDF 的第二个约束是 reciprocity(互易性)。在常见静态、被动、不带磁光效应的表面模型里,交换入射方向与出射方向后,反射关系保持一致。这个性质对离线路径追踪和实时 IBL 都有意义,因为它允许渲染系统把视线方向与光线方向放入同一套反射模型中分析。材质系统中一旦出现依赖方向的特殊效果,例如各向异性、高度依赖屏幕空间的假反射或艺术化 rim light,就应明确这些效果属于附加项,和基础 BRDF 的物理约束分层处理。
BRDF 的第三个核心量是 reflectance(反射率)。反射率表示入射能量中有多少比例被反射出去。在实时材质里,反射率经常被拆成几组可编辑参数:非金属的漫反射颜色、法线入射时的镜面反射 、粗糙度控制的高光扩散程度,以及金属材质中带颜色的镜面反射。贯穿材料中的粗糙塑料球具有有色漫反射和弱镜面反射;金属球的颜色主要进入镜面反射,漫反射贡献接近零;白墙球体则由接近 Lambert 的宽漫反射主导。
下面的简化 shader 片段只展示 BRDF 输入如何进入一次直接光评估。代码省略 IBL、阴影采样和多灯循环,目的在于固定数据路径。
struct MaterialSample {
vec3 baseColor;
float roughness;
float metallic;
vec3 normalWS;
vec3 emissive;
};
vec3 evaluateDirectLight(
MaterialSample material,
vec3 lightRadiance,
vec3 lightDirWS,
vec3 viewDirWS
) {
vec3 N = normalize(material.normalWS);
vec3 L = normalize(lightDirWS);
vec3 V = normalize(viewDirWS);
float NoL = max(dot(N, L), 0.0);
float NoV = max(dot(N, V), 0.0);
vec3 diffuse = evaluateDiffuseBRDF(material.baseColor, material.metallic);
vec3 specular = evaluateSpecularBRDF(material.baseColor, material.roughness, material.metallic, N, L, V, NoV);
return material.emissive + lightRadiance * (diffuse + specular) * NoL;
}
这段代码给出一个排查顺序。画面偏暗时,先看 NoL、light radiance 和颜色空间;高光形状异常时,检查 roughness、normal map 和 specular BRDF;金属颜色错误时,检查 metallic 是否改变了 baseColor 的解释;自发光溢出时,检查 emissive 是否绕过了 BRDF 能量约束。BRDF 解释表面如何反射外部光,自发光描述表面自己向外输出光,二者在 shader 中应保持清晰分层。
BRDF 也有明确边界。它把光看作在同一个表面点进入并离开,所以它适合描述不透明表面的漫反射和镜面反射。皮肤、蜡、玉石等材料中光会进入表面内部并在邻近位置射出,这类现象需要次表面散射模型补充。透明玻璃、水和薄膜还涉及透射、折射和体积吸收,它们会使用 BSDF、BTDF 或更完整的材质模型。当前章节只把不透明实时 PBR 表面的反射路径讲清楚。
把这些约束放回贯穿材料,可以得到第一条稳定判断:同一盏灯下,哑光白墙的亮度变化主要来自 和漫反射 albedo;塑料表面的高光亮度主要来自低值 与 roughness;金属表面的颜色进入镜面项;clearcoat 表面在基础 BRDF 外叠加一个更光滑的上层反射。材质系统需要把这些差异编码成数据,shader 需要按一致模型解释这些数据。
28.2 常见 BRDF 模型对比(Lambert / Cook-Torrance 等)
比较 BRDF 模型时,应使用同一组维度:输入参数、反射分布、视觉结果、计算成本和资产管线含义。只看模型名称会掩盖真正的工程差异。Lambert、Cook-Torrance、GGX 和 Disney BRDF 分别代表从单一漫反射、微表面镜面、高光尾部分布到艺术参数化的一组常见选择。
Lambert 漫反射假设表面把入射光均匀散射到所有出射方向。它的典型形式是 $f_d = albedo / pi$,只依赖漫反射颜色,不依赖视线方向。因此白墙球体在相机移动时不会出现随视角移动的高光,亮度主要跟法线和光线夹角变化。Lambert 的优势是稳定、便宜、易于和 albedo 贴图对应;它的边界是无法表达光滑塑料、金属、清漆和强视角依赖反射。
Cook-Torrance 模型把镜面反射解释为大量微小镜面片共同作用的结果。实时 PBR 中常见形式可写成 $f_s = D \cdot G \cdot F / (4 \cdot NoL \cdot NoV)$。 描述微表面法线分布, 描述遮蔽和阴影, 描述 Fresnel 反射随视角变化。这个结构把高光宽度、掠射角反射增强和粗糙表面的能量分布放入可拆解的模型中。贯穿材料中的粗糙塑料与金属球,都可以使用同一套 Cook-Torrance 镜面框架,只是输入的 、metallic 和 roughness 不同。
GGX 通常指微表面模型中的一种法线分布选择。它相比一些较早的分布具有更长的高光尾部,因此在粗糙金属、磨砂塑料和环境反射中更接近许多真实材质的视觉结果。工程上,GGX 的意义并不止于一个公式;它会影响直接光高光、IBL 预滤波、BRDF LUT 和 roughness 映射。如果直接光用 GGX,而环境反射预滤波使用另一种分布,同一个 roughness 数值会在局部灯光和环境反射中呈现不同的高光宽度。
Disney BRDF 更偏向材质作者使用的参数化体系。它把 base color、roughness、metallic、specular、sheen、clearcoat、anisotropic 等参数组织成更接近制作工具的编辑模型。它的价值在于把多个反射 lobes 组合成可调的材质语言,例如涂层表面可以在基础层外增加 clearcoat 高光,布料可以通过 sheen 改善掠射角边缘表现。引擎采用 Disney 风格参数时,应把每个参数对应到实际 shader 项,防止材质编辑器中的滑块和运行时 BRDF 语义脱节。
| 模型 | 主要输入 | 视觉结果 | 工程边界 |
|---|---|---|---|
| Lambert | albedo、normal、light direction | 宽而均匀的漫反射 | 适合哑光不透明表面,缺少视角相关高光 |
| Cook-Torrance | roughness、F0、normal、light/view direction | 可控镜面高光与 Fresnel 变化 | 需要一致的 D/G/F 组合和能量处理 |
| GGX microfacet | roughness、microfacet normal distribution | 粗糙表面保留较长高光尾部 | IBL 预滤波和直接光评估要使用一致假设 |
| Disney style BRDF | baseColor、metallic、roughness、clearcoat、sheen 等 | 更接近 DCC 工具的材质编辑体验 | 参数多,variant 与贴图槽管理成本更高 |
BRDF 模型差异会直接变成资源路径差异。Lambert 只需要较少参数和纹理,通常读取 base color 与 normal 即可;Cook-Torrance 需要 roughness、metallic 或 specular、normal、可能还需要 precomputed BRDF LUT;Disney 风格材质会带来 clearcoat、sheen、anisotropy 等额外纹理槽或 uniform。模型越丰富,材质系统越需要清楚区分默认值、纹理缺省、feature toggle 和 shader variant key。
下面的流程图把一次材质评估拆成模型选择、参数读取和反射评估三个阶段。它用于说明模型名称、贴图数据和最终颜色之间的因果路径。
图中的 Fragment 输入 包含插值后的 UV、世界空间位置、切线空间基向量和基础 varyings。采样材质参数 决定 base color、roughness、metallic、normal、emissive 等值。建立 N L V 把贴图法线转入世界空间,并构造 light direction 与 view direction。最终颜色来自多个反射项的组合。排查材质问题时,应沿着这条路径定位:先确认输入空间,再确认参数值,再确认模型分支,最后确认输出颜色和 tone mapping 前的 HDR 数值。
四个球体的观察结果可以把模型差异固定下来。白墙球体的亮度随光照方向平滑变化,说明 Lambert 主导。粗糙塑料在正面能看到弱而宽的高光,说明 diffuse 与 dielectric specular 同时存在。金属球缺少明显漫反射,环境颜色和光源颜色通过镜面项染上金属色。clearcoat 球体在基础粗糙高光之外还有一层更窄、更亮的上层高光,说明材质由多个 lobe 叠加生成。
这一节得到的判断顺序是:先问材质是否需要视角相关反射,再问镜面项是否需要物理约束,再问 roughness 是否要和 IBL 预滤波一致,再问材质编辑器参数能否稳定映射到 shader。这样比较模型时,读者看到的不是名称列表,而是一条从参数到画面再到资源成本的链路。
28.3 材质系统数据结构设计
材质系统的核心任务是把可编辑资产变成 GPU 可消费的数据。资产侧关心命名、纹理槽、默认值、DCC 兼容和美术工作流;运行时侧关心内存布局、descriptor 或 bind group、shader variant、纹理采样状态和批处理排序。一个合格的材质系统需要在这两侧之间建立稳定映射。
以贯穿材料中的四个球体为例,CPU 侧可以把材质描述为一个 asset object,GPU 侧则把它压缩成 constant buffer、texture index 和 feature flags。baseColor、roughness、metallic 属于基础 BRDF 输入;normal 改变表面法线方向;emissive 直接加入输出;clearcoat 触发额外 lobe。材质系统要保证这些字段在编辑器、导入器、序列化文件、GPU buffer 和 shader 中含义一致。
struct MaterialGPU {
vec4 baseColorFactor;
vec4 emissiveFactor;
float roughnessFactor;
float metallicFactor;
float normalScale;
float clearcoatFactor;
uint baseColorTexture;
uint normalTexture;
uint metallicRoughnessTexture;
uint emissiveTexture;
uint clearcoatTexture;
uint flags;
};
这个结构体现了三类数据。第一类是 factor,用于没有纹理时提供默认值,也用于和纹理相乘。第二类是 texture index,用于从纹理数组、descriptor array 或 bindless table 中找到实际纹理。第三类是 flags,用于说明材质启用了哪些路径,例如 normal map、emissive、alpha test、clearcoat 或 double sided。字段的顺序和对齐要服从目标 API 的 uniform buffer 或 storage buffer 规则,跨 Vulkan、Metal、Direct3D、WebGPU 时要通过显式 layout 或生成代码保持一致。
材质贴图的颜色空间会直接影响 BRDF 输入。base color 与 emissive 通常以 sRGB 形式存储,进入 shader 后要转为线性空间参与光照计算;normal、roughness、metallic、occlusion 等数据贴图应按线性数据读取。若 roughness 被错误当作 sRGB 解码,低值区域会被改变,高光宽度会明显失真。若 base color 被当作线性数据直接使用,整体反射颜色会偏暗或偏亮,后续 tone mapping 很难修正这种输入错误。
材质系统还要管理通道打包。常见 PBR 管线会把 occlusion、roughness、metallic 打包到同一张纹理的 R、G、B 通道,减少 texture fetch 和绑定数量。打包策略要写进资产规范和导入器,shader 中的读取也要固定。例如 glTF 2.0 的 metallic-roughness 模型使用 pbrMetallicRoughness,其官方规范定义了 baseColorFactor、metallicFactor、roughnessFactor、baseColorTexture 和 metallicRoughnessTexture 等字段;实现者还需要按规范处理 base color 的 sRGB 编码、normal texture 的线性数据和缺省采样值。可回溯资料可见 Khronos glTF 2.0 Specification。
贴图槽设计要同时覆盖当前 shader 和后续 pass。材质资产往往跨多个 pass 使用:G-buffer pass 需要 base color、normal、roughness、metallic;shadow pass 可能只需要 alpha cutoff;depth pre-pass 可能只读取 opacity;lighting pass 可能读取 G-buffer 后重新评估 BRDF;forward transparent pass 又会直接采样材质纹理。材质系统应按 pass 明确哪些字段会被读取,减少无效绑定和无意义 variant。
shader variant 是材质系统的另一个边界。把所有 feature 都写进一个 shader 并用动态分支控制,能减少编译数量,但会增加运行时分支和寄存器压力。为每个材质组合生成专用 shader,能减少无效代码路径,但会造成 variant 数量膨胀和 pipeline cache 压力。工程上常用的折中是把影响 pipeline state 或大量代码路径的特性放入 variant key,例如 alpha mode、normal map、clearcoat、skinning、deferred/forward;把只是数值变化的参数留在 uniform 或 texture 中。
下面的 JSON 片段展示一个接近 glTF metallic-roughness 的材质描述。它说明资产格式如何把参数和纹理槽交给运行时材质系统。
{
"name": "RoughGold",
"pbrMetallicRoughness": {
"baseColorFactor": [1.0, 0.766, 0.336, 1.0],
"metallicFactor": 1.0,
"roughnessFactor": 0.35,
"baseColorTexture": { "index": 0 },
"metallicRoughnessTexture": { "index": 1 }
},
"normalTexture": { "index": 2, "scale": 1.0 },
"emissiveFactor": [0.0, 0.0, 0.0]
}
这段数据进入引擎后,导入器应完成四件事。第一,记录 factor 和 texture slot,并为缺失纹理写入规范默认值。第二,标记 base color 的 sRGB 采样和 metallic-roughness 的线性采样。第三,把 normal texture 关联到 mesh 的 tangent space,缺少 tangent 时执行导入阶段生成或运行时 fallback。第四,生成 material key,使 renderer 能选择正确 shader variant 和 descriptor layout。
材质调试也要围绕数据结构展开。若金属球显示成灰色,先查看 metallicFactor 与 metallic channel 是否为 1,再查看 baseColor 是否在金属路径中进入 F0。若粗糙塑料的高光过窄,先查看 roughness factor 和贴图通道,再查看采样颜色空间。若 normal map 造成接缝,先查看 tangent space 约定和 mesh tangent,再查看 normal texture 是否使用线性读取。工具上,RenderDoc 或平台 GPU 调试器可以检查 draw call 绑定的 texture、buffer、shader variant 和采样器状态;工具输出回答的是“当前 draw call 实际读到了什么”,正文中的 BRDF 模型回答的是“这些数据被如何解释”。
本节的关键结论是:材质系统不是贴图列表。它是资产语义、GPU 资源、shader 变体、pass 需求和调试证据之间的映射层。BRDF 决定参数如何进入颜色计算,材质系统决定这些参数是否能稳定、低成本、跨平台地到达 shader。
28.4 Metal/Roughness 与 Specular/Glossiness 管线差异
Metal/Roughness 与 Specular/Glossiness 是两种常见 PBR 参数化管线。它们可以驱动相近的 BRDF,但暴露给资产作者和引擎的数据含义不同。比较这两种管线时,应关注 base color、diffuse、specular、F0、roughness、glossiness、贴图通道和引擎 fallback,而非只比较哪一种“更真实”。
Metal/Roughness 管线使用 baseColor、metallic 和 roughness 作为核心参数。对于非金属,baseColor 表示漫反射颜色,镜面法线入射反射率通常使用约 0.04 的默认值。对于金属,baseColor 表示带颜色的镜面反射,漫反射贡献趋近于零。roughness 控制微表面法线分布,数值越低,高光越集中;数值越高,高光越宽,环境反射越模糊。
Specular/Glossiness 管线使用 diffuse、specular 和 glossiness 作为核心参数。diffuse 表示漫反射颜色,specular 直接表示 F0 的 RGB 值,glossiness 表示表面平滑程度。常见关系是 glossiness = 1 - roughness,一些实现还会把微表面粗糙度写成 alpha = (1 - glossiness) * (1 - glossiness)。这种管线给非金属的彩色镜面和特殊材料更多自由度,但也要求资产、shader 和校验工具更严格地处理能量分配。
| 维度 | Metal/Roughness | Specular/Glossiness |
|---|---|---|
| 核心参数 | baseColor、metallic、roughness | diffuse、specular、glossiness |
| 非金属 F0 | 通常由引擎给出默认低反射值 | 由 specular 直接给出 RGB 值 |
| 金属颜色 | baseColor 进入镜面反射 | specular 表示有色 F0,diffuse 通常接近黑色 |
| 粗糙度表达 | roughness 越大,高光越宽 | glossiness 越大,高光越窄 |
| 资产兼容 | glTF 2.0 base material 默认采用该模型 | glTF 旧扩展 KHR_materials_pbrSpecularGlossiness 支持该模型,扩展已归档并被新扩展体系取代 |
| 运行时成本 | 参数少,移动端和 Web 更易统一 | 表达范围更宽,贴图和校验成本更高 |
Metal/Roughness 的优势是参数少、默认值稳定、跨工具传播成本低。对大多数游戏、Web 预览和实时引擎来说,它能用较少贴图表达塑料、金属、木材、墙面和简单涂层。它的主要边界是非金属 F0 自由度较低,当材质需要彩色镜面、特殊涂层或复杂多层反射时,需要扩展参数或额外 lobe。
Specular/Glossiness 的优势是直接控制 F0。它适合已有 specular/glossiness 资产库、电影管线中的某些材质迁移、以及需要更自由镜面颜色的特殊表面。它的成本来自数据校验和转换。若 diffuse 与 specular 同时给出高能量,材质可能超过合理反射范围;若 glossiness 与 roughness 的映射和 IBL 预滤波假设不一致,直接光与环境反射会出现高光宽度不统一的问题。Khronos 的旧 glTF 扩展文档对 diffuseFactor、specularFactor、glossinessFactor、specularGlossinessTexture 和转换关系有明确描述,可见 KHR_materials_pbrSpecularGlossiness。
资产转换时,关键问题是信息自由度。Metal/Roughness 通过一个 metallic 标量在非金属和金属之间混合,Specular/Glossiness 直接给出 RGB F0。把 Specular/Glossiness 转为 Metal/Roughness 时,引擎通常要从 diffuse 与 specular 推断 metalness,并把 glossiness 映射到 roughness。这个过程会把部分彩色镜面、非标准 F0 和混合材料压缩到较少参数里。把 Metal/Roughness 转为 Specular/Glossiness 相对直接,但仍要明确金属区域的 diffuse 处理和 roughness 到 glossiness 的映射。
引擎内部应选择一个 canonical material representation(规范内部材质表示)。一种常见策略是运行时统一使用 Metal/Roughness,把导入的 Specular/Glossiness 在资产构建阶段转换,并保存转换报告;另一种策略是在内部保留更通用的 diffuseColor、specularF0、roughness、metallicHint,由不同 shader path 选择使用。前一种策略有利于 Web、移动端和 glTF 资产流;后一种策略有利于高端材质和离线资产迁移。选择依据是目标平台、已有资产库、材质编辑需求、IBL 管线和 shader variant 预算。
用贯穿材料复盘这两种管线,可以得到可观察判断。粗糙塑料在 Metal/Roughness 中表现为 metallic = 0、有色 baseColor、较高 roughness;在 Specular/Glossiness 中表现为有色 diffuse、低值灰色 specular、中低 glossiness。金属球在 Metal/Roughness 中表现为 metallic = 1、有色 baseColor;在 Specular/Glossiness 中表现为黑色或低值 diffuse、有色 specular、由 glossiness 控制高光宽度。若两个管线渲染同一材质时只有漫反射接近,高光颜色或高光宽度差异明显,排查重点应放在 F0、roughness/glossiness 映射、IBL 预滤波和纹理颜色空间上。
最终检查顺序可以固定为五步。先确认资产声明的是 Metal/Roughness 还是 Specular/Glossiness。再确认每张贴图的通道含义和颜色空间。然后确认 F0 如何从参数得到,金属区域和非金属区域是否走了正确解释。接着确认 roughness 或 glossiness 是否和直接光、IBL、BRDF LUT 使用同一映射。最后用调试视图输出 baseColor、metallic、roughness、F0、normal 和 final specular,观察问题来自数据输入还是 BRDF 评估。
最小自检任务
给定一个场景:同一个球体 mesh 使用同一盏白色方向光和同一张 HDR 环境贴图。材质 A 的参数为 baseColor = [0.8, 0.1, 0.05]、metallic = 0.0、roughness = 0.75。材质 B 的参数为 baseColor = [1.0, 0.77, 0.34]、metallic = 1.0、roughness = 0.25。材质 C 来自 Specular/Glossiness 资产,参数为 diffuse = [0.0, 0.0, 0.0]、specular = [1.0, 0.77, 0.34]、glossiness = 0.75。请判断三者分别对应什么材质倾向,并给出排查材质 B 与 C 高光宽度不一致的顺序。
答案要点
材质 A 是粗糙非金属表面。metallic = 0.0 使 baseColor 进入漫反射颜色,roughness = 0.75 使镜面高光较宽且强度较低。观察时应看到有色漫反射主导,视角相关高光存在但不尖锐。
材质 B 是较光滑的金色金属表面。metallic = 1.0 使 baseColor 进入有色镜面反射,漫反射贡献趋近于零,roughness = 0.25 产生较集中高光和较清晰环境反射。
材质 C 在 Specular/Glossiness 管线下也表达金色金属。diffuse 接近黑色,specular 直接给出金色 F0,glossiness = 0.75 通常映射到 roughness = 0.25,并可能进一步映射到微表面 alpha。它和材质 B 的目标外观接近。
若材质 B 与 C 高光宽度不一致,先确认 C 的 glossiness 是否按 roughness = 1 - glossiness 转换。再确认微表面 alpha 是否在两条路径中使用相同平方映射。然后检查直接光 BRDF 与 IBL 预滤波是否使用同一 roughness 定义。接着检查 specular/glossiness texture 的 A 通道是否被按线性数据读取。最后输出调试视图,分别查看 roughness、F0、normal 和 specular term,判断差异来自转换数据还是 BRDF 评估路径。
本章知识点总结
- BRDF 定义:BRDF 描述同一表面点上入射方向、出射方向和法线之间的反射关系,并把入射光转换为朝相机方向的反射亮度。
- 能量守恒:实时 PBR 通过模型设计、参数范围和贴图校验约束反射能量,使没有自发光的表面受入射能量限制。
- 互易性:常见静态被动表面满足入射方向和出射方向交换后的反射一致性,路径追踪和 IBL 都依赖这一类稳定假设。
- Lambert 漫反射:Lambert 模型用
albedo / pi表达均匀散射,适合哑光不透明表面。 - 微表面镜面:Cook-Torrance 类模型把镜面反射拆成法线分布、遮蔽项和 Fresnel 项,从而控制高光形状与视角变化。
- GGX 分布:GGX 会产生较长高光尾部,直接光、IBL 预滤波和 BRDF LUT 应使用一致 roughness 假设。
- Disney 参数化:Disney 风格 BRDF 把多个反射 lobe 组织成材质作者可编辑的参数,但会增加贴图槽和 shader variant 成本。
- 材质系统:材质系统负责把资产参数、纹理槽、默认值、GPU buffer、descriptor 和 shader variant 连接成稳定运行时路径。
- 颜色空间:base color 与 emissive 通常按 sRGB 存储并在线性空间参与光照,roughness、metallic、normal 和 occlusion 应按线性数据读取。
- 通道打包:把 occlusion、roughness、metallic 放入同一纹理能减少采样和绑定成本,但导入器、资产规范和 shader 读取必须保持一致。
- Variant 边界:影响大量代码路径或 pipeline state 的材质特性适合进入 variant key,纯数值变化适合留在 uniform 或 texture 中。
- Metal/Roughness:Metal/Roughness 用
baseColor、metallic和roughness表达主流 PBR 材质,参数少且跨平台传播成本低。 - Specular/Glossiness:Specular/Glossiness 用
diffuse、specular和glossiness直接控制 F0 和光滑度,表达更自由但校验成本更高。 - 转换检查:两种管线互转时应检查 F0、金属区域、roughness/glossiness 映射、IBL 预滤波和纹理颜色空间。
- 调试顺序:材质问题应按输入空间、参数值、纹理编码、模型分支、BRDF 输出和工具捕获证据逐步定位。