UE4 默认光照材质:GBuffer 参数与 StandardShading
March 25, 2025About 2 min
UE4 默认光照材质:GBuffer 参数与 StandardShading
UE4 里实现了好几种着色模型:default lit、subsurface、clearcoat、hair、cloth、eye 等,其中 default lit 用得最多。这篇拆一下 default lit 的 GBuffer 参数怎么从材质输入换算出来,以及 StandardShading 那段核心 HLSL 到底在算什么。
四个主参数与 GBuffer 换算
default lit 用两个 lobe:一个 diffuse、一个 specular,两者的贡献相加。对外暴露四个主参数:
- Base Color
- Metallic
- Specular
- Roughness
Base Color、Metallic、Roughness 都很直观。唯一要留意的是 Specular——它是一个标量,用来控制非金属表面的高光强度(金属的高光由 Base Color 决定)。
从这四个参数换算到 GBuffer 的 DiffuseColor 和 SpecularColor:
GBuffer.DiffuseColor = BaseColor - BaseColor * Metallic;
GBuffer.SpecularColor = lerp(0.08 * Specular.xxx, BaseColor, Metallic.xxx);
两行浓缩了金属工作流的本质:
- 金属度拉高时漫反射归零:
BaseColor - BaseColor * Metallic,Metallic=1 时 DiffuseColor 变 0——金属没有漫反射分量。 - 高光颜色在「绝缘体高光」和「基色」之间按金属度插值:非金属(Metallic=0)时高光是
0.08 * Specular的无色高光,那个 0.08 就是常见绝缘体约 4% 反射率的换算;金属(Metallic=1)时高光被 Base Color 染色。
StandardShading
核心着色函数:
float3 StandardShading(float3 DiffuseColor, float3 SpecularColor,
float3 LobeRoughness, float3 LobeEnergy,
float3 L, float3 V, half3 N)
{
float NoL = dot(N, L);
float NoV = dot(N, V);
float LoV = dot(L, V);
float InvLenH = rsqrt(2 + 2 * LoV);
float NoH = saturate((NoL + NoV) * InvLenH);
float VoH = saturate(InvLenH + InvLenH * LoV);
NoL = saturate(NoL);
NoV = saturate(abs(NoV) + 1e-5);
// Generalized microfacet specular
float D = D_GGX(LobeRoughness[1], NoH) * LobeEnergy[1];
float Vis = Vis_SmithJointApprox(LobeRoughness[1], NoV, NoL);
float3 F = F_Schlick(SpecularColor, VoH);
float3 Diffuse = Diffuse_Lambert(DiffuseColor);
return Diffuse * LobeEnergy[2] + (D * Vis) * F;
}
几个实现细节:
- 半程向量的长度用
rsqrt(2 + 2*LoV)算,避免显式归一化。|L+V|² = 2 + 2·(L·V),所以InvLenH = 1/|L+V|,NoH、VoH都用它凑出来,省了一次 normalize。 - 微表面高光是 D·Vis·F 三项:
D_GGX是法线分布项(GGX/Trowbridge-Reitz),Vis_SmithJointApprox是几何遮蔽项(已经把 Cook-Torrance 分母里的1/(4·NoL·NoV)吸收进去了),F_Schlick是菲涅尔项。这也是为什么函数里看不到那个1/(4·NoL·NoV)——它被 Vis 项约掉了,照抄公式时别再乘一遍。 NoV = abs(NoV) + 1e-5:加个小 epsilon 防止除零 / 掠射角数值爆炸。- LobeEnergy 用来做能量补偿:高光乘
LobeEnergy[1],漫反射乘LobeEnergy[2]。
Unity 的 standard 材质基本是同一套 metallic 工作流,思路一致,不再重复。
延伸阅读
- Brian Karis, Real Shading in Unreal Engine 4(SIGGRAPH 2013)
- 材质模型的通用原理见 Disney BRDF 材质模型