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/integrator/intersect_closest.h3
-rw-r--r--intern/cycles/kernel/light/light.h113
-rw-r--r--intern/cycles/util/math_intersect.h29
3 files changed, 119 insertions, 26 deletions
diff --git a/intern/cycles/kernel/integrator/intersect_closest.h b/intern/cycles/kernel/integrator/intersect_closest.h
index 366bfba7aca..df710dc1d82 100644
--- a/intern/cycles/kernel/integrator/intersect_closest.h
+++ b/intern/cycles/kernel/integrator/intersect_closest.h
@@ -341,9 +341,8 @@ ccl_device void integrator_intersect_closest(KernelGlobals kg,
* these in the path_state_init. */
const int last_type = INTEGRATOR_STATE(state, isect, type);
const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
-
hit = lights_intersect(
- kg, &ray, &isect, last_isect_prim, last_isect_object, last_type, path_flag) ||
+ kg, state, &ray, &isect, last_isect_prim, last_isect_object, last_type, path_flag) ||
hit;
}
diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h
index e0a9f1c57f5..f47e8fbcf82 100644
--- a/intern/cycles/kernel/light/light.h
+++ b/intern/cycles/kernel/light/light.h
@@ -112,35 +112,58 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
else {
ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
- if (type == LIGHT_POINT || type == LIGHT_SPOT) {
+ if (type == LIGHT_SPOT) {
+ ls->Ng = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
float radius = klight->spot.radius;
if (radius > 0.0f)
/* sphere light */
- ls->P += sphere_light_sample(P, ls->P, radius, randu, randv);
+ ls->P += disk_light_sample(ls->Ng, randu, randv) * radius;
ls->D = normalize_len(ls->P - P, &ls->t);
- ls->Ng = -ls->D;
float invarea = klight->spot.invarea;
ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
ls->pdf = invarea;
- if (type == LIGHT_SPOT) {
- /* spot light attenuation */
- float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
- ls->eval_fac *= spot_light_attenuation(
- dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng);
- if (!in_volume_segment && ls->eval_fac == 0.0f) {
- return false;
- }
+ /* spot light attenuation */
+ ls->eval_fac *= spot_light_attenuation(
+ ls->Ng, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
+ if (!in_volume_segment && ls->eval_fac == 0.0f) {
+ return false;
}
+
float2 uv = map_to_sphere(ls->Ng);
ls->u = uv.x;
ls->v = uv.y;
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
}
+ else if (type == LIGHT_POINT) {
+ float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ float radius = klight->spot.radius;
+ ls->P = center;
+ float pdf = 1.0;
+
+ if (radius > 0.0f) {
+ ls->Ng = normalize(P - center);
+ ls->P += disk_light_sample(ls->Ng, randu, randv) * radius;
+ pdf = klight->spot.invarea;
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ }
+ else {
+ ls->Ng = normalize(P - center);
+ }
+
+ ls->D = normalize_len(ls->P - P, &ls->t);
+ ls->pdf = pdf;
+ ls->eval_fac = M_1_PI_F * 0.25f * klight->spot.invarea;
+
+ float2 uv = map_to_sphere(ls->Ng);
+ ls->u = uv.x;
+ ls->v = uv.y;
+ ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
+ }
else {
/* area light */
float3 axisu = make_float3(
@@ -207,6 +230,7 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
}
ccl_device bool lights_intersect(KernelGlobals kg,
+ IntegratorState state,
ccl_private const Ray *ccl_restrict ray,
ccl_private Intersection *ccl_restrict isect,
const int last_prim,
@@ -237,8 +261,31 @@ ccl_device bool lights_intersect(KernelGlobals kg,
LightType type = (LightType)klight->type;
float t = 0.0f, u = 0.0f, v = 0.0f;
- if (type == LIGHT_POINT || type == LIGHT_SPOT) {
- /* Sphere light. */
+ if (type == LIGHT_SPOT) {
+ /* Spot/Disk light. */
+ const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+ const float3 lightN = make_float3(
+ klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
+ const float radius = klight->spot.radius;
+ if (radius == 0.0f) {
+ continue;
+ }
+
+ /* One sided. */
+ if (dot(ray->D, lightN) >= 0.0f) {
+ continue;
+ }
+
+ float3 P;
+ if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lightN, radius, &P, &t)) {
+ continue;
+ }
+ }
+ else if (type == LIGHT_POINT) {
+ /* Sphere light (aka, aligned disk light). */
+ const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
+ const float3 ray_P = ray->P - ray->D * mis_ray_t;
+
const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
const float radius = klight->spot.radius;
if (radius == 0.0f) {
@@ -246,7 +293,8 @@ ccl_device bool lights_intersect(KernelGlobals kg,
}
float3 P;
- if (!ray_aligned_disk_intersect(ray->P, ray->D, ray->t, lightP, radius, &P, &t)) {
+ const float3 lsN = normalize(ray_P - lightP);
+ if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lsN, radius, &P, &t)) {
continue;
}
}
@@ -378,23 +426,38 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
ls->P = ray_P + ray_D * ls->t;
ls->D = ray_D;
- if (type == LIGHT_POINT || type == LIGHT_SPOT) {
- ls->Ng = -ray_D;
+ if (type == LIGHT_SPOT) {
+ ls->Ng = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
float invarea = klight->spot.invarea;
ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
ls->pdf = invarea;
- if (type == LIGHT_SPOT) {
- /* spot light attenuation */
- float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
- ls->eval_fac *= spot_light_attenuation(
- dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng);
+ /* spot light attenuation */
+ float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
+ ls->eval_fac *= spot_light_attenuation(
+ ls->Ng, klight->spot.spot_angle, klight->spot.spot_smooth, -ls->D);
- if (ls->eval_fac == 0.0f) {
- return false;
- }
+ if (ls->eval_fac == 0.0f) {
+ return false;
}
+
+ float2 uv = map_to_sphere(ls->Ng);
+ ls->u = uv.x;
+ ls->v = uv.y;
+
+ /* compute pdf */
+ if (ls->t != FLT_MAX)
+ ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
+ }
+ else if (type == LIGHT_POINT) {
+ float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
+
+ ls->Ng = normalize(ray_P - center);
+ float invarea = klight->spot.invarea;
+ ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
+ ls->pdf = invarea;
+
float2 uv = map_to_sphere(ls->Ng);
ls->u = uv.x;
ls->v = uv.y;
@@ -402,6 +465,8 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
/* compute pdf */
if (ls->t != FLT_MAX)
ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
+ else
+ ls->pdf = 0.f;
}
else if (type == LIGHT_AREA) {
/* area light */
diff --git a/intern/cycles/util/math_intersect.h b/intern/cycles/util/math_intersect.h
index 54ce3ab4b66..0fce9ff24fd 100644
--- a/intern/cycles/util/math_intersect.h
+++ b/intern/cycles/util/math_intersect.h
@@ -85,6 +85,35 @@ ccl_device bool ray_aligned_disk_intersect(float3 ray_P,
return true;
}
+ccl_device bool ray_disk_intersect(float3 ray_P,
+ float3 ray_D,
+ float ray_t,
+ float3 disk_P,
+ float3 disk_N,
+ float disk_radius,
+ ccl_private float3 *isect_P,
+ ccl_private float *isect_t)
+{
+ const float3 vp = ray_P - disk_P;
+ const float dp = dot(vp, disk_N);
+ const float cos_angle = dot(disk_N, -ray_D);
+ if (dp * cos_angle > 0.f) // front of light
+ {
+ float t = dp / cos_angle;
+ if (t < 0.f) { /* Ray points away from the light. */
+ return false;
+ }
+ float3 P = ray_P + t * ray_D;
+ float3 T = P - disk_P;
+ if (dot(T, T) < sqr(disk_radius) /*&& t > 0.f*/ && t <= ray_t) {
+ *isect_P = ray_P + t * ray_D;
+ *isect_t = t;
+ return true;
+ }
+ }
+ return false;
+}
+
ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P,
float3 ray_dir,
float ray_t,