DFGLUT
DFGLUT 会从内置的 16×16 DFG(Distribution–Fresnel–Geometry)查找表纹理中采样,基于粗糙度 roughness 和视角项 dotNV,输出一个 vec2 系数,用于 PBR 镜面环境光照的 split-sum(分裂求积)公式。
核心优势
通过预计算 LUT 纹理直接查表,避免在着色器中执行复杂积分或高阶近似,在保持与 three.js 标准 PBR 外观一致的前提下,将镜面环境光的校正简化为一次纹理采样,稳定且高性能,并可与 DFGApprox 互相对照使用。
常见用途
为预过滤环境贴图提供正确的 PBR 镜面环境光补偿,使金属/非金属在不同粗糙度下的高光能量保持物理合理
在自定义 PBR 材质或自定义 NodeMaterial 中复用 three.js / glTF 相同的环境镜面公式,保证自定义效果与 MeshStandardMaterial 外观一致
在调试或学习 PBR 时,与 DFGApprox 进行对比,观察 LUT 解与解析近似解在不同粗糙度和视角下的细微差异
如何调整
DFGLUT 本身没有可调属性,它的行为完全由两个输入控制:`roughness` 和 `dotNV`。`roughness`(对应 LUT 的 U 轴)通常来自材质粗糙度贴图或常量,数值越大,高光越宽、能量被重新分布得更均匀;你可以在输入前用 `pow(roughness, n)` 等方式微调感知粗糙度曲线。`dotNV`(对应 LUT 的 V 轴)是法线与视线的点积,通常在 [0,1] 范围,通过 `clamp` 约束可避免采样落在纹理边缘之外。DFGLUT 内部使用 `LinearFilter` 和 `ClampToEdgeWrapping` 的 16×16 半浮点 RG 纹理:线性过滤会在粗糙度和视角之间做平滑插值,保持过渡自然;包裹模式为 clamp,则会在越界时钳制到边界值,因此建议始终将 `roughness`、`dotNV` 控制在物理合理的区间内。与 `DFGApprox` 相比,如果你更关心与 three.js 默认 PBR 外观保持完全一致,或希望在不同平台上结果更稳定,可以优先使用 DFGLUT;如果想完全摆脱纹理依赖,则可以改用 DFGApprox。
代码示例
1// 1. 准备输入:粗糙度和 dotNV(法线与视线方向的点积)
2const roughness = roughnessNode; // 0.0 ~ 1.0
3const dotNV = clamp( normalView.dot( positionViewDirection ), 0.0, 1.0 );
4
5// 2. 从 DFG LUT 查出环境镜面系数 (vec2)
6const dfg = DFGLUT.call( { roughness, dotNV } );
7
8// 3. 使用 split-sum 公式构造环境镜面 IBL
9const prefilteredEnv = texture( envMap, reflectionVector );
10const specularIBL = prefilteredEnv.mul( f0.mul( dfg.x ).add( dfg.y ) );
11
12meshStandardNodeMaterial( {
13 envNode: specularIBL
14} );