[Bf-blender-cvs] [034924c1ee7] soc-2022-many-lights-sampling: Returns conditioned light_tree_pdf for MIS, consistent with light_tree_sample
Weizhen Huang
noreply at git.blender.org
Thu Oct 13 21:05:36 CEST 2022
Commit: 034924c1ee7942fe11946095e051dbbb5101a7fa
Author: Weizhen Huang
Date: Thu Oct 13 20:45:22 2022 +0200
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB034924c1ee7942fe11946095e051dbbb5101a7fa
Returns conditioned light_tree_pdf for MIS, consistent with light_tree_sample
===================================================================
M intern/cycles/kernel/light/light_tree.h
===================================================================
diff --git a/intern/cycles/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h
index bdbdd94e892..76c98de4759 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -560,7 +560,8 @@ ccl_device bool light_tree_sample_distant_lights(KernelGlobals kg,
return -1;
}
-/* We need to be able to find the probability of selecting a given light for MIS. */
+/* We need to be able to find the probability of selecting a given light for MIS.
+ * Returns a conditioned pdf which is consistent with the pdf computed in `light_tree_sample()` */
ccl_device float light_tree_pdf(KernelGlobals kg,
ConstIntegratorState state,
const float3 P,
@@ -589,46 +590,44 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
const int target_leaf = kemitter->parent_index;
ccl_global const KernelLightTreeNode *kleaf = &kernel_data_fetch(light_tree_nodes, target_leaf);
+ uint bit_trail = kleaf->bit_trail;
+
/* We generate a random number to use for selecting a light. */
RNGState rng_state;
path_state_rng_load(state, &rng_state);
/* to-do: is this the correct macro to use? */
float randu = path_state_rng_1D(kg, &rng_state, PRNG_LIGHT);
- /* We traverse to the leaf node and
- * find the probability of selecting the target light. */
+ /* Keep track of the currently selected primitive and its weight,
+ * as well as the total weight as part of the weighted reservoir sampling. */
+ int selected_light = -1;
+ float selected_reservoir_weight = -1.0f;
+ float total_reservoir_weight = 0.0f;
+
+ /* We need a stack to substitute for recursion. */
const int stack_size = 32;
int stack[stack_size];
- int tree_depth[stack_size];
- float pdfs[stack_size];
int stack_index = 0;
stack[0] = 0;
- tree_depth[0] = 0;
- pdfs[0] = 1.0f;
-
- float light_tree_pdf = 0.0f;
- float light_leaf_pdf = 0.0f;
- float total_weight = 0.0f;
- float target_weight = 0.0f;
- uint bit_trail_mask = 0;
- uint bit_trail = kleaf->bit_trail;
while (stack_index >= 0) {
- const float pdf = pdfs[stack_index];
+ const bool traversing_target_branch = stack_index == 0;
const int index = stack[stack_index];
- const int depth = tree_depth[stack_index];
const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, index);
+ /* TODO: interior nodes are processed before leaf nodes, but current implementation forces the
+ * reader to think about the leaf node first. Maybe switch the two if-branches for better
+ * understandability? */
+
+ /* Leaf node */
if (knode->child_index <= 0) {
- int selected_light = -1;
- float light_weight = 0.0f;
- /* If we're at the leaf node containing the light we need,
- * then we iterate through the lights to find the target emitter.
+ float pdf_emitter_selection = 1.0f;
+
+ /* If the leaf node contains the target emitter, we are processing the last node.
+ * We then iterate through the lights to find the target emitter.
* Otherwise, we randomly select one. */
if (index == target_leaf) {
- light_tree_pdf = pdf;
-
float target_emitter_importance = 0.0f;
float total_emitter_importance = 0.0f;
for (int i = 0; i < knode->num_prims; i++) {
@@ -636,58 +635,47 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
float light_importance = light_tree_emitter_importance(
kg, P, N, has_transmission, leaf_emitter);
if (leaf_emitter == emitter) {
- selected_light = leaf_emitter;
- light_weight = light_tree_emitter_reservoir_weight(kg, P, N, selected_light);
- target_weight = light_weight;
target_emitter_importance = light_importance;
+ selected_light = leaf_emitter;
+ selected_reservoir_weight = light_tree_emitter_reservoir_weight(
+ kg, P, N, selected_light);
+ total_reservoir_weight += selected_reservoir_weight;
}
total_emitter_importance += light_importance;
}
-
- light_leaf_pdf = target_emitter_importance / total_emitter_importance;
+ pdf_emitter_selection = target_emitter_importance / total_emitter_importance;
+ const float pdf_reservoir = selected_reservoir_weight / total_reservoir_weight;
+ pdf *= pdf_emitter_selection * pdf_reservoir;
}
else {
- float light_probability = 1.0f;
selected_light = light_tree_cluster_select_emitter(
- kg, &randu, P, N, has_transmission, knode, &light_probability);
- light_weight = light_tree_emitter_reservoir_weight(kg, P, N, selected_light);
- }
+ kg, &randu, P, N, has_transmission, knode, &pdf_emitter_selection);
- if (selected_light < 0) {
- stack_index--;
- continue;
- }
+ if (selected_light < 0) {
+ stack_index--;
+ continue;
+ }
- if (light_weight == 0.0f) {
- stack_index--;
- continue;
+ total_reservoir_weight += light_tree_emitter_reservoir_weight(kg, P, N, selected_light);
}
- total_weight += light_weight;
-
stack_index--;
continue;
}
- /* At an interior node, the left child is directly after the parent,
- * while the right child is stored as the child index.
- * We adaptively split if the variance is high enough. */
+ /* Interior node */
+ const bool go_left = (bit_trail & 1) == 0;
+ bit_trail >>= traversing_target_branch;
const int left_index = index + 1;
const int right_index = knode->child_index;
if (light_tree_should_split(kg, P, knode) && stack_index < stack_size - 1) {
- stack[stack_index] = left_index;
- tree_depth[stack_index] = depth + 1;
- pdfs[stack_index] = pdf;
- stack[stack_index + 1] = right_index;
- tree_depth[stack_index + 1] = depth + 1;
- pdfs[stack_index + 1] = pdf;
+ /* Always store nodes on the target branch in stack[0] */
+ stack[stack_index] = go_left ? left_index : right_index;
stack_index++;
+ stack[stack_index] = go_left ? right_index : left_index;
continue;
}
- /* If we don't split, and the bit trail to the current node is identical to the bit trail to
- the target leaf up to the given depth, then we continue traversing down the path towards the
- target leaf, otherwise we pick a random branch. */
-
+ /* No splitting, choose between the left or the right child */
const ccl_global KernelLightTreeNode *left = &kernel_data_fetch(light_tree_nodes, left_index);
const ccl_global KernelLightTreeNode *right = &kernel_data_fetch(light_tree_nodes,
right_index);
@@ -703,39 +691,21 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
}
float left_probability = left_importance / (left_importance + right_importance);
- /* TODO: using both the bit trail and an estimator for the pdf may be wrong,
- * but so far seemed to converge to the correct result. Needs to be revisited. */
- bit_trail_mask = 0;
- for (int i = 0; i < depth; i++) {
- bit_trail_mask = bit_trail_mask | (1U << i);
- }
-
- if (((bit_trail & bit_trail_mask) == knode->bit_trail)) {
- if ((bit_trail >> depth) & 1) {
- stack[stack_index] = right_index;
- pdfs[stack_index] = pdf * (1.0f - left_probability);
- }
- else {
- stack[stack_index] = left_index;
- pdfs[stack_index] = pdf * left_probability;
- }
+ if (traversing_target_branch) {
+ pdf *= go_left ? left_probability : (1.0f - left_probability);
+ stack[stack_index] = go_left ? left_index : right_index;
}
else {
- if (randu <= left_probability) {
+ if (randu <= left_probability) { /* traverse left */
stack[stack_index] = left_index;
randu = randu / left_probability;
- pdfs[stack_index] = pdf * left_probability;
}
- else {
+ else { /* traverse right */
stack[stack_index] = right_index;
randu = (randu - left_probability) / (1.0f - left_probability);
- pdfs[stack_index] = pdf * (1.0f - left_probability);
}
}
- tree_depth[stack_index] = depth + 1;
}
-
- pdf *= light_leaf_pdf * light_tree_pdf * target_weight / total_weight;
return pdf;
}
More information about the Bf-blender-cvs
mailing list