五分钟学会PBR材质精髓:BRDF计算全流程拆解
一、PBR 简介PBRPhysically Based Rendering基于物理的渲染是一种着色与渲染方法旨在通过模拟光与物质的真实物理交互来生成高度真实且在任何光照环境下都表现自然的图像。简单来说就是让材质在不同光线下都看起来“像真的”而不是只在特定角度下才好看。PBR 的核心思想传统渲染常用“取巧”的参数如漫反射颜色、高光强度等调整时很难直观预测结果。而 PBR 遵循两个基本物理原则1. 能量守恒反射的光能总量 ≤ 入射的光能总量。2. 微平面理论物体表面由无数微小平面组成每个小平面像镜子一样反光。PBR 的两种主要工作流工作流 workflow特点典型贴图金属/粗糙度(Metal/Roughness)最主流直观控制金属度和粗糙度基础色(Albedo)、金属度(Metallic)、粗糙度(Roughness)、法线、AO高光/光泽度(Specular/Glossiness)较早使用控制高光颜色漫反射(Diffuse)、高光(Specular)、光泽度(Glossiness)当前游戏与实时渲染普遍采用 金属/粗糙度 流程因为它参数更直观、纹理压缩更高效。二、PBR BRDF 计算本篇文章将围绕金属度的 workflow 来进行 PBR 的计算。首先介绍一下 PBR 的计算核心 BRDF双向反射分布函数BRDFBidirectional Reflectance Distribution Function:它决定了光线从某个方向入射后会向哪个方向反射多少能量。计算公式如下Diffuse部分这里的漫反射部分的计算中的 Albedo 是物体的本征颜色不是漫反射颜色即物体的反照率。Specular部分分母部分NdotL dot_c(normal, lightDir);NdotV dot_c(normal, viewDir);对于 D 项有各向同性 D 项各向异性 D 项其中1、NdotH dot_c(normal, halfDir);2、alpha: roughness * roughness3、alpha_x: tangent 方向上的粗糙度4、alpha_y: bitangent 方向上的粗糙度5、T: tangent 切线方向6、B: bitangent 副切线方向7、N: normal 法线方向8、H: halfDir 半角向量H normalize(viewDir lightDir)9、TdotH dot_c(tangent, halfDir);10、BdotH dot_c(bitangent, halfDir);11、pi ≈ 3.1415926对于 G 项有各项同性 G 项各项异性 G 项其中:1、NdotV dot_c(normal, viewDir);2、NdotL dot_c(normal, lightDir);3、x NdotL 或 Ndot V4、alpha roughness * roughness5、alpha_x tangent 方向上的粗糙度6、alpha_y bitangent 方向上的粗糙度7、omega viewDir 或 lightDir8、TdotO dot_c(tangent, omega);9、BdotO dot_c(bitangent, omega);10、NdotO dot_c(normal, omega);对于 F 项其中1、F0 是 0° 入射角即垂直入射时的菲涅尔反射率2、VdotH dot_c(viewDir, halfDir)直接光照 Direct直接光照用于计算平行光、点光源、聚光灯等光源的贡献。其中1、BRDF: 双向反射分布函数值 BRDF Diffuse Specular2、LightColor: 光照颜色3、NdotL dot_c(normal, lightDir);4、Shadow 是在光照状态下的阴影数值 [0, 1]0 表示未遮挡IBL 间接光照IBLImage-Based Lighting基于图像的光照是一种在计算机图形学中模拟间接光照环境光带来的漫反射和镜面反射的技术。不再用虚拟的点光源或方向光而是用一张 360° 的全景环境贴图通常是 HDR 格式来代表整个场景的光照信息。其中1、或2、Albedo 物体反照率3、kD (1 - kS) * (1 - Metallic)4、kS F0 (max(float3(1-roughness, 1-roughness, 1-roughness), F0) - F0) * pow(1 - NdotV, 5.0);5、AO: 环境光遮蔽项对于 Irradiance 项Irradiance来自整个半球所有入射方向的光照积分结果通常由球谐函数SH近似计算。关于球谐函数更详细的内容可以参考球谐函数SH其中1、ci: SH系数2、Yi: 球谐基函数常用球谐基函数dir (x, y, z) 是三维方向向量对于一张 cubeMap 可以通过若干次采样来计算出 SH 系数其离散采样公式为其中1、Li: 是 ci 的近似用有限的采样次数来近似 SH 系数2、N 是采样总次数3、f(dir) 是 CubeMap 在 dir 方向上的采样结果是一个颜色4、Yi(dir) 是球谐基函数在 dir 方向上的值5、dir 采样方向可以通过如下逻辑进行采样float goldenAngle PI * (3.0 - sqrt(5.0)); for (int si ZERO; si sampleCount; si) { // 从球体 y 1.0 开始采样一直到 y -1.0 float y 1.0 - (i / sampleCount) * 2.0; // 在 Y y 平面处对球体进行切割切面圆的半径 radius float radius sqrt(1.0 - y * y); // 计算本次采样的水平旋转角 float theta goldenAngle * i; // 本次采样的 x、y 坐标 float x cos(theta) * radius; float z sin(theta) * radius; // 本次采样的方向向量 float3 dir normalize(float3(x, y, z)); }最终可以得到从 L00 ~ L22 一共 9 个 SH 系数然后可以通过这些球谐函数系数来对环境光照进行重建重建方法就是公式中的 Irradiance。一般记录一个4x4矩阵 M 来对其进行重建由于每个 L 是一个计算出来的 float3 类型的数则对于每个 L 的 r 通道可以构建出来一个 M.r同理有M.g、M.b分别对应 r、g、b 通道重建时镜面 IBL关于预过滤贴图的计算方法我会在另一篇文章中给出如果更新我会放在这里镜面IBL计算采样预过滤环境贴图:PrefilterMap SAMPLE_TEXTURE2D_LOD(PrefilteredEnvMap, sampler, uv, mip);其中1、PrefilteredEnvMap: 预过滤环境贴图通过 GGX 分布采样取平均后得到的。2、sampler: 二维贴图采样器3、uv 是由视线的反射方向向量转化成的R reflect(-v, n) 三维向量转uv4、mip 是由 roughness 计算出来的 minmap 等级BRDF LUT关于LUT的计算方法我会在另一篇文章中给出如果更新我会放在这里BRDF LUT 计算BRDF_LUT SAMPLE_TEXTURE2D_LOD(LUT, sampler, float2(NdotV, Roughness), 0);BRDFLUTBRDF_LUT.x * F BRDF_LUT.yF F0(1-F0)(1-VdotH)^5其中1、LUT: BRDF 镜面预积分2、PrefilterMap: 镜面 IBL 采样出来的颜色3、AO: 环境光遮蔽项最终合成Tome MappingGamma 校正