diff options
Diffstat (limited to 'source/blender/draw/engines/eevee')
3 files changed, 49 insertions, 24 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index cba86d058ea..e23a5a81169 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -96,7 +96,7 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli) } } else if (ELEM(la->type, LA_SPOT, LA_LOCAL)) { - power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI); /* 1/(4*r²*Pi²) */ + power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI); /* `1/(4*(r^2)*(Pi^2))` */ /* for point lights (a.k.a radius == 0.0) */ // power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */ @@ -106,7 +106,7 @@ static float light_shape_power_get(const Light *la, const EEVEE_Light *evli) /* Make illumination power closer to cycles for bigger radii. Cycles uses a cos^3 term that we * cannot reproduce so we account for that by scaling the light power. This function is the * result of a rough manual fitting. */ - power += 1.0f / (2.0f * M_PI); /* power *= 1 + r²/2 */ + power += 1.0f / (2.0f * M_PI); /* `power *= 1 + (r^2)/2` */ } return power; } @@ -257,7 +257,7 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) float power = max_fff(UNPACK3(evli->color)) * evli->volume; if (power > 0.0f && evli->light_type != LA_SUN) { /* The limit of the power attenuation function when the distance to the light goes to 0 is - * 2 / r² where r is the light radius. We need to find the right radius that emits at most + * `2 / r^2` where r is the light radius. We need to find the right radius that emits at most * the volume light upper bound. Inverting the function we get: */ float min_radius = 1.0f / sqrtf(0.5f * upper_bound / power); /* Square it here to avoid a multiplication inside the shader. */ diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 5739024993e..5ada53ab98c 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -79,7 +79,7 @@ bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata) * type the rest of the bits are used for the name hash. */ int EEVEE_renderpasses_aov_hash(const ViewLayerAOV *aov) { - int hash = BLI_hash_string(aov->name); + int hash = BLI_hash_string(aov->name) << 1; SET_FLAG_FROM_TEST(hash, aov->type == AOV_TYPE_COLOR, EEVEE_AOV_HASH_COLOR_TYPE_MASK); return hash; } 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..05496ad4ab0 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(safe_sqrt(1.0 - N1_z2), safe_sqrt(N1_z2)); + vec2 N2 = vec2(safe_sqrt(1.0 - N2_z2), safe_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(safe_sqrt(1.0 - Nz2), safe_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 --------- */ |