[Bf-blender-cvs] [5366920563a] soc-2022-many-lights-sampling: Use as few arccosines as possible

Weizhen Huang noreply at git.blender.org
Thu Oct 13 21:05:36 CEST 2022


Commit: 5366920563a38389c5e2268ba57a2d273d882e03
Author: Weizhen Huang
Date:   Thu Oct 13 20:41:49 2022 +0200
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB5366920563a38389c5e2268ba57a2d273d882e03

Use as few arccosines as possible

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

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 3dba7553c76..bdbdd94e892 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -4,16 +4,16 @@
 
 CCL_NAMESPACE_BEGIN
 
-/* to-do: this seems like a relative expensive computation, and we can make it a lot cheaper
+/* 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_bounding_box_angle(const float3 bbox_min,
-                                               const float3 bbox_max,
-                                               const float3 P,
-                                               const float3 point_to_centroid)
+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 theta_u = 0;
+  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);
@@ -25,10 +25,9 @@ ccl_device float light_tree_bounding_box_angle(const float3 bbox_min,
   corners[7] = bbox_max;
   for (int i = 0; i < 8; ++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);
+    cos_theta_u = fminf(cos_theta_u, dot(point_to_centroid, point_to_corner));
   }
-  return theta_u;
+  return cos_theta_u;
 }
 
 /* This is the general function for calculating the importance of either a cluster or an emitter.
@@ -46,41 +45,64 @@ 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);
 
-  /* Since we're not using the splitting heuristic, we clamp
-   * the distance to half the radius of the cluster. */
+  /* TODO: we're using the splitting heuristic now, do we still need te 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));
 
-  const float theta = fast_acosf(dot(bcone_axis, -point_to_centroid));
-  float theta_i = fast_acosf(dot(point_to_centroid, N));
-  const float theta_u = light_tree_bounding_box_angle(bbox_min, bbox_max, P, point_to_centroid);
+  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);
 
-  /* Avoid using cosine until needed. */
-  const float theta_prime = fmaxf(theta - theta_o - theta_u, 0.0f);
-  if (theta_prime >= theta_e) {
-    return 0.0f;
+  const float sin_theta_u = safe_sqrtf(1.0f - sqr(cos_theta_u));
+
+  /* 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;
   }
 
   /* 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 && (theta_i - theta_u > M_PI_2_F)) {
+  if (!has_transmission && cos_theta_i_prime < 0) {
     return 0.0f;
   }
 
-  if (theta_i > M_PI_2_F) {
-    theta_i = M_PI_F - theta_i;
-  }
+  /* 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;
 
-  const float cos_theta_prime = fast_cosf(theta_prime);
-  float cos_theta_i_prime = 1.0f;
-  if (theta_i - theta_u > 0.0f) {
-    cos_theta_i_prime = fabsf(fast_cosf(theta_i - theta_u));
+  float cos_theta_o, sin_theta_o;
+  fast_sincosf(theta_o, &sin_theta_o, &cos_theta_o);
+
+  float cos_theta_prime;
+  if ((cos_theta > cos_theta_u) || (cos_theta_minus_theta_u > cos_theta_o)) {
+    /* theta - theta_o - theta_u < 0 */
+    kernel_assert((fast_acosf(cos_theta) - theta_o - fast_acosf(cos_theta_u)) < 1e-4f);
+    cos_theta_prime = 1.0f;
+  }
+  else if ((cos_theta > cos_theta_u) || (theta_o + theta_e > M_PI_F) ||
+           (cos_theta_minus_theta_u > cos(theta_o + theta_e))) {
+    /* theta' = theta - theta_o - theta_u < theta_e */
+    kernel_assert((fast_acosf(cos_theta) - theta_o - fast_acosf(cos_theta_u) - theta_e) < 1e-4f);
+    const float sin_theta_minus_theta_u = safe_sqrtf(1.0f - sqr(cos_theta_minus_theta_u));
+    cos_theta_prime = cos_theta_minus_theta_u * cos_theta_o +
+                      sin_theta_minus_theta_u * sin_theta_o;
+  }
+  else {
+    return 0.f;
   }
 
-  /* to-do: find a good approximation for this value. */
+  /* TODO: find a good approximation for this value. */
   const float f_a = 1.0f;
-  float importance = f_a * cos_theta_i_prime * energy / distance_squared * cos_theta_prime;
-  return importance;
+  return fabsf(f_a * cos_theta_i_prime * energy / distance_squared * cos_theta_prime);
 }
 
 /* This is uniformly sampling the reservoir for now. */



More information about the Bf-blender-cvs mailing list