[Bf-blender-cvs] [7b3c1a203ef] soc-2022-many-lights-sampling: Cycles: update distant light importance heuristics

Jeffrey Liu noreply at git.blender.org
Sat Jul 9 22:01:42 CEST 2022


Commit: 7b3c1a203efdecf08d0aa041a76a984f2d72d870
Author: Jeffrey Liu
Date:   Sat Jul 9 16:01:03 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB7b3c1a203efdecf08d0aa041a76a984f2d72d870

Cycles: update distant light importance heuristics

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

M	intern/cycles/kernel/light/light_tree.h
M	intern/cycles/kernel/types.h
M	intern/cycles/scene/light.cpp

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

diff --git a/intern/cycles/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h
index 1b9e5d3806b..0ba28982e91 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -69,7 +69,7 @@ ccl_device float light_tree_node_importance(const float3 P,
   }
 
   /* to-do: find a good approximation for this value. */
-  const float f_a = 1;
+  const float f_a = 1.0f;
 
   float importance = f_a * cos_theta_i_prime * energy / distance_squared * cos_theta_prime;
   return importance;
@@ -225,8 +225,6 @@ ccl_device int light_tree_sample(KernelGlobals kg,
   return -1;
 }
 
-/* to-do: assign relative importances for the background and distant lights.
- * Can we somehow adjust the importance measure to account for these as well? */
 ccl_device float light_tree_distant_light_importance(KernelGlobals kg,
                                                      const float3 P,
                                                      const float3 N,
@@ -234,7 +232,28 @@ ccl_device float light_tree_distant_light_importance(KernelGlobals kg,
 {
   ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch(
       light_tree_distant_group, index);
-  return kdistant->energy;
+
+  if (kdistant->energy == 0.0f) {
+    return 0.0f;
+  }
+
+  const float3 light_axis = make_float3(
+      kdistant->direction[0], kdistant->direction[1], kdistant->direction[2]);
+  const float theta = fast_acosf(dot(N, light_axis));
+  const float theta_i_prime = theta - kdistant->bounding_radius;
+
+  float cos_theta_i_prime = 1;
+  if (theta_i_prime > M_PI_2_F) {
+    return 0.0f;
+  } else if (theta - kdistant->bounding_radius > 0) {
+    cos_theta_i_prime = fast_cosf(theta - kdistant->bounding_radius);
+  }
+
+  /* to-do: find a good value for this. */
+  const float f_a = 1.0f;
+  float importance = f_a * cos_theta_i_prime * kdistant->energy;
+
+  return importance;
 }
 
 template<bool in_volume_segment>
@@ -286,7 +305,16 @@ ccl_device int light_tree_sample_distant_lights(KernelGlobals kg,
 /* We need to be able to find the probability of selecting a given light, for MIS. */
 ccl_device float light_tree_pdf(KernelGlobals kg, const float3 P, const float3 N, const int prim)
 {
-  float pdf = kernel_data.integrator.pdf_light_tree;
+  float distant_light_importance = light_tree_distant_light_importance(
+      kg, P, N, kernel_data.integrator.num_distant_lights);
+  float light_tree_importance = 0.0f;
+  if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) {
+    const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0);
+    light_tree_importance = light_tree_cluster_importance(kg, P, N, kroot);
+  }
+  const float total_group_importance = light_tree_importance + distant_light_importance;
+  assert(total_group_importance != 0.0f);
+  float pdf = light_tree_importance / total_group_importance;
 
   const int emitter = (prim >= 0) ? kernel_data_fetch(triangle_to_tree, prim) :
                                     kernel_data_fetch(light_to_tree, ~prim);
@@ -351,7 +379,16 @@ ccl_device float distant_lights_pdf(KernelGlobals kg,
                                     const float3 N,
                                     const int prim)
 {
-  float pdf = (1 - kernel_data.integrator.pdf_light_tree);
+  float distant_light_importance = light_tree_distant_light_importance(
+      kg, P, N, kernel_data.integrator.num_distant_lights);
+  float light_tree_importance = 0.0f;
+  if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) {
+    const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0);
+    light_tree_importance = light_tree_cluster_importance(kg, P, N, kroot);
+  }
+  const float total_group_importance = light_tree_importance + distant_light_importance;
+  assert(total_group_importance != 0.0f);
+  float pdf = distant_light_importance / total_group_importance;
 
   /* The light_to_tree array doubles as a lookup table for
    * both the light tree as well as the distant lights group.*/
@@ -383,16 +420,31 @@ ccl_device bool light_tree_sample_from_position(KernelGlobals kg,
                                                 const uint32_t path_flag,
                                                 ccl_private LightSample *ls)
 {
+  float distant_light_importance = light_tree_distant_light_importance(
+      kg, P, N, kernel_data.integrator.num_distant_lights);
+  float light_tree_importance = 0.0f;
+  if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) {
+    const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0);
+    light_tree_importance = light_tree_cluster_importance(kg, P, N, kroot);
+  }
+  const float total_importance = light_tree_importance + distant_light_importance;
+
+  if (total_importance == 0.0f) {
+    return false;
+  }
+
+  const float light_tree_probability = light_tree_importance / total_importance;
+
   float pdf_factor = 1.0f;
   bool ret;
   float tree_u = path_state_rng_1D(kg, rng_state, 1);
