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:
authorSam Kottler <dev@samkottler.net>2020-08-04 23:15:52 +0300
committerSam Kottler <dev@samkottler.net>2020-08-04 23:15:52 +0300
commit8d20d9d9eea981884bf1a2ee7de032391954ffaf (patch)
treedf887a542ce91e45977e2ba61414b74a3c10eeaf
parent3fa449a448d49e2c81a43d90b3880262e144eb2f (diff)
Initial attempt at splitting for volumes.soc-2020-production-ready-light-tree
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h510
1 files changed, 408 insertions, 102 deletions
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index 83e1019a2f2..1b9a8006382 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -137,6 +137,212 @@ ccl_device_noinline_cpu bool kernel_path_volume_bounce(KernelGlobals *kg,
}
# if !defined(__SPLIT_KERNEL__) && (defined(__BRANCHED_PATH__) || defined(__VOLUME_DECOUPLED__))
+ccl_device void accum_light_tree_contribution_volume(KernelGlobals *kg,
+ float randu,
+ float randv,
+ int offset,
+ float pdf_factor,
+ bool can_split,
+ float3 throughput,
+ float scale_factor,
+ PathRadiance *L,
+ ccl_addr_space PathState *state,
+ ShaderData *sd,
+ ShaderData *emission_sd,
+ Ray *ray,
+ const VolumeSegment *segment)
+{
+ float3 P = sd->P_pick;
+ float3 N = sd->N_pick;
+ float t = sd->t_pick;
+
+ float time = sd->time;
+ int bounce = state->bounce;
+
+ float randu_stack[64];
+ float randv_stack[64];
+ int offset_stack[64];
+ float pdf_stack[64];
+
+ randu_stack[0] = randu;
+ randv_stack[0] = randv;
+ offset_stack[0] = offset;
+ pdf_stack[0] = pdf_factor;
+
+ int stack_idx = 0;
+
+ while (stack_idx > -1) {
+ randu = randu_stack[stack_idx];
+ randv = randv_stack[stack_idx];
+ offset = offset_stack[stack_idx];
+ pdf_factor = pdf_stack[stack_idx];
+ /* read in first part of node of light tree */
+ int right_child_offset, distribution_id, num_emitters;
+ update_node(kg, offset, &right_child_offset, &distribution_id, &num_emitters);
+
+ /* found a leaf */
+ if (right_child_offset == -1) {
+
+ /* if there are several emitters in this leaf then pick one of them */
+ if (num_emitters > 1) {
+
+ /* create and sample CDF without dynamic allocation.
+ * see comment in light_tree_sample() for this piece of code */
+ float sum = 0.0f;
+ for (int i = 0; i < num_emitters; ++i) {
+ sum += calc_light_importance(kg, t, P, N, offset, i);
+ }
+
+ if (sum == 0.0f) {
+ --stack_idx;
+ continue;
+ }
+
+ float sum_inv = 1.0f / sum;
+ float cdf_L = 0.0f;
+ float cdf_R = 0.0f;
+ float prob = 0.0f;
+ int light = num_emitters - 1;
+ for (int i = 1; i < num_emitters + 1; ++i) {
+ prob = calc_light_importance(kg, t, P, N, offset, i - 1) * sum_inv;
+ cdf_R = cdf_L + prob;
+ if (randu < cdf_R) {
+ light = i - 1;
+ break;
+ }
+
+ cdf_L = cdf_R;
+ }
+ distribution_id += light;
+ pdf_factor *= prob;
+
+ /* rescale random number */
+ randu = (randu - cdf_L) / (cdf_R - cdf_L);
+ }
+
+ /* pick a point on the chosen light(distribution_id) and calculate the
+ * probability of picking this point */
+ LightSample ls;
+ light_point_sample(kg, -1, randu, randv, time, P, bounce, distribution_id, &ls);
+
+ /* combine pdfs */
+ ls.pdf *= pdf_factor;
+
+ /* compute and accumulate the total contribution of this light */
+ Ray light_ray;
+ light_ray.t = 0.0f;
+# ifdef __OBJECT_MOTION__
+ light_ray.time = sd->time;
+# endif
+ float3 tp = throughput;
+ bool has_emission = false;
+ bool is_lamp = false;
+ BsdfEval L_light ccl_optional_struct_init;
+ /* sample position on volume segment */
+ float rphase = path_branched_rng_1D(
+ kg, state->rng_hash, state, distribution_id, 1.0f, PRNG_PHASE_CHANNEL);
+ float rscatter = path_branched_rng_1D(
+ kg, state->rng_hash, state, distribution_id, 1.0f, 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);
+ if (result == VOLUME_PATH_SCATTERED) {
+ light_point_sample(kg, -1, randu, randv, time, sd->P_pick, bounce, distribution_id, &ls);
+ if (ls.pdf <= 0.0f) {
+ --stack_idx;
+ continue;
+ }
+ /* sample random light */
+ float terminate = path_branched_rng_light_termination(
+ kg, state->rng_hash, state, distribution_id, 1.0f);
+ 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(kg, L, state, tp, &L_light, shadow, 1.0f, is_lamp);
+ }
+
+ --stack_idx;
+ can_split = true;
+ continue;
+ }
+ else { // Interior node, choose which child(ren) to go down
+
+ int child_offsetL = offset + 4;
+ int child_offsetR = 4 * right_child_offset;
+
+ /* choose whether to go down both(split) or only one of the children */
+ if (can_split && split(kg, P, offset)) {
+ /* go down both child nodes */
+ //++stack_idx;
+ randu_stack[stack_idx] = randu;
+ randv_stack[stack_idx] = randv;
+ offset_stack[stack_idx] = child_offsetL;
+ pdf_stack[stack_idx] = pdf_factor;
+
+ ++stack_idx;
+ randu_stack[stack_idx] = randu;
+ randv_stack[stack_idx] = randv;
+ offset_stack[stack_idx] = child_offsetR;
+ pdf_stack[stack_idx] = pdf_factor;
+ }
+ else {
+ /* go down one of the child nodes */
+
+ /* evaluate the importance of each of the child nodes */
+ float I_L = calc_node_importance(kg, t, P, N, child_offsetL);
+ float I_R = calc_node_importance(kg, t, P, N, child_offsetR);
+
+ if ((I_L == 0.0f) && (I_R == 0.0f)) {
+ return;
+ }
+
+ /* calculate the probability of going down the left node */
+ float P_L = I_L / (I_L + I_R);
+
+ /* choose which node to go down */
+ if (randu <= P_L) { // Going down left node
+ /* rescale random number */
+ randu = randu / P_L;
+
+ offset = child_offsetL;
+ pdf_factor *= P_L;
+ }
+ else { // Going down right node
+ /* rescale random number */
+ randu = (randu * (I_L + I_R) - I_L) / I_R;
+
+ offset = child_offsetR;
+ pdf_factor *= 1.0f - P_L;
+ }
+
+ //++stack_idx;
+ can_split = false;
+ randu_stack[stack_idx] = randu;
+ randv_stack[stack_idx] = randv;
+ offset_stack[stack_idx] = offset;
+ pdf_stack[stack_idx] = pdf_factor;
+ }
+ }
+ }
+}
+
ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
ShaderData *sd,
ShaderData *emission_sd,
@@ -151,127 +357,227 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg,
BsdfEval L_light ccl_optional_struct_init;
bool use_light_tree = kernel_data.integrator.use_light_tree;
- int num_lights = 1;
- if (sample_all_lights && !use_light_tree) {
- num_lights = kernel_data.integrator.num_all_lights;
- if (kernel_data.integrator.pdf_triangles != 0.0f) {
- num_lights += 1;
+ if (use_light_tree) {
+ Ray light_ray;
+ bool is_lamp;
+
+ light_ray.t = 0.0f;
+# ifdef __OBJECT_MOTION__
+ light_ray.time = sd->time;
+# endif
+
+ int index;
+ float randu, randv;
+ path_state_rng_2D(kg, state, PRNG_LIGHT_U, &randu, &randv);
+
+ /* sample light group distribution */
+ int group = light_group_distribution_sample(kg, &randu);
+ float group_prob = kernel_tex_fetch(__light_group_sample_prob, group);
+ float pdf = 1.0f;
+
+ if (group == LIGHTGROUP_TREE) {
+ /* accumulate contribution to L from potentially several lights */
+ accum_light_tree_contribution_volume(kg,
+ randu,
+ randv,
+ 0,
+ group_prob,
+ true,
+ throughput,
+ 1.0f,
+ L, // todo: is num_samples_adjust correct here?
+ state,
+ sd,
+ emission_sd,
+ ray,
+ segment);
+
+ /* have accumulated all the contributions so return */
+ return;
+ }
+ else if (group == LIGHTGROUP_DISTANT) {
+ /* pick a single distant light */
+ light_distant_sample(kg, sd->P, &randu, &index, &pdf);
+ }
+ else if (group == LIGHTGROUP_BACKGROUND) {
+ /* pick a single background light */
+ light_background_sample(kg, sd->P, &randu, &index, &pdf);
+ }
+ else {
+ kernel_assert(false);
+ }
+
+ /* sample a point on the given distant/background light */
+ LightSample ls;
+ light_point_sample(kg, -1, randu, randv, sd->time, sd->P, state->bounce, index, &ls);
+
+ /* combine pdfs */
+ ls.pdf *= group_prob;
+
+ if (ls.pdf <= 0.0f)
+ return;
+
+ float3 tp = throughput;
+ bool has_emission = false;
+ /* sample position on volume segment */
+ float rphase = path_branched_rng_1D(
+ kg, state->rng_hash, state, index, 1.0f, PRNG_PHASE_CHANNEL);
+ float rscatter = path_branched_rng_1D(
+ kg, state->rng_hash, state, index, 1.0f, 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);
+ if (result == VOLUME_PATH_SCATTERED) {
+ light_point_sample(kg, -1, randu, randv, sd->time, sd->P_pick, state->bounce, index, &ls);
+ /* sample random light */
+ float terminate = path_branched_rng_light_termination(
+ kg, state->rng_hash, state, index, 1.0f);
+ has_emission = direct_emission(
+ kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate);
}
- }
- for (int i = 0; i < num_lights; ++i) {
- /* sample one light at random */
- int num_samples = 1;
- uint lamp_rng_hash = state->rng_hash;
- bool double_pdf = false;
- bool is_mesh_light = false;
- bool is_lamp = false;
+ /* 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(kg, L, state, tp, &L_light, shadow, 1.0f, is_lamp);
+ }
+ }
+ else {
+ int num_lights = 1;
if (sample_all_lights && !use_light_tree) {
- /* 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;
- }
- 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;
+ num_lights = kernel_data.integrator.num_all_lights;
+ if (kernel_data.integrator.pdf_triangles != 0.0f) {
+ num_lights += 1;
}
}
+ for (int i = 0; i < num_lights; ++i) {
+ /* sample one light at random */
+ int num_samples = 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 && !use_light_tree) {
+ /* 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;
+ }
+ 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;
+ }
+ }
- float num_samples_inv = 1.0f / num_samples;
+ float num_samples_inv = 1.0f / num_samples;
- for (int j = 0; j < num_samples; j++) {
- Ray light_ray ccl_optional_struct_init;
- light_ray.t = 0.0f; /* reset ray */
+ for (int j = 0; j < num_samples; j++) {
+ Ray light_ray ccl_optional_struct_init;
+ light_ray.t = 0.0f; /* reset ray */
# ifdef __OBJECT_MOTION__
- light_ray.time = sd->time;
+ light_ray.time = sd->time;
# endif
- bool has_emission = false;
+ bool has_emission = false;
- float3 tp = throughput;
+ 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, lamp_rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
+ if (kernel_data.integrator.use_direct_light) {
+ /* sample random position on random light/triangle */
+ float light_u, light_v;
+ path_branched_rng_2D(
+ kg, lamp_rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
- /* only sample triangle lights */
- if (is_mesh_light && double_pdf) {
- light_u = 0.5f * light_u;
- }
+ /* only sample triangle lights */
+ if (is_mesh_light && double_pdf) {
+ light_u = 0.5f * light_u;
+ }
- LightSample ls ccl_optional_struct_init;
- const int lamp = is_lamp ? i : -1;
- light_sample(kg,
- lamp,
- light_u,
- light_v,
- sd->time,
- sd->P_pick,
- sd->N_pick,
- sd->t_pick,
- state->bounce,
- &ls);
-
- /* 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);
-
- 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_pick,
- sd->N_pick,
- -1.0,
- state->bounce,
- &ls)) {
- if (double_pdf) {
- ls.pdf *= 2.0f;
+ LightSample ls ccl_optional_struct_init;
+ const int lamp = is_lamp ? i : -1;
+ light_sample(kg,
+ lamp,
+ light_u,
+ light_v,
+ sd->time,
+ sd->P_pick,
+ sd->N_pick,
+ sd->t_pick,
+ state->bounce,
+ &ls);
+
+ /* 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);
+
+ 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_pick,
+ sd->N_pick,
+ -1.0,
+ 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);
}
-
- /* 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);
}
}
- }
- /* trace shadow ray */
- float3 shadow;
+ /* trace shadow ray */
+ float3 shadow;
- const bool blocked = shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow);
+ const bool blocked = shadow_blocked(kg, sd, emission_sd, state, &light_ray, &shadow);
- if (has_emission && !blocked) {
- /* accumulate */
- path_radiance_accum_light(
- kg, L, state, tp * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
+ if (has_emission && !blocked) {
+ /* accumulate */
+ path_radiance_accum_light(
+ kg, L, state, tp * num_samples_inv, &L_light, shadow, num_samples_inv, is_lamp);
+ }
}
}
}