[Bf-blender-cvs] [fe8897ad4cd] soc-2022-many-lights-sampling: Cycles: support distant lights in tree

Jeffrey Liu noreply at git.blender.org
Sat Jun 25 22:16:08 CEST 2022


Commit: fe8897ad4cdb2e9cbe25f3ecbd7289fffaa53b63
Author: Jeffrey Liu
Date:   Sat Jun 25 16:00:31 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rBfe8897ad4cdb2e9cbe25f3ecbd7289fffaa53b63

Cycles: support distant lights in tree

This is the initial support for sampling distant lights.
The heuristic needs to be adjusted but it works in basic cases.

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

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

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

diff --git a/intern/cycles/kernel/data_arrays.h b/intern/cycles/kernel/data_arrays.h
index 978e45f07b7..42e6e88509d 100644
--- a/intern/cycles/kernel/data_arrays.h
+++ b/intern/cycles/kernel/data_arrays.h
@@ -63,6 +63,7 @@ KERNEL_DATA_ARRAY(float2, light_background_conditional_cdf)
 /* light tree */
 KERNEL_DATA_ARRAY(KernelLightTreeNode, light_tree_nodes)
 KERNEL_DATA_ARRAY(KernelLightTreeEmitter, light_tree_emitters)
+KERNEL_DATA_ARRAY(KernelLightTreeDistantEmitter, light_tree_distant_group)
 
 /* particles */
 KERNEL_DATA_ARRAY(KernelParticle, particles)
