Cycles: improve light tree with large spot blend
In the original paper, the falloff inside `bcone.theta_e` is assumed to be `pi/2`, which is too large for spot light and resulted in an overestimation near the cone boundary. To address this issue, attenuate the energy of a spot light using the minimal possible angle formed by the light axis and the shading point when traversing the light tree. Ref: #122362 Pull Request: https://projects.blender.org/blender/blender/pulls/122667
This commit is contained in:
committed by
Weizhen Huang
parent
f98b01e492
commit
296ac0e9ef
@@ -286,9 +286,11 @@ template<bool in_volume_segment>
|
||||
ccl_device_forceinline bool spot_light_tree_parameters(const ccl_global KernelLight *klight,
|
||||
const float3 centroid,
|
||||
const float3 P,
|
||||
const ccl_private BoundingCone &bcone,
|
||||
ccl_private float &cos_theta_u,
|
||||
ccl_private float2 &distance,
|
||||
ccl_private float3 &point_to_centroid)
|
||||
ccl_private float3 &point_to_centroid,
|
||||
ccl_private float &energy)
|
||||
{
|
||||
float min_distance;
|
||||
point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
|
||||
@@ -317,6 +319,18 @@ ccl_device_forceinline bool spot_light_tree_parameters(const ccl_global KernelLi
|
||||
distance.x = hypotenus;
|
||||
}
|
||||
|
||||
/* Apply a similar scaling as in `spot_light_attenuation()` to account for spot blend. */
|
||||
{
|
||||
/* Minimum angle formed by the emitter axis and the direction to the shading point,
|
||||
* cos(theta') in the paper. */
|
||||
const float cos_min_outgoing_angle = cosf(
|
||||
fmaxf(0.0f, fast_acosf(dot(bcone.axis, -point_to_centroid)) - fast_acosf(cos_theta_u)));
|
||||
/* Use `cos(bcone.theta_e)` instead of `klight->spot.cos_half_spot_angle` to account for
|
||||
* non-uniform scaling. */
|
||||
energy *= smoothstepf((cos_min_outgoing_angle - cosf(bcone.theta_e)) *
|
||||
klight->spot.spot_smooth);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -420,6 +420,7 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
|
||||
|
||||
/* Early out if the emitter is guaranteed to be invisible. */
|
||||
bool is_visible;
|
||||
float energy = kemitter->energy;
|
||||
if (is_triangle(kemitter)) {
|
||||
is_visible = triangle_light_tree_parameters<in_volume_segment>(
|
||||
kg, kemitter, centroid, P_c, N_or_D, bcone, cos_theta_u, distance, point_to_centroid);
|
||||
@@ -431,7 +432,7 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
|
||||
/* Function templates only modifies cos_theta_u when in_volume_segment = true. */
|
||||
case LIGHT_SPOT:
|
||||
is_visible = spot_light_tree_parameters<in_volume_segment>(
|
||||
klight, centroid, P_c, cos_theta_u, distance, point_to_centroid);
|
||||
klight, centroid, P_c, bcone, cos_theta_u, distance, point_to_centroid, energy);
|
||||
break;
|
||||
case LIGHT_POINT:
|
||||
is_visible = point_light_tree_parameters<in_volume_segment>(
|
||||
@@ -475,7 +476,7 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
|
||||
bcone,
|
||||
distance.x,
|
||||
distance.y,
|
||||
kemitter->energy,
|
||||
energy,
|
||||
max_importance,
|
||||
min_importance);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user