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
path: root/intern
diff options
context:
space:
mode:
authorPatrick Mours <pmours@nvidia.com>2019-08-25 19:11:41 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2019-08-26 11:26:53 +0300
commitfd52dc58ddea642b7162b01538c0c6c48abb0507 (patch)
tree21df79cee59c14c0cada5c4bc49da3824d4c8a4b /intern
parentf491c23f1e104998752380b930307e7abc4597b3 (diff)
Cycles: GPU code generation optimizations for direct lighting
Use a single loop to iterate over all lights, reducing divergence and amount of code to generate. Moving ray intersection calls out of conditionals will also help the Optix compiler. Ref D5363
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/kernel/kernel_light.h61
-rw-r--r--intern/cycles/kernel/kernel_path.h10
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h241
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h244
-rw-r--r--intern/cycles/kernel/split/kernel_direct_lighting.h3
5 files changed, 234 insertions, 325 deletions
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 758e91159b6..ce908ce0fe2 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -1076,7 +1076,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
int len = kernel_data.integrator.num_distribution + 1;
float r = *randu;
- while (len > 0) {
+ do {
int half_len = len >> 1;
int middle = first + half_len;
@@ -1087,7 +1087,7 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
first = middle + 1;
len = len - half_len - 1;
}
- }
+ } while (len > 0);
/* Clamping should not be needed but float rounding errors seem to
* make this fail on rare occasions. */
@@ -1104,42 +1104,49 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
/* Generic Light */
-ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, int bounce)
+ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals *kg, int index, int bounce)
{
return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
}
-ccl_device_noinline bool light_sample(
- KernelGlobals *kg, float randu, float randv, float time, float3 P, int bounce, LightSample *ls)
+ccl_device_noinline bool light_sample(KernelGlobals *kg,
+ int lamp,
+ float randu,
+ float randv,
+ float time,
+ float3 P,
+ int bounce,
+ LightSample *ls)
{
- /* sample index */
- int index = light_distribution_sample(kg, &randu);
-
- /* fetch light data */
- const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution,
- index);
- int prim = kdistribution->prim;
-
- if (prim >= 0) {
- int object = kdistribution->mesh_light.object_id;
- int shader_flag = kdistribution->mesh_light.shader_flag;
+ if (lamp < 0) {
+ /* sample index */
+ int index = light_distribution_sample(kg, &randu);
+
+ /* fetch light data */
+ const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(
+ __light_distribution, index);
+ int prim = kdistribution->prim;
+
+ if (prim >= 0) {
+ int object = kdistribution->mesh_light.object_id;
+ int shader_flag = kdistribution->mesh_light.shader_flag;
+
+ triangle_light_sample(kg, prim, object, randu, randv, time, ls, P);
+ ls->shader |= shader_flag;
+ return (ls->pdf > 0.0f);
+ }
- triangle_light_sample(kg, prim, object, randu, randv, time, ls, P);
- ls->shader |= shader_flag;
- return (ls->pdf > 0.0f);
+ lamp = -prim - 1;
}
- else {
- int lamp = -prim - 1;
- if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
- return false;
- }
-
- return lamp_light_sample(kg, lamp, randu, randv, P, ls);
+ if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
+ return false;
}
+
+ return lamp_light_sample(kg, lamp, randu, randv, P, ls);
}
-ccl_device int light_select_num_samples(KernelGlobals *kg, int index)
+ccl_device_inline int light_select_num_samples(KernelGlobals *kg, int index)
{
return kernel_tex_fetch(__lights, index).samples;
}
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 1e8d54a23bf..63be0a7f505 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -474,12 +474,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
# endif /* __SUBSURFACE__ */
# if defined(__EMISSION__)
- if (kernel_data.integrator.use_direct_light) {
- int all = (kernel_data.integrator.sample_all_lights_indirect) ||
- (state->flag & PATH_RAY_SHADOW_CATCHER);
- kernel_branched_path_surface_connect_light(
- kg, sd, emission_sd, state, throughput, 1.0f, L, all);
- }
+ int all = (kernel_data.integrator.sample_all_lights_indirect) ||
+ (state->flag & PATH_RAY_SHADOW_CATCHER);
+ kernel_branched_path_surface_connect_light(
+ kg, sd, emission_sd, state, throughput, 1.0f, L, all);
# endif /* defined(__EMISSION__) */
# ifdef __VOLUME__
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index 07444a98d82..d299106ea96 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -32,140 +32,100 @@ ccl_device_noinline_cpu void kernel_branched_path_surface_connect_light(
{
# ifdef __EMISSION__
/* sample illumination from lights to find path contribution */
- if (!(sd->flag & SD_BSDF_HAS_EVAL))
- return;
-
- Ray light_ray;
BsdfEval L_light;
- bool is_lamp;
-
-# ifdef __OBJECT_MOTION__
- light_ray.time = sd->time;
-# endif
-
- if (sample_all_lights) {
- /* lamp sampling */
- for (int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
- if (UNLIKELY(light_select_reached_max_bounces(kg, i, state->bounce)))
- continue;
-
- int num_samples = ceil_to_int(num_samples_adjust * light_select_num_samples(kg, i));
- float num_samples_inv = num_samples_adjust /
- (num_samples * kernel_data.integrator.num_all_lights);
- uint lamp_rng_hash = cmj_hash(state->rng_hash, i);
-
- for (int j = 0; j < num_samples; j++) {
- float light_u, light_v;
- path_branched_rng_2D(
- kg, lamp_rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
- float terminate = path_branched_rng_light_termination(
- kg, lamp_rng_hash, state, j, num_samples);
- LightSample ls;
- if (lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) {
- /* The sampling probability returned by lamp_light_sample assumes that all lights were
- * sampled.
- * However, this code only samples lamps, so if the scene also had mesh lights, the real
- * probability is twice as high. */
- if (kernel_data.integrator.pdf_triangles != 0.0f)
- ls.pdf *= 2.0f;
+ int num_lights = 0;
+ if (kernel_data.integrator.use_direct_light) {
+ if (sample_all_lights) {
+ num_lights = kernel_data.integrator.num_all_lights;
+ if (kernel_data.integrator.pdf_triangles != 0.0f) {
+ num_lights += 1;
+ }
+ }
+ else {
+ num_lights = 1;
+ }
+ }
- if (direct_emission(
- kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
- /* trace shadow ray */
- float3 shadow;
-
- if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L,
- state,
- throughput * num_samples_inv,
- &L_light,
- shadow,
- num_samples_inv,
- is_lamp);
- }
- else {
- path_radiance_accum_total_light(L, state, throughput * num_samples_inv, &L_light);
- }
- }
+ for (int i = 0; i < num_lights; i++) {
+ /* sample one light at random */
+ int num_samples = 1;
+ int num_all_lights = 1;
+ uint lamp_rng_hash = state->rng_hash;
+ bool double_pdf = false;
+ bool is_mesh_light = false;
+ bool is_lamp = false;
+
+ if (sample_all_lights) {
+ /* lamp sampling */
+ is_lamp = i < kernel_data.integrator.num_all_lights;
+ if (is_lamp) {
+ if (UNLIKELY(light_select_reached_max_bounces(kg, i, state->bounce))) {
+ continue;
}
+ num_samples = ceil_to_int(num_samples_adjust * light_select_num_samples(kg, i));
+ num_all_lights = kernel_data.integrator.num_all_lights;
+ lamp_rng_hash = cmj_hash(state->rng_hash, i);
+ double_pdf = kernel_data.integrator.pdf_triangles != 0.0f;
+ }
+ /* mesh light sampling */
+ else {
+ num_samples = ceil_to_int(num_samples_adjust * kernel_data.integrator.mesh_light_samples);
+ double_pdf = kernel_data.integrator.num_all_lights != 0;
+ is_mesh_light = true;
}
}
- /* mesh light sampling */
- if (kernel_data.integrator.pdf_triangles != 0.0f) {
- int num_samples = ceil_to_int(num_samples_adjust *
- kernel_data.integrator.mesh_light_samples);
- float num_samples_inv = num_samples_adjust / num_samples;
+ float num_samples_inv = num_samples_adjust / (num_samples * num_all_lights);
- for (int j = 0; j < num_samples; j++) {
+ for (int j = 0; j < num_samples; j++) {
+ Ray light_ray;
+ light_ray.t = 0.0f; /* reset ray */
+# ifdef __OBJECT_MOTION__
+ light_ray.time = sd->time;
+# endif
+ bool has_emission = false;
+
+ if (kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL)) {
float light_u, light_v;
path_branched_rng_2D(
- kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
+ kg, lamp_rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
float terminate = path_branched_rng_light_termination(
- kg, state->rng_hash, state, j, num_samples);
+ kg, lamp_rng_hash, state, j, num_samples);
/* only sample triangle lights */
- if (kernel_data.integrator.num_all_lights)
+ if (is_mesh_light && double_pdf) {
light_u = 0.5f * light_u;
+ }
LightSample ls;
- if (light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
- /* Same as above, probability needs to be corrected since the sampling was forced to
- * select a mesh light. */
- if (kernel_data.integrator.num_all_lights)
+ const int lamp = is_lamp ? i : -1;
+ if (light_sample(kg, lamp, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+ /* The sampling probability returned by lamp_light_sample assumes that all lights were
+ * sampled. However, this code only samples lamps, so if the scene also had mesh lights,
+ * the real probability is twice as high. */
+ if (double_pdf) {
ls.pdf *= 2.0f;
-
- if (direct_emission(
- kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
- /* trace shadow ray */
- float3 shadow;
-
- if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L,
- state,
- throughput * num_samples_inv,
- &L_light,
- shadow,
- num_samples_inv,
- is_lamp);
- }
- else {
- path_radiance_accum_total_light(L, state, throughput * num_samples_inv, &L_light);
- }
}
+
+ has_emission = direct_emission(
+ kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate);
}
}
- }
- }
- else {
- /* sample one light at random */
- float light_u, light_v;
- path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
- float terminate = path_state_rng_light_termination(kg, state);
- LightSample ls;
- if (light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
- /* sample random light */
- if (direct_emission(
- kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
- /* trace shadow ray */
- float3 shadow;
-
- if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) {
+ /* trace shadow ray */
+ float3 shadow;
+
+ const bool blocked = shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow);
+
+ if (has_emission) {
+ if (!blocked) {
/* accumulate */
- path_radiance_accum_light(L,
- state,
- throughput * num_samples_adjust,
- &L_light,
- shadow,
- num_samples_adjust,
- is_lamp);
+ path_radiance_accum_light(
+ L, state, throughput * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
}
else {
- path_radiance_accum_total_light(L, state, throughput * num_samples_adjust, &L_light);
+ path_radiance_accum_total_light(L, state, throughput * num_samples_inv, &L_light);
}
}
}
@@ -255,45 +215,48 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg,
PROFILING_INIT(kg, PROFILING_CONNECT_LIGHT);
#ifdef __EMISSION__
- if (!(kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL)))
- return;
-
# ifdef __SHADOW_TRICKS__
- if (state->flag & PATH_RAY_SHADOW_CATCHER) {
- kernel_branched_path_surface_connect_light(kg, sd, emission_sd, state, throughput, 1.0f, L, 1);
- return;
- }
-# endif
-
+ int all = (state->flag & PATH_RAY_SHADOW_CATCHER);
+ kernel_branched_path_surface_connect_light(kg, sd, emission_sd, state, throughput, 1.0f, L, all);
+# else
/* sample illumination from lights to find path contribution */
- float light_u, light_v;
- path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
-
Ray light_ray;
BsdfEval L_light;
- bool is_lamp;
+ bool is_lamp = false;
+ bool has_emission = false;
-# ifdef __OBJECT_MOTION__
+ light_ray.t = 0.0f;
+# ifdef __OBJECT_MOTION__
light_ray.time = sd->time;
-# endif
+# endif
- LightSample ls;
- if (light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
- float terminate = path_state_rng_light_termination(kg, state);
- if (direct_emission(
- kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
- /* trace shadow ray */
- float3 shadow;
+ if (kernel_data.integrator.use_direct_light && (sd->flag & SD_BSDF_HAS_EVAL)) {
+ float light_u, light_v;
+ path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
- if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
- }
- else {
- path_radiance_accum_total_light(L, state, throughput, &L_light);
- }
+ LightSample ls;
+ if (light_sample(kg, -1, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+ float terminate = path_state_rng_light_termination(kg, state);
+ has_emission = direct_emission(
+ kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate);
+ }
+ }
+
+ /* trace shadow ray */
+ float3 shadow;
+
+ const bool blocked = shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow);
+
+ if (has_emission) {
+ if (!blocked) {
+ /* accumulate */
+ path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
+ }
+ else {
+ path_radiance_accum_total_light(L, state, throughput, &L_light);
}
}
+# endif
#endif
}
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index 82975c2ad26..6b62005d19a 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -26,34 +26,39 @@ ccl_device_inline void kernel_path_volume_connect_light(KernelGlobals *kg,
PathRadiance *L)
{
# ifdef __EMISSION__
- if (!kernel_data.integrator.use_direct_light)
- return;
-
/* sample illumination from lights to find path contribution */
- float light_u, light_v;
- path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
-
Ray light_ray;
BsdfEval L_light;
- LightSample ls;
- bool is_lamp;
+ bool is_lamp = false;
+ bool has_emission = false;
+ light_ray.t = 0.0f;
+# ifdef __OBJECT_MOTION__
/* connect to light from given point where shader has been evaluated */
light_ray.time = sd->time;
+# endif
- if (light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
- float terminate = path_state_rng_light_termination(kg, state);
- if (direct_emission(
- kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
- /* trace shadow ray */
- float3 shadow;
+ if (kernel_data.integrator.use_direct_light) {
+ float light_u, light_v;
+ path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
- if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
- }
+ LightSample ls;
+ if (light_sample(kg, -1, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+ float terminate = path_state_rng_light_termination(kg, state);
+ has_emission = direct_emission(
+ kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate);
}
}
+
+ /* trace shadow ray */
+ float3 shadow;
+
+ const bool blocked = shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow);
+
+ if (has_emission && !blocked) {
+ /* accumulate */
+ path_radiance_accum_light(L, state, throughput, &L_light, shadow, 1.0f, is_lamp);
+ }
# endif /* __EMISSION__ */
}
@@ -122,7 +127,7 @@ ccl_device_noinline_cpu bool kernel_path_volume_bounce(KernelGlobals *kg,
return true;
}
-# ifndef __SPLIT_KERNEL__
+# if !defined(__SPLIT_KERNEL__) && (defined(__BRANCHED_PATH__) || defined(__VOLUME_DECOUPLED__))
ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
ShaderData *sd,
ShaderData *emission_sd,
@@ -134,96 +139,71 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
const VolumeSegment *segment)
{
# ifdef __EMISSION__
- if (!kernel_data.integrator.use_direct_light)
- return;
-
- Ray light_ray;
BsdfEval L_light;
- bool is_lamp;
-
- light_ray.time = sd->time;
+ int num_lights = 1;
if (sample_all_lights) {
- /* lamp sampling */
- for (int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
- if (UNLIKELY(light_select_reached_max_bounces(kg, i, state->bounce)))
- continue;
-
- int num_samples = light_select_num_samples(kg, i);
- float num_samples_inv = 1.0f / (num_samples * kernel_data.integrator.num_all_lights);
- uint lamp_rng_hash = cmj_hash(state->rng_hash, i);
-
- for (int j = 0; j < num_samples; j++) {
- /* sample random position on given light */
- float light_u, light_v;
- path_branched_rng_2D(
- kg, lamp_rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
-
- LightSample ls;
- lamp_light_sample(kg, i, light_u, light_v, ray->P, &ls);
-
- float3 tp = throughput;
-
- /* sample position on volume segment */
- float rphase = path_branched_rng_1D(
- kg, state->rng_hash, state, j, num_samples, PRNG_PHASE_CHANNEL);
- float rscatter = path_branched_rng_1D(
- kg, state->rng_hash, state, j, num_samples, PRNG_SCATTER_DISTANCE);
-
- VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
- state,
- ray,
- sd,
- &tp,
- rphase,
- rscatter,
- segment,
- (ls.t != FLT_MAX) ? &ls.P :
- NULL,
- false);
+ num_lights = kernel_data.integrator.num_all_lights;
+ if (kernel_data.integrator.pdf_triangles != 0.0f) {
+ num_lights += 1;
+ }
+ }
- /* todo: split up light_sample so we don't have to call it again with new position */
- if (result == VOLUME_PATH_SCATTERED &&
- lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) {
- if (kernel_data.integrator.pdf_triangles != 0.0f)
- ls.pdf *= 2.0f;
-
- float terminate = path_branched_rng_light_termination(
- kg, state->rng_hash, state, j, num_samples);
- if (direct_emission(
- kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
- /* trace shadow ray */
- float3 shadow;
-
- if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(
- L, state, tp * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
- }
- }
+ for (int i = 0; i < num_lights; ++i) {
+ /* sample one light at random */
+ int num_samples = 1;
+ int num_all_lights = 1;
+ uint lamp_rng_hash = state->rng_hash;
+ bool double_pdf = false;
+ bool is_mesh_light = false;
+ bool is_lamp = false;
+
+ if (sample_all_lights) {
+ /* lamp sampling */
+ is_lamp = i < kernel_data.integrator.num_all_lights;
+ if (is_lamp) {
+ if (UNLIKELY(light_select_reached_max_bounces(kg, i, state->bounce))) {
+ continue;
}
+ num_samples = light_select_num_samples(kg, i);
+ num_all_lights = kernel_data.integrator.num_all_lights;
+ lamp_rng_hash = cmj_hash(state->rng_hash, i);
+ double_pdf = kernel_data.integrator.pdf_triangles != 0.0f;
+ }
+ /* mesh light sampling */
+ else {
+ num_samples = kernel_data.integrator.mesh_light_samples;
+ double_pdf = kernel_data.integrator.num_all_lights != 0;
+ is_mesh_light = true;
}
}
- /* mesh light sampling */
- if (kernel_data.integrator.pdf_triangles != 0.0f) {
- int num_samples = kernel_data.integrator.mesh_light_samples;
- float num_samples_inv = 1.0f / num_samples;
+ float num_samples_inv = 1.0f / (num_samples * num_all_lights);
+
+ for (int j = 0; j < num_samples; j++) {
+ Ray light_ray;
+ light_ray.t = 0.0f; /* reset ray */
+# ifdef __OBJECT_MOTION__
+ light_ray.time = sd->time;
+# endif
+ bool has_emission = false;
- for (int j = 0; j < num_samples; j++) {
- /* sample random position on random triangle */
+ float3 tp = throughput;
+
+ if (kernel_data.integrator.use_direct_light) {
+ /* sample random position on random light/triangle */
float light_u, light_v;
path_branched_rng_2D(
- kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
+ kg, lamp_rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
/* only sample triangle lights */
- if (kernel_data.integrator.num_all_lights)
+ if (is_mesh_light && double_pdf) {
light_u = 0.5f * light_u;
+ }
LightSample ls;
- light_sample(kg, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
-
- float3 tp = throughput;
+ const int lamp = is_lamp ? i : -1;
+ light_sample(kg, lamp, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
/* sample position on volume segment */
float rphase = path_branched_rng_1D(
@@ -243,69 +223,31 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
NULL,
false);
- /* todo: split up light_sample so we don't have to call it again with new position */
- if (result == VOLUME_PATH_SCATTERED &&
- light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
- if (kernel_data.integrator.num_all_lights)
- ls.pdf *= 2.0f;
-
- float terminate = path_branched_rng_light_termination(
- kg, state->rng_hash, state, j, num_samples);
- if (direct_emission(
- kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
- /* trace shadow ray */
- float3 shadow;
-
- if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(
- L, state, tp * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
+ if (result == VOLUME_PATH_SCATTERED) {
+ /* todo: split up light_sample so we don't have to call it again with new position */
+ if (light_sample(kg, lamp, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+ if (double_pdf) {
+ ls.pdf *= 2.0f;
}
+
+ /* sample random light */
+ float terminate = path_branched_rng_light_termination(
+ kg, state->rng_hash, state, j, num_samples);
+ has_emission = direct_emission(
+ kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate);
}
}
}
- }
- }
- else {
- /* sample random position on random light */
- float light_u, light_v;
- path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
- LightSample ls;
- light_sample(kg, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
-
- float3 tp = throughput;
-
- /* sample position on volume segment */
- float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL);
- float rscatter = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE);
-
- VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
- state,
- ray,
- sd,
- &tp,
- rphase,
- rscatter,
- segment,
- (ls.t != FLT_MAX) ? &ls.P :
- NULL,
- false);
-
- /* todo: split up light_sample so we don't have to call it again with new position */
- if (result == VOLUME_PATH_SCATTERED &&
- light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
- /* sample random light */
- float terminate = path_state_rng_light_termination(kg, state);
- if (direct_emission(
- kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
- /* trace shadow ray */
- float3 shadow;
-
- if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow)) {
- /* accumulate */
- path_radiance_accum_light(L, state, tp, &L_light, shadow, 1.0f, is_lamp);
- }
+ /* trace shadow ray */
+ float3 shadow;
+
+ const bool blocked = shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow);
+
+ if (has_emission && !blocked) {
+ /* accumulate */
+ path_radiance_accum_light(
+ L, state, tp * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
}
}
}
diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h
index b2ca59d60cc..3be2b35812f 100644
--- a/intern/cycles/kernel/split/kernel_direct_lighting.h
+++ b/intern/cycles/kernel/split/kernel_direct_lighting.h
@@ -86,8 +86,7 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg,
float terminate = path_state_rng_light_termination(kg, state);
LightSample ls;
- if (light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
-
+ if (light_sample(kg, -1, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
Ray light_ray;
light_ray.time = sd->time;