diff --git a/intern/cycles/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h
index 788c2ccf90d..679dcda39f9 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -30,7 +30,7 @@ ccl_device float light_tree_bounding_box_angle(const float3 bbox_min,
 
 /* 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.
- * to-do: find a better way to handle this? */
+ * to-do: find a better way to handle this? or rename it to be more clear? */
 ccl_device float light_tree_node_importance(const float3 P,
                                             const float3 N,
                                             const float3 bbox_min,
@@ -112,11 +112,10 @@ ccl_device float light_tree_cluster_importance(KernelGlobals kg,
       P, N, bbox_min, bbox_max, bcone_axis, knode->theta_o, knode->theta_e, knode->energy);
 }
 
-
 /* to-do: for now, we're not going to worry about being in a volume for now,
  * but this seems to be a good way to differentiate whether we're in a volume or not. */
 template<bool in_volume_segment>
-ccl_device bool light_tree_sample(KernelGlobals kg,
+ccl_device int light_tree_sample(KernelGlobals kg,
                                   ccl_private const RNGState *rng_state,
                                   float randu,
                                   const float randv,
@@ -186,11 +185,11 @@ ccl_device bool light_tree_sample(KernelGlobals kg,
     emitter_cdf += emitter_pdf;
     if (tree_u < emitter_cdf) {
       *pdf_factor *= emitter_pdf;
-      ccl_global const KernelLightDistribution *kdistribution = &kernel_data_fetch(light_distribution,
-                                                                                   prim_index);
+      ccl_global const KernelLightDistribution *kdistribution = &kernel_data_fetch(
+          light_distribution, prim_index);
 
-      /* to-do: this is the same code as light_distribution_sample, except the index is determined differently.
-       * Would it be better to refactor this into a separate function? */
+      /* to-do: this is the same code as light_distribution_sample, except the index is determined
+       * differently. Would it be better to refactor this into a separate function? */
       const int prim = kdistribution->prim;
 
       if (prim >= 0) {
@@ -224,6 +223,60 @@ ccl_device bool light_tree_sample(KernelGlobals kg,
   return false;
 }
 
+/* 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,
+                                                     const int index)
+{
+  ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch(
+      light_tree_distant_group, index);
+  return kdistant->energy;
+}
+
+template<bool in_volume_segment>
+ccl_device int light_tree_sample_distant_lights(KernelGlobals kg,
+                                                ccl_private const RNGState *rng_state,
+                                                float randu,
+                                                const float randv,
+                                                const float time,
+                                                const float3 N,
+                                                const float3 P,
+                                                const int bounce,
+                                                const uint32_t path_flag,
+                                                ccl_private LightSample *ls,
+                                                float *pdf_factor)
+{
+  const int num_distant_lights = kernel_data.integrator.num_distant_lights;
+  float total_importance = 0.0f;
+  for (int i = 0; i < num_distant_lights; i++) {
+    total_importance += light_tree_distant_light_importance(kg, P, N, i);
+  }
+  const float inv_total_importance = 1 / total_importance;
+
+  float light_cdf = 0.0f;
+  float distant_u = path_state_rng_1D(kg, rng_state, 1);
+  for (int i = 0; i < num_distant_lights; i++) {
+    const float light_pdf = light_tree_distant_light_importance(kg, P, N, i) *
+                            inv_total_importance;
+    light_cdf += light_pdf;
+    if (distant_u < light_cdf) {
+      *pdf_factor *= light_pdf;
+      ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch(
+          light_tree_distant_group, i);
+
+      const int lamp = -kdistant->prim_id - 1;
+
+      if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
+        return false;
+      }
+
+      return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls);
+    }
+  }
+}
+
 ccl_device bool light_tree_sample_from_position(KernelGlobals kg,
                                                 ccl_private const RNGState *rng_state,
                                                 float randu,
@@ -235,10 +288,40 @@ ccl_device bool light_tree_sample_from_position(KernelGlobals kg,
                                                 const uint32_t path_flag,
                                                 ccl_private LightSample *ls)
 {
-  float pdf_factor;
-  bool ret = light_tree_sample<false>(
-      kg, rng_state, randu, randv, time, N, P, bounce, path_flag, ls, &pdf_factor);
-  assert(pdf_factor != 0.0f);
+  const int num_distant_lights = kernel_data.integrator.num_distant_lights;
+  const int num_light_tree_prims = kernel_data.integrator.num_distribution - num_distant_lights;
+
+  float pdf_factor = 1.0f;
+  bool ret = false;
+  if (num_distant_lights == 0) {
+    ret = light_tree_sample<false>(
+        kg, rng_state, randu, randv, time, N, P, bounce, path_flag, ls, &pdf_factor);
+  }
+  else if (num_light_tree_prims == 0) {
+    ret = light_tree_sample_distant_lights<false>(
+        kg, rng_state, randu, randv, time, N, P, bounce, path_flag, ls, &pdf_factor);
+  }
+  else {
+    const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, 0);
+    const float light_tree_importance = light_tree_cluster_importance(kg, P, N, knode);
+    const float distant_light_importance = light_tree_distant_light_importance(kg, P, N, num_distant_lights);
+
+    const float light_tree_probability = light_tree_importance /
+                                         (light_tree_importance +
+                                          distant_light_importance);
+
+    if (randu < light_tree_probability) {
+      ret = light_tree_sample<false>(
+          kg, rng_state, randu, randv, time, N, P, bounce, path_flag, ls, &pdf_factor);
+      pdf_factor *= light_tree_probability;
+    }
+    else {
+      ret = light_tree_sample_distant_lights<false>(
+          kg, rng_state, randu, randv, time, N, P, bounce, path_flag, ls, &pdf_factor);
+      pdf_factor *= (1 - light_tree_probability);
+    }
+  }
+
   ls->pdf *= pdf_factor;
   return ret;
 }
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 474a6966ae5..09939ca074c 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -1239,6 +1239,7 @@ typedef struct KernelIntegrator {
   int use_direct_light;
   int num_distribution;
   int num_all_lights;
+  int num_distant_lights;
   float pdf_triangles;
   float pdf_lights;
   float light_inv_rr_threshold;
@@ -1303,7 +1304,7 @@ typedef struct KernelIntegrator {
   float splitting_threshold;
 
   /* padding */
-  int pad1, pad2, pad3;
+  int pad1, pad2;
 } KernelIntegrator;
 static_assert_align(KernelIntegrator, 16);
 
@@ -1538,9 +1539,33 @@ typedef struct KernelLightTreeEmitter {
 
   /* Energy. */
   float energy;
+
+  /* prim_id denotes the location in the lights or triangles array. */
+  int prim_id;
+
+  /* Padding. */
+  int pad1, pad2, pad3;
 } KernelLightTreeEmitter;
 static_assert_align(KernelLightTreeEmitter, 16);
 
+typedef struct KernelLightTreeDistantEmitter {
+  /* Direction from world to light. */
+  float direction[3];
+
+  /* Size of light (in radians). */
+  float bounding_radius;
+
+  /* Energy. */
+  float energy;
+
+  /* Prim ID. */
+  int prim_id;
+
+  /* Padding. */
+  int pad1, pad2;
+} KernelLightTreeDistantEmitter;
+static_assert_align(KernelLightTreeDistantEmitter, 16);
+
 typedef struct KernelParticle {
   int index;
   float age;
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 97f0e98633f..a7b49bbff65 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -80,6 +80,35 @@ static void shade_background_pixels(Device *device,
       });
 }
 
+static float average_background_energy(Device *device,
+                                       DeviceScene *dscene,
+                                       Progress &progress,
+                                       Scene *scene,
+                                       Light *light)
+{
+  if (light->get_light_type() != LIGHT_BACKGROUND) {
+    assert(false);
+  }
+
+  /* get the resolution from the light's size (we stuff it in there) */
+  int2 res = make_int2(light->get_map_resolution(), light->get_map_resolution() / 2);
+  /* If it's still unknown, just use the default. */
+  if (res.x == 0 || res.y == 0) {
+    res = make_int2(1024, 512);
+    VLOG_INFO << "Setting World MIS resolution to default\n";
+  }
+
+  vector<float3> pixels;
+  shade_background_pixels(device, dscene, res.x, re

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list