PBR (Physically Based Rendering)
一. 理论
总:反射率方程:
将方程拆成两个部份
1.1 入射光辐射
Li(p,ωi) 由光源获取或者由环境贴图(IBL)计算。
1.2 BRDF(双向反射分布函数)
fr(p,ωi,ωo) 它接受入射(光)方向ωi出射(观察)方向ωo平面法线n以及一个用来表示微平面粗糙程度的参数a作为函数的输入参数。几乎所有实时渲染管线使用的都是一种被称为Cook-Torrance BRDF模型
kd = 入射光线中被折射部分的能量所占的比率
ks = 是被反射部分的比率
第1部份 Lambertian漫反射
第2部份 镜面反射部分
近一步拆分分子 DFG
-
D 代表(法线分布函数),从统计学上近似地表示了与某些(半程)向量h取向一致的微平面的比率。Trowbridge-Reitz GGX公式
n:表面法线
h:光线的视线的半程向量
a: 表面粗糙度
GLSL代码:
float DistributionGGX(vec3 N, vec3 H, float roughness) {
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N,H), 0.0);
float NdtoH2 = NdotH * NdotH;
float nom = a2;
float denom = (NdtoH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
-
F 代表(几何函数),几何函数从统计学上近似的求得了微平面间相互遮蔽的比率,Schlick-GGX公式:
这里的k取决于我们要用的是针对直接光照还是针对IBL光照的几何函数:
史密斯法公式, 是将视角方向和光线方向的几何遮蔽结合
GLSL代码:
float GeometrySchlickGGX(float NdotV, float roughness) {
float r = (roughness + 1.0);
float k = (r*r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
-
F 代表(菲涅尔方程)描述的是在不同的表面角下表面所反射的光线所占的比率
用Fresnel-Schlick近似法求得近似解
F0:基础反射率
GLSL代码:
vec3 F0 = vec3(0.04);
F0 = mix(F0, uMaterial.albedo, uMaterial.metallic);
vec3 F = fresnelSchlick(clamp(dot(H, V), 0.0, 1.0), F0);
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
1.2总结
最终的反射率方程:
最终方程