[Bf-blender-cvs] [4030347b118] soc-2022-many-lights-sampling: Fix wrong node energy variance computation

Weizhen Huang noreply at git.blender.org
Tue Oct 18 16:13:31 CEST 2022


Commit: 4030347b1181c99e54b23351e76ae8a943865162
Author: Weizhen Huang
Date:   Tue Oct 18 16:09:22 2022 +0200
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB4030347b1181c99e54b23351e76ae8a943865162

Fix wrong node energy variance computation

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

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

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

diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp
index d8f4125c078..87e26ba2250 100644
--- a/intern/cycles/scene/light_tree.cpp
+++ b/intern/cycles/scene/light_tree.cpp
@@ -225,13 +225,13 @@ float LightTreePrimitive::calculate_energy(Scene *scene) const
   return fabsf(scene->shader_manager->linear_rgb_to_gray(strength));
 }
 
-void LightTreeBuildNode::init_leaf(uint offset,
-                                   uint n,
+void LightTreeBuildNode::init_leaf(const uint &offset,
+                                   const uint &n,
                                    const BoundBox &b,
                                    const OrientationBounds &c,
-                                   float e,
-                                   float e_var,
-                                   uint bits)
+                                   const float &e,
+                                   const float &e_var,
+                                   const uint &bits)
 {
   bbox = b;
   bcone = c;
@@ -245,12 +245,18 @@ void LightTreeBuildNode::init_leaf(uint offset,
   is_leaf = true;
 }
 
-void LightTreeBuildNode::init_interior(LightTreeBuildNode *c0, LightTreeBuildNode *c1, uint bits)
+void LightTreeBuildNode::init_interior(LightTreeBuildNode *c0,
+                                       LightTreeBuildNode *c1,
+                                       const BoundBox &b,
+                                       const OrientationBounds &c,
+                                       const float &e,
+                                       const float &e_var,
+                                       const uint &bits)
 {
-  bbox = merge(c0->bbox, c1->bbox);
-  bcone = merge(c0->bcone, c1->bcone);
-  energy = c0->energy + c1->energy;
-  energy_variance = c0->energy_variance + c1->energy_variance;
+  bbox = b;
+  bcone = c;
+  energy = e;
+  energy_variance = e_var;
   first_prim_index = 0;
   num_lights = 0;
 
@@ -328,13 +334,62 @@ LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &p
     centroid_bounds.grow(prim.centroid);
 
     energy_total += prim.energy;
-    energy_squared_total += prim.energy * prim.energy;
+    energy_squared_total += sqr(prim.energy);
   }
 
   /* Var(X) = E[X^2] - E[X]^2 */
-  float energy_variance = (energy_squared_total / num_prims) -
-                          (energy_total / num_prims) * (energy_total / num_prims);
-  if (num_prims == 1 || len(centroid_bounds.size()) == 0.0f) {
+  float energy_variance = (energy_squared_total / num_prims) - sqr(energy_total / num_prims);
+
+  bool try_splitting = num_prims > 1 && len(centroid_bounds.size()) > 0.0f;
+  int min_dim, min_bucket;
+  bool should_split = false;
+  if (try_splitting) {
+    /* Find the best place to split the primitives into 2 nodes.
+     * If the best split cost is no better than making a leaf node, make a leaf instead.*/
+    float min_cost = min_split_saoh(
+        centroid_bounds, primitive_info, start, end, node_bbox, node_bcone, min_dim, min_bucket);
+    should_split = num_prims > max_lights_in_leaf_ || min_cost < energy_total;
+  }
+  if (should_split) {
+    /* Partition the primitives between start and end into the appropriate split,
+     * based on the minimum dimension and minimum bucket returned from split_saoh.
+     * This is an O(n) algorithm where we iterate from the left and right side,
+     * and swaps the appropriate left and right elements until complete. */
+    int left = start, right = end - 1;
+    float bounding_dimension = (min_bucket + 1) * (centroid_bounds.size()[min_dim] /
+                                                   LightTreeBucketInfo::num_buckets) +
+                               centroid_bounds.min[min_dim];
+    while (left < right) {
+      while (primitive_info[left].centroid[min_dim] <= bounding_dimension && left < end) {
+        left++;
+      }
+
+      while (primitive_info[right].centroid[min_dim] > bounding_dimension && right >= start) {
+        right--;
+      }
+
+      if (left < right) {
+        LightTreePrimitiveInfo temp = primitive_info[left];
+        primitive_info[left] = primitive_info[right];
+        primitive_info[right] = temp;
+      }
+    }
+
+    /* At this point, we should expect right to be just past left,
+     * where left points to the first element that belongs to the right node. */
+    LightTreeBuildNode *left_node = recursive_build(
+        primitive_info, start, left, total_nodes, ordered_prims, bit_trail, depth + 1);
+    LightTreeBuildNode *right_node = recursive_build(primitive_info,
+                                                     left,
+                                                     end,
+                                                     total_nodes,
+                                                     ordered_prims,
+                                                     bit_trail | (1u << depth),
+                                                     depth + 1);
+    node->init_interior(
+        left_node, right_node, node_bbox, node_bcone, energy_total, energy_variance, bit_trail);
+  }
+  else {
     int first_prim_offset = ordered_prims.size();
     for (int i = start; i < end; i++) {
       int prim_num = primitive_info[i].prim_num;
@@ -348,86 +403,17 @@ LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &p
                     energy_variance,
                     bit_trail);
   }
-  else {
-    /* Find the best place to split the primitives into 2 nodes.
-     * If the best split cost is no better than making a leaf node, make a leaf instead.*/
-    float min_cost;
-    int min_dim, min_bucket;
-    split_saoh(centroid_bounds,
-               primitive_info,
-               start,
-               end,
-               node_bbox,
-               node_bcone,
-               min_cost,
-               min_dim,
-               min_bucket);
-    if (num_prims > max_lights_in_leaf_ || min_cost < energy_total) {
-      /* Partition the primitives between start and end into the appropriate split,
-       * based on the minimum dimension and minimum bucket returned from split_saoh.
-       * This is an O(n) algorithm where we iterate from the left and right side,
-       * and swaps the appropriate left and right elements until complete. */
-      int left = start, right = end - 1;
-      float bounding_dimension = (min_bucket + 1) * (centroid_bounds.size()[min_dim] /
-                                                     LightTreeBucketInfo::num_buckets) +
-                                 centroid_bounds.min[min_dim];
-      while (left < right) {
-        while (primitive_info[left].centroid[min_dim] <= bounding_dimension && left < end) {
-          left++;
-        }
-
-        while (primitive_info[right].centroid[min_dim] > bounding_dimension && right >= start) {
-          right--;
-        }
-
-        if (left < right) {
-          LightTreePrimitiveInfo temp = primitive_info[left];
-          primitive_info[left] = primitive_info[right];
-          primitive_info[right] = temp;
-        }
-      }
-
-      /* At this point, we should expect right to be just past left,
-       * where left points to the first element that belongs to the right node. */
-      LightTreeBuildNode *left_node = recursive_build(
-          primitive_info, start, left, total_nodes, ordered_prims, bit_trail, depth + 1);
-      LightTreeBuildNode *right_node = recursive_build(primitive_info,
-                                                       left,
-                                                       end,
-                                                       total_nodes,
-                                                       ordered_prims,
-                                                       bit_trail | (1u << depth),
-                                                       depth + 1);
-      node->init_interior(left_node, right_node, bit_trail);
-    }
-    else {
-      int first_prim_offset = ordered_prims.size();
-      for (int i = start; i < end; i++) {
-        int prim_num = primitive_info[i].prim_num;
-        ordered_prims.push_back(prims_[prim_num]);
-      }
-      node->init_leaf(first_prim_offset,
-                      num_prims,
-                      node_bbox,
-                      node_bcone,
-                      energy_total,
-                      energy_variance,
-                      bit_trail);
-    }
-  }
-
   return node;
 }
 
-void LightTree::split_saoh(const BoundBox &centroid_bbox,
-                           const vector<LightTreePrimitiveInfo> &primitive_info,
-                           int start,
-                           int end,
-                           const BoundBox &bbox,
-                           const OrientationBounds &bcone,
-                           float &min_cost,
-                           int &min_dim,
-                           int &min_bucket)
+float LightTree::min_split_saoh(const BoundBox &centroid_bbox,
+                                const vector<LightTreePrimitiveInfo> &primitive_info,
+                                int start,
+                                int end,
+                                const BoundBox &bbox,
+                                const OrientationBounds &bcone,
+                                int &min_dim,
+                                int &min_bucket)
 {
   /* Even though this factor is used for every bucket, we use it to compare
    * the min_cost and total_energy (when deciding between creating a leaf or interior node. */
@@ -436,7 +422,7 @@ void LightTree::split_saoh(const BoundBox &centroid_bbox,
   const float max_extent = max4(extent.x, extent.y, extent.z, 0.0f);
 
   /* Check each dimension to find the minimum splitting cost. */
-  min_cost = FLT_MAX;
+  float min_cost = FLT_MAX;
   for (int dim = 0; dim < 3; dim++) {
     /* If the centroid bounding box is 0 along a given dimension, skip it. */
     if (centroid_bbox.size()[dim] == 0.0f) {
@@ -508,6 +494,7 @@ void LightTree::split_saoh(const BoundBox &centroid_bbox,
       }
     }
   }
+  return min_cost;
 }
 
 int LightTree::flatten_tree(const LightTreeBuildNode *node, int &offset, int parent)
diff --git a/intern/cycles/scene/light_tree.h b/intern/cycl

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list