[Bf-blender-cvs] [141afd88bc6] soc-2022-many-lights-sampling: More accurate light behind surface test using all corners of bounding box

Alaska noreply at git.blender.org
Wed Oct 19 21:10:15 CEST 2022


Commit: 141afd88bc6179cb6c1cebb8f97152cc361c4e9b
Author: Alaska
Date:   Wed Oct 19 16:10:51 2022 +0200
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB141afd88bc6179cb6c1cebb8f97152cc361c4e9b

More accurate light behind surface test using all corners of bounding box

In Many Lights Sampling we use whether or not a bounding box is
behind an opaque surface to decide whether or not we discard or
consider the bounding box.

However the calculation used for figuring out if a bounding box
is behind a surface ended up being wrong in some situations.

This patch attempts to fix this by checking if each corner of
the bounding box is behind the surface, resulting in a (hopefully)
perfect differentiation between boxes behind and infront of a
surface.

Contributed by Alaska, with changes by Brecht.

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

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

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 85069cd5118..4e634fa2659 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -4,32 +4,6 @@
 
 CCL_NAMESPACE_BEGIN
 
-/* TODO: this seems like a relative expensive computation, and we can make it a lot cheaper
- * by using a bounding sphere instead of a bounding box. This will be more inaccurate, but it
- * might be fine when used along with the adaptive splitting. */
-ccl_device float light_tree_cos_bounding_box_angle(const float3 bbox_min,
-                                                   const float3 bbox_max,
-                                                   const float3 P,
-                                                   const float3 point_to_centroid)
-{
-  /* Iterate through all 8 possible points of the bounding box. */
-  float cos_theta_u = 1.0f;
-  float3 corners[8];
-  corners[0] = bbox_min;
-  corners[1] = make_float3(bbox_min.x, bbox_min.y, bbox_max.z);
-  corners[2] = make_float3(bbox_min.x, bbox_max.y, bbox_min.z);
-  corners[3] = make_float3(bbox_min.x, bbox_max.y, bbox_max.z);
-  corners[4] = make_float3(bbox_max.x, bbox_min.y, bbox_min.z);
-  corners[5] = make_float3(bbox_max.x, bbox_min.y, bbox_max.z);
-  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(corners[i] - P);
-    cos_theta_u = fminf(cos_theta_u, dot(point_to_centroid, point_to_corner));
-  }
-  return cos_theta_u;
-}
-
 /* This is the general function for calculating the importance of either a cluster or an emitter.
  * Both of the specialized functions obtain the necessary data before calling this function. */
 ccl_device float light_tree_node_importance(const float3 P,
@@ -45,7 +19,7 @@ ccl_device float light_tree_node_importance(const float3 P,
   const float3 centroid = 0.5f * bbox_min + 0.5f * bbox_max;
   const float3 point_to_centroid = normalize(centroid - P);
 
-  /* TODO: we're using the splitting heuristic now, do we still need te clamp the distance to half
+  /* TODO: we're using the splitting heuristic now, do we still need to clamp the distance to half
    * the radius of the cluster? */
   const float distance_squared = fmaxf(0.25f * len_squared(centroid - bbox_max),
                                        len_squared(centroid - P));
@@ -53,28 +27,38 @@ ccl_device float light_tree_node_importance(const float3 P,
   const float cos_theta = dot(bcone_axis, -point_to_centroid);
   const float cos_theta_i = has_transmission ? fabsf(dot(point_to_centroid, N)) :
                                                dot(point_to_centroid, N);
-  const float cos_theta_u = light_tree_cos_bounding_box_angle(
-      bbox_min, bbox_max, P, point_to_centroid);
 
-  const float sin_theta_u = safe_sqrtf(1.0f - sqr(cos_theta_u));
+  bool bbox_is_behind_surface = !has_transmission && (cos_theta_i < 0);
 
-  /* cos_theta_i_prime = |cos(max{theta_i - theta_u, 0})| */
-  float cos_theta_i_prime;
-  if (cos_theta_i > cos_theta_u) {
-    cos_theta_i_prime = 1.0f;
-  }
-  else {
-    kernel_assert(fast_acosf(cos_theta_i) >= fast_acosf(cos_theta_u));
-    const float sin_theta_i = safe_sqrtf(1.0f - sqr(cos_theta_i));
-    cos_theta_i_prime = cos_theta_i * cos_theta_u + sin_theta_i * sin_theta_u;
+  /* TODO: this seems like a relative expensive computation, and we can make it a lot cheaper
+   * by using a bounding sphere instead of a bounding box. This will be more inaccurate, but it
+   * might be fine when used along with the adaptive splitting. */
+  float cos_theta_u = 1.0f;
+
+  /* Iterate through all 8 possible points of the bounding box. */
+  for (int i = 0; i < 8; ++i) {
+    const float3 corner = make_float3((i & 1) ? bbox_max.x : bbox_min.x,
+                                      (i & 2) ? bbox_max.y : bbox_min.y,
+                                      (i & 4) ? bbox_max.z : bbox_min.z);
+
+    /* Caculate the bounding box angle. */
+    float3 point_to_corner = normalize(corner - P);
+    cos_theta_u = fminf(cos_theta_u, dot(point_to_centroid, point_to_corner));
+
+    /* Figure out whether or not the bounding box is in front or behind the shading point. */
+    if (bbox_is_behind_surface && dot(point_to_corner, N) >= 0) {
+      bbox_is_behind_surface = false;
+    }
   }
 
   /* If the node is guaranteed to be behind the surface we're sampling, and the surface is opaque,
    * then we can give the node an importance of 0 as it contributes nothing to the surface. */
-  if (!has_transmission && cos_theta_i_prime < 0) {
+  if (bbox_is_behind_surface) {
     return 0.0f;
   }
 
+  const float sin_theta_u = safe_sqrtf(1.0f - sqr(cos_theta_u));
+
   /* cos(theta - theta_u) */
   const float sin_theta = safe_sqrtf(1.0f - sqr(cos_theta));
   const float cos_theta_minus_theta_u = cos_theta * cos_theta_u + sin_theta * sin_theta_u;
@@ -100,6 +84,17 @@ ccl_device float light_tree_node_importance(const float3 P,
     return 0.f;
   }
 
+  /* cos_theta_i_prime = |cos(max{theta_i - theta_u, 0})| */
+  float cos_theta_i_prime;
+  if (cos_theta_i > cos_theta_u) {
+    cos_theta_i_prime = 1.0f;
+  }
+  else {
+    kernel_assert(fast_acosf(cos_theta_i) >= fast_acosf(cos_theta_u));
+    const float sin_theta_i = safe_sqrtf(1.0f - sqr(cos_theta_i));
+    cos_theta_i_prime = cos_theta_i * cos_theta_u + sin_theta_i * sin_theta_u;
+  }
+
   /* TODO: find a good approximation for this value. */
   const float f_a = 1.0f;
   return fabsf(f_a * cos_theta_i_prime * energy / distance_squared * cos_theta_prime);



More information about the Bf-blender-cvs mailing list