假设无论光源在哪,入射光线的辐射率一样,点光源具有相同的辐射强度,所以辐射强度可以设为一个常量向量
辐射强度根据点的位置和光源的位置和距离进行缩放,所以根据表面法向量和入射角度来缩放辐射强度,用光源的数目计算总辐照度
vec3 lightColor = vec3(23.47, 21.31, 20.79);
vec3 wi = normalize(lightPos - fragPos);
float cosTheta = max(dot(N, Wi), 0.0);
float attenuation = calculateAttenuation(fragPos, lightPos);
float radiance = lightColor * attenuation * cosTheta;
首先计算镜面反射和漫反射的比值,和表面折射的光线相比,反射了多少光线,使用菲涅尔方程
DFG4(ωo⋅n)(ωi⋅n)
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
然后计算法线分布函数和几何遮蔽函数
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 NdotH2 = NdotH*NdotH;
float num = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom; return num / denom;
}
float GeometrySchlickGGX(float NdotV, float roughness)
{
float r = (roughness + 1.0);
float k = (r*r) / 8.0;
float num = NdotV;
float denom = NdotV * (1.0 - k) + k;
return num / 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;
}
在几何遮蔽函数和法线分布函数中用粗糙度的平方,使光线看起来更自然
使用菲涅尔方程计算出ks后计算折射比值kd
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
金属不会折射光线,所以没有漫反射,将系数设置为0
在着色器的最后进行伽马矫正,在伽马矫正前从LDR转为HDR