From a0eef0f4f1268ff246d5c642e7a9a49e34733436 Mon Sep 17 00:00:00 2001 From: Hinageshi <69386319+Hinageshi01@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:53:58 +0800 Subject: [PATCH] Visibility functions with different levels of exactness. (#9) --- Engine/BuiltInShaders/common/BRDF.sh | 43 ++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/Engine/BuiltInShaders/common/BRDF.sh b/Engine/BuiltInShaders/common/BRDF.sh index 05fd008c..189037e3 100644 --- a/Engine/BuiltInShaders/common/BRDF.sh +++ b/Engine/BuiltInShaders/common/BRDF.sh @@ -13,17 +13,36 @@ float DistributionGGX(float NdotH, float rough) { return a2 * CD_PI_INV * denom_inv * denom_inv; } -// Geometry -float Visibility(float NdotV, float NdotL, float rough) { - // Specular BRDF = (F * D * G) / (4 * NdotV * NdotL) - // = (F * D * (NdotV / (NdotV * (1 - K) + K)) * (NdotL / (NdotL * (1 - K) + K))) / (4 * NdotV * NdotL) - // = (F * D * (1 / (NdotV * (1 - K) + K)) * (1 / (NdotL * (1 - K) + K))) / 4 - // = F * D * Vis - // Vis = 1 / (NdotV * (1 - K) + K) / (NdotL * (1 - K) + K) / 4 +float Visibility_HighQuality(float NdotV, float NdotL, float rough) { + // BRDF = (F * D * G) / (4 * NdotV * NdotL) = F * D * V + // V = G / (4 * NdotV * NdotL) + // = 0.5 / (NdotL * sqrt(a2 + (1 - a2) * NdotV^2) + NdotV * sqrt(a2 + (1 - a2) * NdotL^2)) + + // rough = (rough + 1) / 2, by Disney + // a = rough^2 + float a2 = pow((rough + 1.0) * 0.5, 4); + float lambda_v = NdotL * sqrt(a2 + (1.0 - a2) * NdotV * NdotV); + float lambda_l = NdotV * sqrt(a2 + (1.0 - a2) * NdotL * NdotL); + + return 0.5 / (lambda_v + lambda_l); +} + +float Visibility_LowQuality(float NdotV, float NdotL, float rough) { + // BRDF = (F * D * G) / (4 * NdotV * NdotL) = F * D * V + // V = G / (4 * NdotV * NdotL) + // = 1 / ((NdotV * (2 - a) + a) * (NdotL * (2 - a) + a)) + + // rough = (rough + 1) / 2, by Disney + // a = rough^2 + float a = (rough + 1.0) * (rough + 1.0) * 0.25; + float g1_v_inv = NdotV * (2.0 - a) + a; + float g1_l_inv = NdotL * (2.0 - a) + a; - float f = rough + 1.0; - float k = f * f * 0.125; - float ggxV = 1.0 / (NdotV * (1.0 - k) + k); - float ggxL = 1.0 / (NdotL * (1.0 - k) + k); - return ggxV * ggxL * 0.25; + return 1.0 / (g1_v_inv * g1_l_inv); } + +// Geometry +float Visibility(float NdotV, float NdotL, float rough) { + // TODO : Wrap them in macros after we've collected enough approximate / exact formulas. + return Visibility_LowQuality(NdotV, NdotL, rough); +} \ No newline at end of file