-  if (tree_u < kernel_data.integrator.pdf_light_tree) {
-    pdf_factor *= kernel_data.integrator.pdf_light_tree;
+  if (tree_u < light_tree_probability) {
+    pdf_factor *= light_tree_probability;
     ret = light_tree_sample<false>(
         kg, rng_state, randu, randv, time, N, P, bounce, path_flag, ls, &pdf_factor);
   }
   else {
-    pdf_factor *= (1 - kernel_data.integrator.pdf_light_tree);
+    pdf_factor *= (1 - light_tree_probability);
     ret = light_tree_sample_distant_lights<false>(
         kg, rng_state, randu, randv, time, N, P, bounce, path_flag, ls, &pdf_factor);
   }
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 9def2e5690b..793b6d4c309 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -1303,12 +1303,11 @@ typedef struct KernelIntegrator {
   int direct_light_sampling_type;
 
   /* Light tree. */
-  float pdf_light_tree;
   int use_light_tree;
   float splitting_threshold;
 
   /* padding */
-  int pad1;
+  int pad1, pad2;
 } KernelIntegrator;
 static_assert_align(KernelIntegrator, 16);
 
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 6278e3efd93..15cbfc36d7a 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -389,7 +389,6 @@ void LightManager::device_update_distribution(Device *device,
   size_t num_distribution = num_triangles + num_lights;
   VLOG_INFO << "Total " << num_distribution << " of light distribution primitives.";
 
-  float pdf_light_tree = 0.0f;
   if (light_tree_enabled && num_distribution > 0) {
     /* For now, we'll start with a smaller number of max lights in a node.
      * More benchmarking is needed to determine what number works best. */
@@ -492,11 +491,15 @@ void LightManager::device_update_distribution(Device *device,
 
     /* We also add distant lights to a separate group. */
     KernelLightTreeDistantEmitter *light_tree_distant_group =
-        dscene->light_tree_distant_group.alloc(num_distant_lights);
+        dscene->light_tree_distant_group.alloc(num_distant_lights + 1);
+
+    /* We use OrientationBounds here to */
+    OrientationBounds distant_light_bounds = OrientationBounds::empty;
     float distant_light_energy = 0.0f;
     for (int index = 0; index < num_distant_lights; index++) {
       LightTreePrimitive prim = distant_lights[index];
       Light *light = scene->lights[prim.lamp_id];
+      OrientationBounds light_bounds;
       
       /* Lights in this group are either a background or distant light. */
       light_tree_distant_group[index].prim_id = ~prim.prim_id;
@@ -506,30 +509,39 @@ void LightManager::device_update_distribution(Device *device,
         energy = average_background_energy(device, dscene, progress, scene, light);
 
         /* We can set an arbitrary direction for the background light. */
-        light_tree_distant_group[index].direction[0] = 0.0f;
-        light_tree_distant_group[index].direction[1] = 0.0f;
-        light_tree_distant_group[index].direction[2] = 1.0f;
+        light_bounds.axis[0] = 0.0f;
+        light_bounds.axis[1] = 0.0f;
+        light_bounds.axis[2] = 1.0f;
 
         /* to-do: this may depend on portal lights as well. */
-        light_tree_distant_group[index].bounding_radius = M_PI_F;
+        light_bounds.theta_o = M_PI_F;
       }
       else {
         energy = prim.calculate_energy(scene);
-
         for (int i = 0; i < 3; i++) {
-          light_tree_distant_group[index].direction[i] = -light->co[i];
+          light_bounds.axis[i] = -light->dir[i];
         }
-        light_tree_distant_group[index].bounding_radius = tanf(light->angle * 0.5f);
+        light_bounds.theta_o = tanf(light->angle * 0.5f);
+      }
+
+      distant_light_bounds = merge(distant_light_bounds, light_bounds);
+      for (int i = 0; i < 3; i++) {
+        light_tree_distant_group[index].direction[i] = light_bounds.axis[i];
       }
+      light_tree_distant_group[index].bounding_radius = light_bounds.theta_o;
 
       light_tree_distant_group[index].energy = energy;
       light_array[~prim.prim_id] = index;
       distant_light_energy += energy;
-    }
+    } 
 
-    if (light_tree_energy > 0.0f) {
-      pdf_light_tree = light_tree_energy / (light_tree_energy + distant_light_energy);
+    /* The net OrientationBounds contain bounding information about all the distant lights. */
+    light_tree_distant_group[num_distant_lights].prim_id = -1;
+    light_tree_distant_group[num_distant_lights].energy = distant_light_energy;
+    for (int i = 0; i < 3; i++) {
+      light_tree_distant_group[num_distant_lights].direction[i] = distant_light_bounds.axis[i];
     }
+    light_tree_distant_group[num_distant_lights].bounding_radius = distant_light_bounds.theta_o;
 
     dscene->light_tree_nodes.copy_to_device();
     dscene->light_tree_emitters.copy_to_device();
@@ -688,7 +700,6 @@ void LightManager::device_update_distribution(Device *device,
     /* pdf_lights is used when sampling lights, and assumes that
      * the light has been sampled through the light distribution.
      * Therefore, we override it for now a

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list