forked from LeenkxTeam/LNXSDK
89 lines
2.5 KiB
GLSL
89 lines
2.5 KiB
GLSL
#ifndef _BRDF_GLSL_
|
|
#define _BRDF_GLSL_
|
|
|
|
// Constants
|
|
//const float PI = 3.1415926535;
|
|
|
|
// Fresnel-Schlick with optimized exponential approximation
|
|
vec3 f_schlick(const vec3 f0, const float vh) {
|
|
return f0 + (1.0 - f0) * exp2((-5.55473 * vh - 6.98316) * vh);
|
|
}
|
|
|
|
float v_smithschlick(const float nl, const float nv, const float a) {
|
|
return 1.0 / ((nl * (1.0 - a) + a) * (nv * (1.0 - a) + a));
|
|
}
|
|
|
|
float d_ggx(const float nh, const float a) {
|
|
float a2 = a * a;
|
|
float denom = nh * nh * (a2 - 1.0) + 1.0;
|
|
denom = max(denom * denom, 2e-6);
|
|
return a2 / (PI * denom);
|
|
}
|
|
|
|
float getMipFromRoughness(const float roughness, const float numMipmaps) {
|
|
// First mipmap level = roughness 0, last = roughness = 1
|
|
return roughness * numMipmaps;
|
|
}
|
|
|
|
vec3 specularBRDF(vec3 N, vec3 V, vec3 L, vec3 F0, float roughness)
|
|
{
|
|
vec3 H = normalize(V + L);
|
|
|
|
float NdotL = max(dot(N, L), 0.0);
|
|
float NdotV = max(dot(N, V), 0.0);
|
|
float NdotH = max(dot(N, H), 0.0);
|
|
float VdotH = max(dot(V, H), 0.0);
|
|
|
|
float alpha = roughness * roughness;
|
|
|
|
float D = d_ggx(NdotH, alpha);
|
|
float k = alpha / 2.0;
|
|
float G_V = NdotV / (NdotV * (1.0 - k) + k + 1e-5);
|
|
float G_L = NdotL / (NdotL * (1.0 - k) + k + 1e-5);
|
|
float G = G_V * G_L;
|
|
|
|
vec3 F = f_schlick(F0, VdotH);
|
|
|
|
return F * D * G / max(4.0 * NdotL * NdotV, 1e-5);
|
|
}
|
|
|
|
vec3 burleyDiffuseBRDF(vec3 N, vec3 V, vec3 L, vec3 albedo, float roughness)
|
|
{
|
|
float NdotL = max(dot(N, L), 0.0);
|
|
float NdotV = max(dot(N, V), 0.0);
|
|
float LdotH = max(dot(L, normalize(L + V)), 0.0);
|
|
|
|
float FD90 = 0.5 + 2.0 * LdotH * LdotH * roughness;
|
|
float FL = pow(1.0 - NdotL, 5.0);
|
|
float FV = pow(1.0 - NdotV, 5.0);
|
|
|
|
float diffuse = (1.0 + (FD90 - 1.0) * FL) * (1.0 + (FD90 - 1.0) * FV);
|
|
return albedo * (1.0 / PI) * diffuse * NdotL;
|
|
}
|
|
|
|
// Energy-conserving material albedo (fades out for metals)
|
|
vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
|
|
return baseColor * (1.0 - metalness);
|
|
}
|
|
|
|
// Metal-aware F0 blending
|
|
vec3 surfaceF0(vec3 baseColor, float metalness) {
|
|
return mix(vec3(0.04), baseColor, metalness);
|
|
}
|
|
|
|
// LUT-based approximation of IBL BRDF (Unreal-style)
|
|
vec2 EnvBRDFApprox(float Roughness, float NoV) {
|
|
const vec4 c0 = vec4(-1, -0.0275, -0.572, 0.022);
|
|
const vec4 c1 = vec4(1, 0.0425, 1.04, -0.04);
|
|
vec4 r = Roughness * c0 + c1;
|
|
float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
|
|
return vec2(-1.04, 1.04) * a004 + r.zw;
|
|
}
|
|
|
|
vec3 IBLSpecularApprox(vec3 specColor, float roughness, float NoV) {
|
|
vec2 brdf = EnvBRDFApprox(roughness, NoV);
|
|
return specColor * brdf.x + brdf.y;
|
|
}
|
|
|
|
#endif
|