Fix #125168: Cycles spot light theata_e can flip with a wide spread

When the spread of a spot light is at it's maximum (180 degrees),
then `atan(tan(theta_e))` could become quite unpredictable due to
a asymtote in the tan function when working with lights with this
spread (because theta_e is `spread * 0.5 = pi/2`).
This lead to issues like theta_e for the spotlight becoming negative,
which lead to rendering errors due to a malformed light tree.

This commit fixes this issue by adding a episilon region around the
troublesome values and sets theta_e to `pi/2` when in that region.

Candidate for backporting to 4.2 and potentially 3.6

Pull Request: https://projects.blender.org/blender/blender/pulls/125172
This commit is contained in:
Alaska
2024-07-22 17:09:43 +02:00
committed by Sergey Sharybin
parent f2c728468c
commit 90e83175eb

View File

@@ -186,13 +186,23 @@ LightTreeEmitter::LightTreeEmitter(Scene *scene,
else if (type == LIGHT_SPOT) {
measure.bcone.theta_o = 0;
const float unscaled_theta_e = lamp->get_spot_angle() * 0.5f;
float theta_e = min(lamp->get_spot_angle() * 0.5f, M_PI_2_F);
const float len_u = len(lamp->get_axisu());
const float len_v = len(lamp->get_axisv());
const float len_w = len(lamp->get_dir());
measure.bcone.theta_e = fast_atanf(fast_tanf(unscaled_theta_e) * fmaxf(len_u, len_v) /
len_w);
/* As theta_e approaches pi/2, the behaviour of atan(tan(theta_e)) can become quite
* unpredicatable as tan(x) has a asymptote at x = pi/2. To avoid this, we skip the back and
* forward conversion. The conversion is required to deal with scaled lights. Since we are no
* longer taking that into consideration in this situation, theta_e may end up being larger
* than what is ideal, resulting in increase nosie. */
if (fabsf(M_PI_2_F - theta_e) < 1e-6f) {
theta_e = M_PI_2_F;
}
else {
theta_e = fast_atanf(fast_tanf(theta_e) * fmaxf(len_u, len_v) / len_w);
}
measure.bcone.theta_e = theta_e;
/* Point and spot lights can emit light from any point within its radius. */
const float3 radius = make_float3(size);