在完成高光反射的 GGX 预过滤后,我们还需要处理环境光的漫反射部分。本阶段(Stage 3)将基于 Lambert 分布对环境贴图进行无权重预过滤,生成用于漫反射计算的环境数据。与高光反射的方向性不同,漫反射是光线在粗糙表面的均匀散射,因此需要用更适合均匀分布的 Lambert 模型进行预过滤。
核心目标
漫反射的核心特性是 “光线在表面向所有方向均匀散射”,其强度仅与光线入射角(与法线的夹角)相关。本阶段的目标是:
- 基于 Lambert 分布生成均匀的半球采样方向;
- 对环境贴图进行 “无权重平均”(所有方向贡献均等),得到漫反射环境光的预过滤结果;
- 将结果存储在环境图集的指定区域,与之前的高光数据形成完整的 PBR 环境数据集合。
准备工作
- 前置条件:已完成 Stage 1(基础环境图集)和 Stage 2(GGX 高光预过滤),获得包含多级数据的
envAtlas
; - 输入资源:
sourceCube
(原始立方体贴图)、envAtlas
(待写入漫反射数据的图集); - 工具依赖:Three.js 环境(
renderer
、scene
、camera
)、SampleGenerator
(已实现 Lambert 样本生成); - 理论基础:了解 Lambert 漫反射模型(
diffuse = (albedo / π) * irradiance
),其中irradiance
是环境光在半球上的平均强度(本阶段预计算的核心)。
Lambert 漫反射与无权重预过滤
Lambert 模型描述了理想漫反射表面的反射规律:光线入射后向所有方向均匀散射,反射强度仅与光线与法线的夹角余弦(n·l
)成正比。对于环境光的漫反射计算,需要预计算辐照度(Irradiance)—— 即环境光在半球上的平均强度(对所有方向的环境光进行积分)。
与 GGX 高光预过滤的 “加权平均” 不同,Lambert 预过滤是 **“无权重平均”**:所有方向的环境光贡献均等(仅需考虑方向是否在半球上),因此采样时不需要按分布权重加权,直接取平均即可。
实现步骤详解
步骤 1:明确 Stage 3 的图集存储区域
漫反射预过滤结果通常只需一个级别(因为漫反射对细节不敏感,低分辨率即可满足需求)。以 512x512 图集为例,存储位置为:
用途 | 图集内位置(x,y) | 分辨率(宽 x 高) | 说明 |
---|---|---|---|
漫反射辐照度 | (128s, 384s) | 64x32 | 位于 Stage 1 和 Stage 2 数据的中间区域,尺寸为 64x32(2:1 等矩形比例) |
s = size / 512
:适配不同图集尺寸(如 512x512 时s=1
,256x256 时s=0.5
)。
步骤 2:生成 Lambert 样本
漫反射的均匀特性决定了采样方向需要在半球上均匀分布,SampleGenerator.generateLambertSamples
负责生成这些样本:
// 生成2048个Lambert样本(均匀分布在半球上)
const samples = SampleGenerator.generateLambertSamples(2048, sourceTotalPixels);
// 将样本打包为纹理,供片段着色器解码
const samplesTex = SampleGenerator.createSampleTexture(samples);
- 样本内容:每个样本包含一个均匀分布在半球上的方向向量(
L
)和对应的 MIP 级别(控制环境贴图采样精度); - 2048 个样本:平衡精度与性能(样本