#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