Fix #128654: EEVEE: improve precision of cubic solver in light LTC

by rescaling the polynomial coefficients and bringing them to the same
magnitude.

Pull Request: https://projects.blender.org/blender/blender/pulls/128753
This commit is contained in:
Weizhen Huang
2024-10-08 21:45:51 +02:00
committed by Weizhen Huang
parent dc6e021472
commit 52f2bb53b9
2 changed files with 19 additions and 14 deletions

View File

@@ -246,8 +246,7 @@ void Light::shape_parameters_set(const ::Light *la,
this->local.shadow_radius = (la->radius > 0.0f) ? max_ff(1e-8f, local.shadow_radius) : 0.0f;
/* Set to default position. */
this->local.shadow_position = float3(0.0f);
/* Ensure a minimum radius/energy ratio to avoid harsh cut-offs. (See 114284) */
this->local.shape_radius = max(la->radius, la->energy * 2e-05f);
this->local.shape_radius = la->radius;
/* Clamp to minimum value before float imprecision artifacts appear. */
this->local.shape_radius = max(0.001f, this->local.shape_radius);
}

View File

@@ -226,7 +226,7 @@ float ltc_evaluate_disk(sampler2DArray utility_tx, vec3 N, vec3 V, mat3 Minv, ve
float d11 = dot(V1, V1);
float d22 = dot(V2, V2);
float d12 = dot(V1, V2);
float a, b; /* Eigenvalues */
float a, inv_b; /* Eigenvalues */
const float threshold = 0.0007; /* Can be adjusted. Fix artifacts. */
if (abs(d12) / sqrt(d11 * d22) > threshold) {
float tr = d11 + d22;
@@ -252,15 +252,15 @@ float ltc_evaluate_disk(sampler2DArray utility_tx, vec3 N, vec3 V, mat3 Minv, ve
}
a = 1.0 / e_max;
b = 1.0 / e_min;
inv_b = e_min;
V1 = normalize(V1_);
V2 = normalize(V2_);
}
else {
a = 1.0 / d11;
b = 1.0 / d22;
inv_b = d22;
V1 *= sqrt(a);
V2 *= sqrt(b);
V2 *= inversesqrt(inv_b);
}
/* Now find front facing ellipse with same solid angle. */
@@ -275,14 +275,17 @@ float ltc_evaluate_disk(sampler2DArray utility_tx, vec3 N, vec3 V, mat3 Minv, ve
float x0 = dot(V1, C) * inv_L;
float y0 = dot(V2, C) * inv_L;
float L_sqr = L * L;
a *= L_sqr;
b *= L_sqr;
float ab = a * inv_b;
inv_b *= square(inv_L);
float t = 1.0 + x0 * x0;
float c0 = a * b;
float c1 = c0 * (t + y0 * y0) - a - b;
float c2 = (1.0 - a * t) - b * (1.0 + y0 * y0);
/* Compared to the original LTC implementation, we scale the polynomial by `b` to avoid numerical
* issues when light size is small.
* i.e., instead of solving `c0 * e^3 + c1 * e^2 + c2 * e + c3 = 0`,
* we solve `c0/b^3 * (be)^3 + c1/b^2 * (be)^2 + c2/b * be + c3 = 0`. */
float c0 = ab * inv_b;
float c1 = ab * (t + y0 * y0) - c0 - inv_b;
float c2 = inv_b - ab * t - (1.0 + y0 * y0);
float c3 = 1.0;
vec3 roots = ltc_solve_cubic(vec4(c0, c1, c2, c3));
@@ -290,7 +293,10 @@ float ltc_evaluate_disk(sampler2DArray utility_tx, vec3 N, vec3 V, mat3 Minv, ve
float e2 = roots.y;
float e3 = roots.z;
vec3 avg_dir = vec3(a * x0 / (a - e2), b * y0 / (b - e2), 1.0);
/* Scale the root back by multiplying `b`.
* `a * x0 / (a - b * e2)` simplifies to `a/b * x0 / (a/b - e2)`,
* `b * y0 / (b - b * e2)` simplifies to `y0 / (1.0 - e2)`. */
vec3 avg_dir = vec3(ab * x0 / (ab - e2), y0 / (1.0 - e2), 1.0);
mat3 rotate = mat3(V1, V2, V3);