diff options
Diffstat (limited to 'intern/cycles/kernel/kernel_light_common.h')
-rw-r--r-- | intern/cycles/kernel/kernel_light_common.h | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/intern/cycles/kernel/kernel_light_common.h b/intern/cycles/kernel/kernel_light_common.h index 39503a4b479..4a683d36226 100644 --- a/intern/cycles/kernel/kernel_light_common.h +++ b/intern/cycles/kernel/kernel_light_common.h @@ -146,6 +146,70 @@ ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot return attenuation; } +ccl_device float light_spread_attenuation(const float3 D, + const float3 lightNg, + const float tan_spread, + const float normalize_spread) +{ + /* Model a soft-box grid, computing the ratio of light not hidden by the + * slats of the grid at a given angle. (see D10594). */ + const float cos_a = -dot(D, lightNg); + const float sin_a = safe_sqrtf(1.0f - sqr(cos_a)); + const float tan_a = sin_a / cos_a; + return max((1.0f - (tan_spread * tan_a)) * normalize_spread, 0.0f); +} + +/* Compute subset of area light that actually has an influence on the shading point, to + * reduce noise with low spread. */ +ccl_device bool light_spread_clamp_area_light(const float3 P, + const float3 lightNg, + float3 *lightP, + float3 *axisu, + float3 *axisv, + const float tan_spread) +{ + /* Closest point in area light plane and distance to that plane. */ + const float3 closest_P = P - dot(lightNg, P - *lightP) * lightNg; + const float t = len(closest_P - P); + + /* Radius of circle on area light that actually affects the shading point. */ + const float radius = t / tan_spread; + + /* TODO: would be faster to store as normalized vector + length, also in rect_light_sample. */ + float len_u, len_v; + const float3 u = normalize_len(*axisu, &len_u); + const float3 v = normalize_len(*axisv, &len_v); + + /* Local uv coordinates of closest point. */ + const float closest_u = dot(u, closest_P - *lightP); + const float closest_v = dot(v, closest_P - *lightP); + + /* Compute rectangle encompassing the circle that affects the shading point, + * clamped to the bounds of the area light. */ + const float min_u = max(closest_u - radius, -len_u * 0.5f); + const float max_u = min(closest_u + radius, len_u * 0.5f); + const float min_v = max(closest_v - radius, -len_v * 0.5f); + const float max_v = min(closest_v + radius, len_v * 0.5f); + + /* Skip if rectangle is empty. */ + if (min_u >= max_u || min_v >= max_v) { + return false; + } + + /* Compute new area light center position and axes from rectangle in local + * uv coordinates. */ + const float new_center_u = 0.5f * (min_u + max_u); + const float new_center_v = 0.5f * (min_v + max_v); + const float new_len_u = max_u - min_u; + const float new_len_v = max_v - min_v; + + *lightP = *lightP + new_center_u * u + new_center_v * v; + *axisu = u * new_len_u; + *axisv = v * new_len_v; + + return true; +} + ccl_device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3 I, float t) { float cos_pi = dot(Ng, I); |