Cycles: support spread angle 0 for area lights
Ref: T87053
This commit is contained in:
parent
c2dc65dfa4
commit
bf18032977
|
@ -97,6 +97,11 @@ ccl_device float area_light_spread_attenuation(const float3 D,
|
||||||
/* Model a soft-box grid, computing the ratio of light not hidden by the
|
/* Model a soft-box grid, computing the ratio of light not hidden by the
|
||||||
* slats of the grid at a given angle. (see D10594). */
|
* slats of the grid at a given angle. (see D10594). */
|
||||||
const float cos_a = -dot(D, lightNg);
|
const float cos_a = -dot(D, lightNg);
|
||||||
|
if (tan_half_spread == 0.0f) {
|
||||||
|
/* cos(0.05°) ≈ 0.9999997 */
|
||||||
|
/* The factor M_PI_F comes from integrating the radiance over the hemisphere */
|
||||||
|
return (cos_a > 0.9999997f) ? M_PI_F : 0.0f;
|
||||||
|
}
|
||||||
const float sin_a = safe_sqrtf(1.0f - sqr(cos_a));
|
const float sin_a = safe_sqrtf(1.0f - sqr(cos_a));
|
||||||
const float tan_a = sin_a / cos_a;
|
const float tan_a = sin_a / cos_a;
|
||||||
return max((tan_half_spread - tan_a) * normalize_spread, 0.0f);
|
return max((tan_half_spread - tan_a) * normalize_spread, 0.0f);
|
||||||
|
@ -128,8 +133,8 @@ ccl_device bool area_light_spread_clamp_light(const float3 P,
|
||||||
const bool is_round = !(*sample_rectangle) && (*len_u == *len_v);
|
const bool is_round = !(*sample_rectangle) && (*len_u == *len_v);
|
||||||
|
|
||||||
/* Whether we should sample the spread circle. */
|
/* Whether we should sample the spread circle. */
|
||||||
bool sample_spread;
|
bool sample_spread = (r_spread == 0.0f);
|
||||||
if (is_round) {
|
if (is_round && !sample_spread) {
|
||||||
/* Distance between the centers of the disk light and the valid region circle. */
|
/* Distance between the centers of the disk light and the valid region circle. */
|
||||||
const float dist = len(make_float2(spread_u, spread_v));
|
const float dist = len(make_float2(spread_u, spread_v));
|
||||||
|
|
||||||
|
@ -168,7 +173,7 @@ ccl_device bool area_light_spread_clamp_light(const float3 P,
|
||||||
sample_spread = (spread_area < circle_area);
|
sample_spread = (spread_area < circle_area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (!is_round && !sample_spread) {
|
||||||
/* Compute rectangle encompassing the circle that affects the shading point,
|
/* Compute rectangle encompassing the circle that affects the shading point,
|
||||||
* clamped to the bounds of the area light. */
|
* clamped to the bounds of the area light. */
|
||||||
const float min_u = max(spread_u - r_spread, -*len_u * 0.5f);
|
const float min_u = max(spread_u - r_spread, -*len_u * 0.5f);
|
||||||
|
@ -210,6 +215,7 @@ ccl_device bool area_light_spread_clamp_light(const float3 P,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sample_spread) {
|
if (sample_spread) {
|
||||||
|
*sample_rectangle = false;
|
||||||
*lightP = *lightP + *axis_u * spread_u + *axis_v * spread_v;
|
*lightP = *lightP + *axis_u * spread_u + *axis_v * spread_v;
|
||||||
*len_u = r_spread * 2.0f;
|
*len_u = r_spread * 2.0f;
|
||||||
*len_v = r_spread * 2.0f;
|
*len_v = r_spread * 2.0f;
|
||||||
|
@ -280,9 +286,16 @@ ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
|
||||||
P, &ls->P, sample_axis_u, sample_len_u, sample_axis_v, sample_len_v, randu, randv, true);
|
P, &ls->P, sample_axis_u, sample_len_u, sample_axis_v, sample_len_v, randu, randv, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ls->P += ellipse_sample(
|
if (klight->area.tan_half_spread == 0.0f) {
|
||||||
sample_axis_u * sample_len_u * 0.5f, sample_axis_v * sample_len_v * 0.5f, randu, randv);
|
ls->pdf = 1.0f;
|
||||||
ls->pdf = 4.0f * M_1_PI_F / (sample_len_u * sample_len_v);
|
}
|
||||||
|
else {
|
||||||
|
ls->P += ellipse_sample(sample_axis_u * sample_len_u * 0.5f,
|
||||||
|
sample_axis_v * sample_len_v * 0.5f,
|
||||||
|
randu,
|
||||||
|
randv);
|
||||||
|
ls->pdf = 4.0f * M_1_PI_F / (sample_len_u * sample_len_v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
inplane = ls->P - old_P;
|
inplane = ls->P - old_P;
|
||||||
}
|
}
|
||||||
|
@ -313,7 +326,7 @@ ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
|
||||||
ls->D, ls->Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
|
ls->D, ls->Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sample_rectangle) {
|
if (!sample_rectangle && klight->area.tan_half_spread > 0) {
|
||||||
ls->pdf *= lamp_light_pdf(Ng, -ls->D, ls->t);
|
ls->pdf *= lamp_light_pdf(Ng, -ls->D, ls->t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +433,10 @@ ccl_device_inline bool area_light_sample_from_intersection(
|
||||||
ray_P, &light_P, sample_axis_u, sample_len_u, sample_axis_v, sample_len_v, 0, 0, false);
|
ray_P, &light_P, sample_axis_u, sample_len_u, sample_axis_v, sample_len_v, 0, 0, false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ls->pdf = 4.0f * M_1_PI_F / (sample_len_u * sample_len_v) * lamp_light_pdf(Ng, -ray_D, ls->t);
|
ls->pdf = klight->area.tan_half_spread == 0.0f ?
|
||||||
|
1.0f :
|
||||||
|
4.0f * M_1_PI_F / (sample_len_u * sample_len_v) *
|
||||||
|
lamp_light_pdf(Ng, -ray_D, ls->t);
|
||||||
}
|
}
|
||||||
|
|
||||||
ls->eval_fac = 0.25f * invarea;
|
ls->eval_fac = 0.25f * invarea;
|
||||||
|
@ -429,12 +445,9 @@ ccl_device_inline bool area_light_sample_from_intersection(
|
||||||
/* Area Light spread angle attenuation */
|
/* Area Light spread angle attenuation */
|
||||||
ls->eval_fac *= area_light_spread_attenuation(
|
ls->eval_fac *= area_light_spread_attenuation(
|
||||||
ls->D, ls->Ng, klight->area.tan_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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return ls->eval_fac > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool in_volume_segment>
|
template<bool in_volume_segment>
|
||||||
|
|
|
@ -1038,9 +1038,10 @@ void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Sce
|
||||||
float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
|
float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
|
||||||
float3 dir = light->dir;
|
float3 dir = light->dir;
|
||||||
|
|
||||||
/* Clamping to a minimum angle to avoid excessive noise. */
|
/* Clamp angles in (0, 0.1) to 0.1 to prevent zero intensity due to floating-point precision
|
||||||
const float min_spread = 1.0f * M_PI_F / 180.0f;
|
* issues, but still handles spread = 0 */
|
||||||
const float half_spread = 0.5f * max(light->spread, min_spread);
|
const float min_spread = 0.1f * M_PI_F / 180.0f;
|
||||||
|
const float half_spread = light->spread == 0 ? 0.0f : 0.5f * max(light->spread, min_spread);
|
||||||
const float tan_half_spread = light->spread == M_PI_F ? FLT_MAX : tanf(half_spread);
|
const float tan_half_spread = light->spread == M_PI_F ? FLT_MAX : tanf(half_spread);
|
||||||
/* Normalization computed using:
|
/* Normalization computed using:
|
||||||
* integrate cos(x) * (1 - tan(x) / tan(a)) * sin(x) from x = 0 to a, a being half_spread.
|
* integrate cos(x) * (1 - tan(x) / tan(a)) * sin(x) from x = 0 to a, a being half_spread.
|
||||||
|
|
|
@ -472,7 +472,7 @@ static void rna_def_area_light(BlenderRNA *brna)
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "spread", PROP_FLOAT, PROP_ANGLE);
|
prop = RNA_def_property(srna, "spread", PROP_FLOAT, PROP_ANGLE);
|
||||||
RNA_def_property_float_sdna(prop, NULL, "area_spread");
|
RNA_def_property_float_sdna(prop, NULL, "area_spread");
|
||||||
RNA_def_property_range(prop, DEG2RADF(1.0f), DEG2RADF(180.0f));
|
RNA_def_property_range(prop, DEG2RADF(0.0f), DEG2RADF(180.0f));
|
||||||
RNA_def_property_ui_text(
|
RNA_def_property_ui_text(
|
||||||
prop,
|
prop,
|
||||||
"Spread",
|
"Spread",
|
||||||
|
|
Loading…
Reference in New Issue