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

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
List details, subscription details or unsubscribe:
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to