diff options
Diffstat (limited to 'source/blender/draw/engines')
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl | 65 |
1 files changed, 45 insertions, 20 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index fdbb70e917d..c8eaa06094e 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -138,30 +138,55 @@ void accumulate_light(vec3 light, float fac, inout vec4 accum) /* Same thing as Cycles without the comments to make it shorter. */ vec3 ensure_valid_reflection(vec3 Ng, vec3 I, vec3 N) { - vec3 R; - float NI = dot(N, I); - float NgR, threshold; - /* Check if the incident ray is coming from behind normal N. */ - if (NI > 0.0) { - /* Normal reflection. */ - R = (2.0 * NI) * N - I; - NgR = dot(Ng, R); - /* Reflection rays may always be at least as shallow as the incoming ray. */ - threshold = min(0.9 * dot(Ng, I), 0.01); - if (NgR >= threshold) { - return N; + vec3 R = -reflect(I, N); + + /* Reflection rays may always be at least as shallow as the incoming ray. */ + float threshold = min(0.9 * dot(Ng, I), 0.025); + if (dot(Ng, R) >= threshold) { + return N; + } + + float NdotNg = dot(N, Ng); + vec3 X = normalize(N - NdotNg * Ng); + + float Ix = dot(I, X), Iz = dot(I, Ng); + float Ix2 = sqr(Ix), Iz2 = sqr(Iz); + float a = Ix2 + Iz2; + + float b = sqrt(Ix2 * (a - sqr(threshold))); + float c = Iz * threshold + a; + + float fac = 0.5 / a; + float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c); + bool valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5)); + bool valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5)); + + vec2 N_new; + if (valid1 && valid2) { + /* If both are possible, do the expensive reflection-based check. */ + vec2 N1 = vec2(sqrt(1.0 - N1_z2), sqrt(N1_z2)); + vec2 N2 = vec2(sqrt(1.0 - N2_z2), sqrt(N2_z2)); + + float R1 = 2.0 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz; + float R2 = 2.0 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz; + + valid1 = (R1 >= 1e-5); + valid2 = (R2 >= 1e-5); + if (valid1 && valid2) { + N_new = (R1 < R2) ? N1 : N2; } + else { + N_new = (R1 > R2) ? N1 : N2; + } + } + else if (valid1 || valid2) { + float Nz2 = valid1 ? N1_z2 : N2_z2; + N_new = vec2(sqrt(1.0 - Nz2), sqrt(Nz2)); } else { - /* Bad incident. */ - R = -I; - NgR = dot(Ng, R); - threshold = 0.01; + return Ng; } - /* Lift the reflection above the threshold. */ - R = R + Ng * (threshold - NgR); - /* Find a bisector. */ - return safe_normalize(I * length(R) + R * length(I)); + return N_new.x * X + N_new.y * Ng; } /* ----------- Cone angle Approximation --------- */ |