ShaderLab: PBR + IBL
本篇文章实现了 PBR 材质的计算和渲染。
shaderlab 代码参考:PBR
最终效果预览:

其中包含4个文件:SH.shader、PrefilterEnvMap&LUT.shader、PBR BRDF.shader、PBRRunner.cs
实现细节
这次实现 PBR 材质时,我没有直接依赖 Unity 内置的 Lit Shader 或 Reflection Probe,而是把整个流程拆成了几块:直接光照的 Cook-Torrance BRDF、漫反射环境光的球谐函数、镜面反射环境光的预过滤贴图,以及运行时负责生成和绑定这些纹理的 C# 脚本。这样做的好处是每一步都更透明,也能更清楚地理解 PBR 里“物理正确”到底来自哪里。
整个实现主要由四个文件组成:
1、SH.shader负责生成球谐系数;
2、PrefilterEnvMap&LUT.shader 负责生成预过滤环境图和 BRDF LUT;
3、PBR BRDF.shader负责最终材质渲染;
4、PBRRunner.cs 负责把这些离屏计算串起来。
第一步是实现直接光照。主 Shader 中使用了标准的 Cook-Torrance 微表面模型:法线分布函数使用 GGX,几何遮蔽项使用 Smith GGX,菲涅尔项使用 Schlick 近似。材质参数上,albedo 决定基础颜色,metallic 控制非金属和金属之间的过渡,roughness 控制高光扩散程度。F0 的计算也遵循常见做法:非金属默认约为 0.04,金属则逐渐过渡到自身的 albedo。最终直接光由漫反射项和镜面项相加,再乘以主光颜色、NdotL 和 URP 主光阴影衰减。
第二步是处理漫反射环境光。漫反射由于经过 Lambert 卷积后变化比较平滑,非常适合用低阶球谐函数表示。SH.shader 中对环境 Cubemap 做球面采样,使用黄金角分布生成较均匀的方向,然后累加 9 个二阶球谐基函数系数。计算完后,再把 RGB 三个通道分别转换成 4x4 矩阵,存进一张 4x4 的 ARGBFloat RenderTexture。运行时只需要用法线构造 float4(normal, 1),分别和 RGB 三个矩阵做二次型计算,就能快速得到该法线方向上的 diffuse irradiance。
第三步是处理镜面环境光。镜面 IBL 比漫反射更复杂,因为它和粗糙度强相关。粗糙度越低,反射越接近清晰镜面;粗糙度越高,反射越模糊。所以 PrefilterEnvMap&LUT.shader 使用 Hammersley 序列和 GGX importance sampling,对环境图进行不同 roughness 下的预过滤。结果没有存在真正的 Cubemap mip 链里,而是打包进一张 2D 贴图:下半部分保存环境贴图和不同粗糙度层级,越靠右 tile 越小,分别对应更高 roughness。
同一个 Shader 还生成 BRDF LUT。BRDF LUT 是 split-sum approximation 的另一半,它把与视角 NdotV 和 roughness 相关的积分预先算好,存在贴图上半部分左侧区域。运行时镜面 IBL 只需要两步:先根据反射方向采样预过滤环境图,再用 NdotV 和 roughness 采样 BRDF LUT,最后组合为 prefilteredColor * (F0 * brdf.x + brdf.y)。这样就避免了每个像素都做大量 Monte Carlo 积分。
第四步是把这些数据接入最终 PBR Shader。PBR BRDF.shader 中最终颜色由三部分组成:主光直接光照、SH 提供的漫反射 IBL、预过滤贴图和 BRDF LUT 提供的镜面 IBL。为了让结果显示更接近常规屏幕输出,最后还做了简单的 Reinhard tone mapping 和 gamma correction。
第五步 PBRRunner.cs 负责运行时调度。它创建 SH 用的 4x4 RenderTexture,以及预过滤环境图用的可配置分辨率 RenderTexture,格式都是 ARGBFloat,保证 HDR 数据不会被普通颜色格式截断。生成时通过 Graphics.Blit 分别调用 SH Shader 和 Prefilter Shader,并用 read/write 双缓冲交换结果。它还会检测 Cubemap、分辨率、采样数是否变化,避免每帧重复计算;需要时也可以通过 regenerateEveryFrame 强制刷新。
这套实现的核心思路可以概括为:运行时材质 Shader 只做必要的 BRDF 组合,把昂贵的环境积分提前烘焙到纹理中。漫反射部分用 SH 压缩低频光照,镜面部分用 GGX importance sampling 生成预过滤环境图,再用 BRDF LUT 补上视角相关项。最终,一个完整的 PBR 材质就由“直接光 + 漫反射 IBL + 镜面 IBL”拼合出来。
目前这个实现已经覆盖了 PBR 的主体结构,但也留有继续扩展的空间,例如加入法线贴图、AO 贴图、多光源支持、更完整的曝光控制,或者把预过滤结果改成真正的 Cubemap mip 链。即便如此,这个版本已经很好地展示了 PBR 材质背后的关键流程:不是简单调几个参数,而是把光照模型、材质能量守恒和环境光积分组织成一条可运行的渲染管线。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)