Cleanup: store tan instead of cot in area lights to increase precision

This commit is contained in:
Weizhen Huang 2022-12-07 18:51:26 +01:00
parent 07d3a3962a
commit f68634a379
3 changed files with 20 additions and 20 deletions

View File

@ -91,7 +91,7 @@ ccl_device_inline float area_light_rect_sample(float3 P,
ccl_device float area_light_spread_attenuation(const float3 D,
const float3 lightNg,
const float cot_half_spread,
const float tan_half_spread,
const float normalize_spread)
{
/* Model a soft-box grid, computing the ratio of light not hidden by the
@ -99,7 +99,7 @@ ccl_device float area_light_spread_attenuation(const float3 D,
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 - (cot_half_spread * tan_a)) * normalize_spread, 0.0f);
return max((tan_half_spread - tan_a) * normalize_spread, 0.0f);
}
/* Compute the minimal rectangle, circle or ellipse that covers the valid sample region, to reduce
@ -111,7 +111,7 @@ ccl_device bool area_light_spread_clamp_light(const float3 P,
ccl_private float *len_u,
ccl_private float3 *axis_v,
ccl_private float *len_v,
const float cot_half_spread,
const float tan_half_spread,
ccl_private bool *sample_rectangle)
{
/* Closest point in area light plane and distance to that plane. */
@ -119,7 +119,7 @@ ccl_device bool area_light_spread_clamp_light(const float3 P,
const float t = len(closest_P - P);
/* Radius of circle on area light that actually affects the shading point. */
const float r_spread = t / cot_half_spread;
const float r_spread = t * tan_half_spread;
/* Local uv coordinates of closest point. */
const float spread_u = dot(*axis_u, closest_P - *lightP);
@ -261,7 +261,7 @@ ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
float sample_len_u = len_u;
float sample_len_v = len_v;
if (klight->area.cot_half_spread > 0.0f) {
if (klight->area.normalize_spread > 0) {
if (!area_light_spread_clamp_light(P,
Ng,
&ls->P,
@ -269,7 +269,7 @@ ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
&sample_len_u,
&sample_axis_v,
&sample_len_v,
klight->area.cot_half_spread,
klight->area.tan_half_spread,
&sample_rectangle)) {
return false;
}
@ -307,10 +307,10 @@ ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
ls->eval_fac = 0.25f * invarea;
if (klight->area.cot_half_spread > 0.0f) {
if (klight->area.normalize_spread > 0) {
/* Area Light spread angle attenuation */
ls->eval_fac *= area_light_spread_attenuation(
ls->D, ls->Ng, klight->area.cot_half_spread, klight->area.normalize_spread);
ls->D, ls->Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
}
if (!sample_rectangle) {
@ -328,10 +328,10 @@ ccl_device_forceinline void area_light_update_position(const ccl_global KernelLi
ls->D = normalize_len(ls->P - P, &ls->t);
ls->pdf = invarea;
if (klight->area.cot_half_spread > 0.f) {
if (klight->area.tan_half_spread > 0) {
ls->eval_fac = 0.25f * invarea;
ls->eval_fac *= area_light_spread_attenuation(
ls->D, ls->Ng, klight->area.cot_half_spread, klight->area.normalize_spread);
ls->D, ls->Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
}
}
@ -401,7 +401,7 @@ ccl_device_inline bool area_light_sample_from_intersection(
bool is_ellipse = (klight->area.invarea < 0.0f);
bool sample_rectangle = !is_ellipse;
if (klight->area.cot_half_spread > 0.0f) {
if (klight->area.normalize_spread > 0) {
if (!area_light_spread_clamp_light(ray_P,
Ng,
&light_P,
@ -409,7 +409,7 @@ ccl_device_inline bool area_light_sample_from_intersection(
&sample_len_u,
&sample_axis_v,
&sample_len_v,
klight->area.cot_half_spread,
klight->area.tan_half_spread,
&sample_rectangle)) {
return false;
}
@ -425,10 +425,10 @@ ccl_device_inline bool area_light_sample_from_intersection(
ls->eval_fac = 0.25f * invarea;
if (klight->area.cot_half_spread > 0.0f) {
if (klight->area.normalize_spread > 0) {
/* Area Light spread angle attenuation */
ls->eval_fac *= area_light_spread_attenuation(
ls->D, ls->Ng, klight->area.cot_half_spread, klight->area.normalize_spread);
ls->D, ls->Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
if (ls->eval_fac == 0.0f) {
return false;
}

View File

@ -1307,7 +1307,7 @@ typedef struct KernelAreaLight {
float len_v;
packed_float3 dir;
float invarea;
float cot_half_spread;
float tan_half_spread;
float normalize_spread;
float pad[2];
} KernelAreaLight;

View File

@ -1041,11 +1041,11 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
/* Clamping to a minimum angle to avoid excessive noise. */
const float min_spread = 1.0f * M_PI_F / 180.0f;
const float half_spread = 0.5f * max(light->spread, min_spread);
/* cot_half_spread is h in D10594#269626 */
const float cot_half_spread = tanf(M_PI_2_F - half_spread);
const float tan_half_spread = light->spread == M_PI_F ? FLT_MAX : tanf(half_spread);
/* Normalization computed using:
* integrate cos(x) * (1 - tan(x) / tan(a)) * sin(x) from x = 0 to a, a being half_spread */
const float normalize_spread = 1.0f / (1.0f - half_spread * cot_half_spread);
* integrate cos(x) * (1 - tan(x) / tan(a)) * sin(x) from x = 0 to a, a being half_spread.
* Divided by tan_half_spread to simplify the attentuation computation in `area.h`. */
const float normalize_spread = 1.0f / (tan_half_spread - half_spread);
dir = safe_normalize(dir);
@ -1059,7 +1059,7 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
klights[light_index].area.len_v = len_v;
klights[light_index].area.invarea = invarea;
klights[light_index].area.dir = dir;
klights[light_index].area.cot_half_spread = cot_half_spread;
klights[light_index].area.tan_half_spread = tan_half_spread;
klights[light_index].area.normalize_spread = normalize_spread;
}
else if (light->light_type == LIGHT_SPOT) {