[Bf-blender-cvs] [59fffd32626] soc-2022-many-lights-sampling: Fix: Cycles light tree construction/traversal bugs

Jeffrey Liu noreply at git.blender.org
Sat Jun 18 10:01:55 CEST 2022


Commit: 59fffd326262122d291829188a3ec75f04c53980
Author: Jeffrey Liu
Date:   Sat Jun 18 04:01:50 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB59fffd326262122d291829188a3ec75f04c53980

Fix: Cycles light tree construction/traversal bugs

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

M	intern/cycles/kernel/light/light_tree.h
M	intern/cycles/scene/light.cpp
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 7cff13b7c97..87c49ebc30c 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -21,7 +21,7 @@ ccl_device float light_tree_bounding_box_angle(const float3 bbox_min,
   corners[6] = make_float3(bbox_max.x, bbox_max.y, bbox_min.z);
   corners[7] = bbox_max;
   for (int i = 0; i < 8; ++i) {
-    float3 point_to_corner = normalize(P - corners[i]);
+    float3 point_to_corner = normalize(corners[i] - P);
     const float cos_theta_u = dot(point_to_centroid, point_to_corner);
     theta_u = fmaxf(fast_acosf(cos_theta_u), theta_u);
   }
@@ -41,9 +41,12 @@ ccl_device float light_tree_node_importance(const float3 P,
                                             const float energy)
 {
   const float3 centroid = 0.5f * bbox_min + 0.5f * bbox_max;
-  const float3 point_to_centroid = normalize(P - centroid);
+  const float3 point_to_centroid = normalize(centroid - P);
 
-  const float distance_squared = len_squared(P - centroid);
+  /* Since we're not using the splitting heuristic, we clamp
+   * the distance to half the radius of the cluster. */
+  const float distance_squared = fminf(len_squared(centroid - P),
+                                       0.25f * len_squared(bbox_max - centroid));
 
   const float theta = fast_acosf(dot(bcone_axis, -point_to_centroid));
   const float theta_i = fast_acosf(dot(point_to_centroid, N));
@@ -51,17 +54,15 @@ ccl_device float light_tree_node_importance(const float3 P,
 
   /* to-do: compare this with directly using fmaxf and cosf. */
   /* Avoid using cosine until needed. */
-  const float theta_prime = fmaxf(theta_i - theta_u, 0);
-  /* to-do: this is also a rough heuristic to see if any contribution is possible.
-   * In the paper, this is only theta_e, but this seems to be off for point lights. */
-  if (theta_prime >= theta_o + theta_e) {
+  const float theta_prime = fmaxf(theta - theta_o - theta_u, 0);
+  if (theta_prime >= theta_e) {
     return 0;
   }
-  const float cos_theta_prime = cosf(theta_prime);
+  const float cos_theta_prime = fast_cosf(theta_prime);
 
   float cos_theta_i_prime = 1;
-  if (theta - theta_o - theta_u > 0) {
-    cos_theta_i_prime = fabsf(cosf(theta - theta_o - theta_u));
+  if (theta_i - theta_u > 0) {
+    cos_theta_i_prime = fabsf(fast_cosf(theta_i - theta_u));
   }
 
   /* to-do: find a good approximation for this value. */
@@ -160,11 +161,16 @@ ccl_device bool light_tree_sample(KernelGlobals kg,
     const float left_probability = left_importance / (left_importance + right_importance);
 
     if (tree_u < left_probability) {
+      index = index + 1;
       knode = left;
+      tree_u = tree_u * (left_importance + right_importance) / left_importance;
       *pdf_factor *= left_probability;
     }
     else {
+      index = knode->child_index;
       knode = right;
+      tree_u = (tree_u * (left_importance + right_importance) - left_importance) /
+               right_importance;
       *pdf_factor *= (1 - left_probability);
     }
   }
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 86a235815c7..aa04bf4986c 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -352,6 +352,7 @@ void LightManager::device_update_distribution(Device *,
     for (int index = 0; index < linearized_bvh.size(); index++) {
       const PackedLightTreeNode &node = linearized_bvh[index];
 
+      light_tree_nodes[index].energy = node.energy;
       for (int i = 0; i < 3; i++) {
         light_tree_nodes[index].bounding_box_min[i] = node.bbox.min[i];
         light_tree_nodes[index].bounding_box_max[i] = node.bbox.max[i];
@@ -536,6 +537,7 @@ void LightManager::device_update_distribution(Device *,
      * the light has been sampled through the light distribution.
      * Therefore, we override it for now and adjust the pdf manually in the light tree.*/
     if (scene->integrator->get_use_light_tree()) {
+      kintegrator->pdf_triangles = 1.0f;
       kintegrator->pdf_lights = 1.0f;
     }
     else {
diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp
index 35c3d11104e..d50f257e6c7 100644
--- a/intern/cycles/scene/light_tree.cpp
+++ b/intern/cycles/scene/light_tree.cpp
@@ -37,9 +37,9 @@ OrientationBounds merge(const OrientationBounds& cone_a,
   }
   else {
     /* Compute new theta_o that contains both a and b. */
-    float theta_o = (theta_d + a->theta_o + b->theta_o) / 2;
+    float theta_o = (theta_d + a->theta_o + b->theta_o) * 0.5f;
 
-    if (theta_o > M_PI_F) {
+    if (theta_o >= M_PI_F) {
       return OrientationBounds({a->axis, M_PI_F, theta_e});
     }
 
@@ -158,7 +158,7 @@ LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &p
   LightTreeBuildNode *node = new LightTreeBuildNode();
   total_nodes++;
   BoundBox node_bbox = BoundBox::empty;
-  OrientationBounds node_bcone;
+  OrientationBounds node_bcone = OrientationBounds::empty;
   BoundBox centroid_bounds = BoundBox::empty;
   float energy_total = 0.0;
   float energy_squared_total = 0.0;
@@ -178,7 +178,7 @@ LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &p
   float energy_variance = (energy_squared_total / num_prims) - (energy_total / num_prims) * (energy_total / num_prims);
 
   /* to-do: find a better way to handle when all centroids overlap. */
-  if (num_prims == 1 || centroid_bounds.area() == 0.0f) {
+  if (num_prims == 1 || len(centroid_bounds.size()) == 0.0f) {
     int first_prim_offset = ordered_prims.size();
     /* to-do: reduce this? */
     for (int i = start; i < end; i++) {
@@ -257,7 +257,8 @@ void LightTree::split_saoh(const BoundBox &centroid_bbox,
                            int& min_dim,
                            int& min_bucket)
 {
-  /* to-do: test without using this in the calculation, since it's the same for every 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. */
   const float inv_total_cost = 1 / (bbox.area() * bcone.calculate_measure());
   const float max_extent = max3(centroid_bbox.size());
 
@@ -305,22 +306,26 @@ void LightTree::split_saoh(const BoundBox &centroid_bbox,
       bcone_R = OrientationBounds::empty;
 
       for (int left = 0; left <= split; left++) {
-        energy_L += buckets[left].energy;
-        bbox_L.grow(buckets[left].bbox);
-        bcone_L = merge(bcone_L, buckets[left].bcone);
+        if (buckets[left].bbox.valid()) {
+          energy_L += buckets[left].energy;
+          bbox_L.grow(buckets[left].bbox);
+          bcone_L = merge(bcone_L, buckets[left].bcone);
+        }
       }
 
       for (int right = split + 1; right < LightTreeBucketInfo::num_buckets; right++) {
-        energy_R += buckets[right].energy;
-        bbox_R.grow(buckets[right].bbox);
-        bcone_R = merge(bcone_R, buckets[right].bcone);
+        if (buckets[right].bbox.valid()) {
+          energy_R += buckets[right].energy;
+          bbox_R.grow(buckets[right].bbox);
+          bcone_R = merge(bcone_R, buckets[right].bcone);
+        }
       }
       
       /* Calculate the cost of splitting using the heuristic as described in the paper. */
-      float left = energy_L * bbox_L.area() * bcone_L.calculate_measure();
-      float right = energy_R * bbox_R.area() * bcone_R.calculate_measure();
+      float left = (bbox_L.valid()) ? energy_L * bbox_L.area() * bcone_L.calculate_measure() : 0.0f;
+      float right = (bbox_R.valid()) ? energy_R * bbox_R.area() * bcone_R.calculate_measure() : 0.0f;
       float regularization = max_extent * inv_extent;
-      bucket_costs[split] = regularization * left * right * inv_total_cost;
+      bucket_costs[split] = regularization * (left + right) * inv_total_cost;
 
       if (bucket_costs[split] < min_cost) {
         min_cost = bucket_costs[split];
diff --git a/intern/cycles/scene/light_tree.h b/intern/cycles/scene/light_tree.h
index 09afbb06e1f..7e2c427eea5 100644
--- a/intern/cycles/scene/light_tree.h
+++ b/intern/cycles/scene/light_tree.h
@@ -87,6 +87,10 @@ struct LightTreePrimitive {
 /* Light Tree Bucket Info
  * */
 struct LightTreeBucketInfo {
+  LightTreeBucketInfo()
+      : energy(0.0f), bbox(BoundBox::empty), bcone(OrientationBounds::empty), count(0)
+  {}
+
   float energy; /* Total energy in the partition */
   BoundBox bbox;
   OrientationBounds bcone;



More information about the Bf-blender-cvs mailing list