Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/kernel/kernel_light.h32
-rw-r--r--intern/cycles/kernel/kernel_light_common.h57
2 files changed, 81 insertions, 8 deletions
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 93b05f0ffce..f288ca3051a 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -119,11 +119,11 @@ ccl_device_inline bool lamp_light_sample(
klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
float3 axisv = make_float3(
klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
- float3 D = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
+ float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
float invarea = fabsf(klight->area.invarea);
bool is_round = (klight->area.invarea < 0.0f);
- if (dot(ls->P - P, D) > 0.0f) {
+ if (dot(ls->P - P, Ng) > 0.0f) {
return false;
}
@@ -135,15 +135,25 @@ ccl_device_inline bool lamp_light_sample(
ls->pdf = invarea;
}
else {
+ float3 sample_axisu = axisu;
+ float3 sample_axisv = axisv;
+
+ if (klight->area.tan_spread > 0.0f) {
+ if (!light_spread_clamp_area_light(
+ P, Ng, &ls->P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
+ return false;
+ }
+ }
+
inplane = ls->P;
- ls->pdf = rect_light_sample(P, &ls->P, axisu, axisv, randu, randv, true);
+ ls->pdf = rect_light_sample(P, &ls->P, sample_axisu, sample_axisv, randu, randv, true);
inplane = ls->P - inplane;
}
ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f;
ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f;
- ls->Ng = D;
+ ls->Ng = Ng;
ls->D = normalize_len(ls->P - P, &ls->t);
ls->eval_fac = 0.25f * invarea;
@@ -155,7 +165,7 @@ ccl_device_inline bool lamp_light_sample(
}
if (is_round) {
- ls->pdf *= lamp_light_pdf(kg, D, -ls->D, ls->t);
+ ls->pdf *= lamp_light_pdf(kg, Ng, -ls->D, ls->t);
}
}
}
@@ -290,7 +300,17 @@ ccl_device bool lamp_light_eval(
ls->pdf = invarea * lamp_light_pdf(kg, Ng, -D, ls->t);
}
else {
- ls->pdf = rect_light_sample(P, &light_P, axisu, axisv, 0, 0, false);
+ float3 sample_axisu = axisu;
+ float3 sample_axisv = axisv;
+
+ if (klight->area.tan_spread > 0.0f) {
+ if (!light_spread_clamp_area_light(
+ P, Ng, &light_P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) {
+ return false;
+ }
+ }
+
+ ls->pdf = rect_light_sample(P, &light_P, sample_axisu, sample_axisv, 0, 0, false);
}
ls->eval_fac = 0.25f * invarea;
diff --git a/intern/cycles/kernel/kernel_light_common.h b/intern/cycles/kernel/kernel_light_common.h
index 7efd1e74202..1f4aecc0b68 100644
--- a/intern/cycles/kernel/kernel_light_common.h
+++ b/intern/cycles/kernel/kernel_light_common.h
@@ -147,16 +147,69 @@ ccl_device float spot_light_attenuation(float3 dir, float spot_angle, float spot
}
ccl_device float light_spread_attenuation(const float3 D,
- const float3 Ng,
+ const float3 lightNg,
const float tan_spread,
const float normalize_spread)
{
- const float cos_a = -dot(D, Ng);
+ /* Model a softbox grid, computing the ratio of light not hidden by the
+ * slats of the grid at a given angle. (seee 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 = 0.5f * (max_u - min_u);
+ const float new_len_v = 0.5f * (max_v - min_v);
+
+ *lightP = *lightP + new_center_u * u + new_center_v * v;
+ *axisu = u * new_len_u * 2.0f;
+ *axisv = v * new_len_v * 2.0f;
+
+ return true;
+}
+
ccl_device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3 I, float t)
{
float cos_pi = dot(Ng, I);