[Bf-blender-cvs] [990bbab47ba] soc-2022-many-lights-sampling: Fix PDF calculation when splitting is enabled

Alaska noreply at git.blender.org
Fri Oct 7 16:16:25 CEST 2022


Commit: 990bbab47ba72ca69efa295804f921ae87a3ef53
Author: Alaska
Date:   Fri Oct 7 13:54:39 2022 +0200
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB990bbab47ba72ca69efa295804f921ae87a3ef53

Fix PDF calculation when splitting is enabled

Previously the PDF calculation while splitting and considering MIS was incorrect.
If we reached a node that did not meet the criteria to split,  then the PDF calculation would resort to following the bit trail to the target leaf as if the current node was the root node. If the light tree split at least once, then this approach was almost always going to be incorrect.
Along with this, we also want to traverse through the light tree until we reach a random leaf under certain circumstances. The previous code did not have anything in place for this which also lead to some incorrect results.

In this patch, I attempted to fix both of these issues by doing these things when we encounter a node that does not meet the criteria to split:
1. Follow the bit trail starting from the position of the current node, rather than following the bit trail from the root node when we're in fact starting from a different node.
2. Guarantee that the current node is along the path of the bit trail before following the path of the bit trail.
3. And if the current node is not along the path, then we traverse down the tree to a random leaf node.

Differential Revision: https://developer.blender.org/D15983

===================================================================

M	intern/cycles/kernel/light/light_tree.h
M	intern/cycles/scene/light_tree.cpp
M	intern/cycles/scene/light_tree.h

===================================================================

diff --git a/intern/cycles/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h
index e8093321891..f78351b0e41 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -315,9 +315,6 @@ ccl_device bool light_tree_sample(KernelGlobals kg,
   stack[0] = 0;
   pdfs_node_selection[0] = 1.0f;
 
-  /* For now, we arbitrarily limit splitting to 8 so that it doesn't continuously split. */
-  int split_count = 0;
-
   /* First traverse the light tree until a leaf node is reached.
    * Also keep track of the probability of traversing to a given node,
    * so that we can scale our PDF accordingly later. */
@@ -372,13 +369,12 @@ ccl_device bool light_tree_sample(KernelGlobals kg,
      * We adaptively split if the variance is high enough. */
     const int left_index = index + 1;
     const int right_index = knode->child_index;
-    if (light_tree_should_split(kg, P, knode) && split_count < 8 && stack_index < stack_size - 1) {
+    if (light_tree_should_split(kg, P, knode) && stack_index < stack_size - 1) {
       stack[stack_index] = left_index;
       pdfs_node_selection[stack_index] = pdf_node_selection;
       stack[stack_index + 1] = right_index;
       pdfs_node_selection[stack_index + 1] = pdf_node_selection;
       stack_index++;
-      split_count++;
       continue;
     }
 
@@ -579,22 +575,24 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
    * find the probability of selecting the target light. */
   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;
 
-  int split_count = 0;
-
   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 int index = stack[stack_index];
+    const int depth = tree_depth[stack_index];
     const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, index);
 
     if (knode->child_index <= 0) {
@@ -651,17 +649,21 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
      * We adaptively split if the variance is high enough. */
     const int left_index = index + 1;
     const int right_index = knode->child_index;
-    if (light_tree_should_split(kg, P, knode) && split_count < 8 && stack_index < stack_size - 1) {
+    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;
       stack_index++;
-      split_count++;
       continue;
     }
 
-    /* If we don't split, the bit trail determines whether we go left or right. */
+    /* 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. */
+
     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);
@@ -677,15 +679,36 @@ ccl_device float light_tree_pdf(KernelGlobals kg,
     }
     float left_probability = left_importance / (left_importance + right_importance);
 
-    if (bit_trail & 1) {
-      stack[stack_index] = right_index;
-      pdfs[stack_index] = pdf * (1.0f - left_probability);
+    /* 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;
+      }
     }
     else {
-      stack[stack_index] = left_index;
-      pdfs[stack_index] = pdf * left_probability;
+      if (randu <= left_probability) {
+        stack[stack_index] = left_index;
+        randu = randu / left_probability;
+        pdfs[stack_index] = pdf * left_probability;
+      }
+      else {
+        stack[stack_index] = right_index;
+        randu = (randu - left_probability) / (1.0f - left_probability);
+        pdfs[stack_index] = pdf * (1.0f - left_probability);
+      }
     }
-    bit_trail = bit_trail >> 1;
+    tree_depth[stack_index] = depth + 1;
   }
 
   pdf *= light_leaf_pdf * light_tree_pdf * target_weight / total_weight;
diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp
index fc11d93a080..d8f4125c078 100644
--- a/intern/cycles/scene/light_tree.cpp
+++ b/intern/cycles/scene/light_tree.cpp
@@ -245,7 +245,7 @@ void LightTreeBuildNode::init_leaf(uint offset,
   is_leaf = true;
 }
 
-void LightTreeBuildNode::init_interior(LightTreeBuildNode *c0, LightTreeBuildNode *c1)
+void LightTreeBuildNode::init_interior(LightTreeBuildNode *c0, LightTreeBuildNode *c1, uint bits)
 {
   bbox = merge(c0->bbox, c1->bbox);
   bcone = merge(c0->bcone, c1->bcone);
@@ -256,6 +256,7 @@ void LightTreeBuildNode::init_interior(LightTreeBuildNode *c0, LightTreeBuildNod
 
   children[0] = c0;
   children[1] = c1;
+  bit_trail = bits;
   is_leaf = false;
 }
 
@@ -397,7 +398,7 @@ LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &p
                                                        ordered_prims,
                                                        bit_trail | (1u << depth),
                                                        depth + 1);
-      node->init_interior(left_node, right_node);
+      node->init_interior(left_node, right_node, bit_trail);
     }
     else {
       int first_prim_offset = ordered_prims.size();
@@ -516,6 +517,7 @@ int LightTree::flatten_tree(const LightTreeBuildNode *node, int &offset, int par
   current_node->bcone = node->bcone;
   current_node->energy = node->energy;
   current_node->energy_variance = node->energy_variance;
+  current_node->bit_trail = node->bit_trail;
   int current_index = offset;
   offset++;
 
@@ -524,7 +526,6 @@ int LightTree::flatten_tree(const LightTreeBuildNode *node, int &offset, int par
   if (node->num_lights > 0) {
     current_node->first_prim_index = node->first_prim_index;
     current_node->num_lights = node->num_lights;
-    current_node->bit_trail = node->bit_trail;
     current_node->is_leaf_node = true;
   }
   else {
diff --git a/intern/cycles/scene/light_tree.h b/intern/cycles/scene/light_tree.h
index 3243985814a..ed4943d028f 100644
--- a/intern/cycles/scene/light_tree.h
+++ b/intern/cycles/scene/light_tree.h
@@ -119,7 +119,7 @@ struct LightTreeBuildNode {
                  float e,
                  float e_var,
                  uint bits);
-  void init_interior(LightTreeBuildNode *c0, LightTreeBuildNode *c1);
+  void init_interior(LightTreeBuildNode *c0, LightTreeBuildNode *c1, uint bits);
 };
 
 /* Packed Light Tree Node



More information about the Bf-blender-cvs mailing list