[Bf-blender-cvs] [ec81cfab34f] soc-2022-many-lights-sampling: Cycles: implement calculation for light tree pdf

Jeffrey Liu noreply at git.blender.org
Sat Jul 9 06:57:06 CEST 2022


Commit: ec81cfab34f5cb3fd495f439c114744ea7eeddca
Author: Jeffrey Liu
Date:   Thu Jul 7 15:28:56 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rBec81cfab34f5cb3fd495f439c114744ea7eeddca

Cycles: implement calculation for light tree pdf

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

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/light_tree.cpp
M	intern/cycles/scene/light_tree.h
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 42e6e88509d..a22200c58eb 100644
--- a/intern/cycles/kernel/data_arrays.h
+++ b/intern/cycles/kernel/data_arrays.h
@@ -64,6 +64,8 @@ KERNEL_DATA_ARRAY(float2, light_background_conditional_cdf)
 KERNEL_DATA_ARRAY(KernelLightTreeNode, light_tree_nodes)
 KERNEL_DATA_ARRAY(KernelLightTreeEmitter, light_tree_emitters)
 KERNEL_DATA_ARRAY(KernelLightTreeDistantEmitter, light_tree_distant_group)
+KERNEL_DATA_ARRAY(uint, light_to_tree)
+KERNEL_DATA_ARRAY(uint, triangle_to_tree)
 
 /* 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 57f2792cc35..cf7e9c2ee18 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -243,7 +243,7 @@ ccl_device int light_tree_sample(KernelGlobals kg,
 
   /* We should never reach this point. */
   assert(false);
-  return false;
+  return -1;
 }
 
 /* to-do: assign relative importances for the background and distant lights.
@@ -289,7 +289,7 @@ ccl_device int light_tree_sample_distant_lights(KernelGlobals kg,
       ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch(
           light_tree_distant_group, i);
 
-      const int lamp = -kdistant->prim_id - 1;
+      const int lamp = kdistant->prim_id;
 
       if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
         return false;
@@ -298,6 +298,10 @@ ccl_device int light_tree_sample_distant_lights(KernelGlobals kg,
       return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls);
     }
   }
+
+  /* We should never reach this point. */
+  assert(false);
+  return -1;
 }
 
 ccl_device bool light_tree_sample_from_position(KernelGlobals kg,
@@ -329,4 +333,81 @@ ccl_device bool light_tree_sample_from_position(KernelGlobals kg,
   return ret;
 }
 
+/* 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;
+
+  const int emitter = (prim >= 0) ? kernel_data_fetch(triangle_to_tree, prim) : kernel_data_fetch(light_to_tree, ~prim);
+  ccl_global const KernelLightTreeEmitter* kemitter = &kernel_data_fetch(light_tree_emitters,
+                                                                         emitter);
+  int parent = kemitter->parent_index;
+  ccl_global const KernelLightTreeNode* kleaf = &kernel_data_fetch(light_tree_nodes, parent);
+
+  /* First, we find the probability of selecting the primitive out of the leaf node. */
+  float total_importance = 0.0f;
+  float emitter_importance = 0.0f;
+  for (int i = 0; i < kleaf->num_prims; i++) {
+    int prim = i - kleaf->child_index; /* At a leaf node, the negative value is the index into first prim. */
+    const float importance = light_tree_emitter_importance(kg, P, N, prim);
+    if (i == emitter) {
+      emitter_importance = importance;
+    }
+    total_importance += importance;
+  }
+  pdf *= emitter_importance / total_importance;
+
+  /* Next, we find the probability of traversing to that leaf node. */
+  int child_index = parent; 
+  parent = kleaf->parent_index;
+  while (parent != -1) {
+    const ccl_global KernelLightTreeNode *kparent = &kernel_data_fetch(light_tree_nodes, parent);
+
+    const int left_index = parent + 1;
+    const int right_index = kparent->child_index;
+    const ccl_global KernelLightTreeNode *kleft = &kernel_data_fetch(light_tree_nodes, left_index);
+    const ccl_global KernelLightTreeNode *kright = &kernel_data_fetch(light_tree_nodes, right_index);
+
+    const float left_importance = light_tree_cluster_importance(kg, P, N, kleft);
+    const float right_importance = light_tree_cluster_importance(kg, P, N, kright);
+    const float left_probability = left_importance / (left_importance + right_importance);
+
+    /* If the child index matches the left index, then we must've traversed left, otherwise right. */
+    if (left_index == child_index) {
+      pdf *= left_probability;
+    }
+    else {
+      pdf *= (1 - left_probability);
+    }
+
+    child_index = parent;
+    parent = kparent->parent_index;
+  }
+
+  return pdf;
+}
+
+ccl_device float distant_lights_pdf(KernelGlobals kg, const float3 P, const float3 N, const int prim)
+{
+  float pdf = (1 - kernel_data.integrator.pdf_light_tree);
+
+  /* The light_to_tree array doubles as a lookup table for
+   * both the light tree as well as the distant lights group.*/
+  const int distant_light = kernel_data_fetch(light_to_tree, prim);
+  const int num_distant_lights = kernel_data.integrator.num_distant_lights;
+
+  float emitter_importance = 0.0f;
+  float total_importance = 0.0f;
+  for (int i = 0; i < num_distant_lights; i++) {
+    float importance = light_tree_distant_light_importance(kg, P, N, i);
+    if (i == distant_light) {
+      emitter_importance = importance;
+    }
+    total_importance += importance;
+  }
+
+  pdf *= emitter_importance / total_importance;
+  return pdf;
+}
+
 CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 3e9fcd19609..fc43a1b735a 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -1523,8 +1523,11 @@ typedef struct KernelLightTreeNode {
     float energy_variance; /* interior nodes use the energy variance for the splitting heuristic. */
   };
 
+  /* Parent. */
+  int parent_index;
+
   /* Padding. */
-  int pad1, pad2;
+  int pad1;
 } KernelLightTreeNode;
 static_assert_align(KernelLightTreeNode, 16);
 
@@ -1554,8 +1557,8 @@ typedef struct KernelLightTreeEmitter {
     } lamp;
   };
 
-  /* Padding. */
-  int pad1;
+  /* Parent. */
+  int parent_index;
 } KernelLightTreeEmitter;
 static_assert_align(KernelLightTreeEmitter, 16);
 
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 242665387ca..aeb8cd7a341 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -305,6 +305,7 @@ void LightManager::device_update_distribution(Device *device,
   size_t num_background_lights = 0;
   size_t num_distant_lights = 0;
   size_t num_triangles = 0;
+  size_t total_triangles = 0;
 
   bool background_mis = false;
 
@@ -360,6 +361,7 @@ void LightManager::device_update_distribution(Device *device,
     /* Count emissive triangles. */
     Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
     size_t mesh_num_triangles = mesh->num_triangles();
+    total_triangles += mesh_num_triangles;
     for (size_t i = 0; i < mesh_num_triangles; i++) {
       int shader_index = mesh->get_shader()[i];
       Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
@@ -393,9 +395,15 @@ void LightManager::device_update_distribution(Device *device,
     LightTree light_tree(light_prims, scene, 8);
     light_prims = light_tree.get_prims();
 
+    /* We want to create separate arrays corresponding to triangles and lights,
+     * which will be used to index back into the light tree for PDF calculations. */
+    uint *light_array = dscene->light_to_tree.alloc(num_lights);
+    uint *triangle_array = dscene->triangle_to_tree.alloc(total_triangles);
+
     /* First initialize the light tree's nodes. */
     const vector<PackedLightTreeNode> &linearized_bvh = light_tree.get_nodes();
     KernelLightTreeNode *light_tree_nodes = dscene->light_tree_nodes.alloc(linearized_bvh.size());
+    KernelLightTreeEmitter *light_tree_emitters = dscene->light_tree_emitters.alloc(light_prims.size());
     float light_tree_energy = 0.0f;
     for (int index = 0; index < linearized_bvh.size(); index++) {
       const PackedLightTreeNode &node = linearized_bvh[index];
@@ -413,70 +421,73 @@ void LightManager::device_update_distribution(Device *device,
       light_tree_nodes[index].theta_o = node.bcone.theta_o;
       light_tree_nodes[index].theta_e = node.bcone.theta_e;
 
+      light_tree_nodes[index].parent_index = node.parent_index;
+
       /* Here we need to make a distinction between interior and leaf nodes. */
       if (node.is_leaf_node) {
         light_tree_nodes[index].num_prims = node.num_lights;
         light_tree_nodes[index].child_index = -node.first_prim_index;
-      }
-      else {
-        light_tree_nodes[index].energy_variance = node.energy_variance;
-        light_tree_nodes[index].child_index = node.second_child_index;
-      }
-    }
-    dscene->light_tree_nodes.copy_to_device();
-
-    /* The light tree emitters store extra information about their bounds. */
-    KernelLightTreeEmitter *light_tree_emitters = dscene->light_tree_emitters.alloc(light_prims.size());
-    for (int index = 0; index < light_prims.size(); index++) {
-      LightTreePrimitive &prim = light_prims[index];
-      BoundBox bbox = prim.calculate_bbox(scene);
-      OrientationBounds bcone = prim.calculate_bcone(scene);
-      float energy = prim.calculate_energy(scene);
-
-      light_tree_emitters[index].energy = energy;
-      for (int i = 0; i < 3; i++) {
-        light_tree_emitters[index].bounding_box_min[i] = bbox.min[i];
-        light_tree_emitters[index].bounding_box_max[i] = bbox.max[i];
-        light_tree_emitters[index].bounding_cone_axis[i] = bcone.axis[i];
-      }
-      light_tree_emitters[index].theta_o = bcone.theta_o;
-      light_tree_emitters[index].theta_e = bcone.theta_e;
-
-      light_tree_emitters[index].prim_id = prim.prim_id;
 
-      if (prim.prim_id >= 0) {
-        light_tree_emitters[index].mesh_light.object_id = prim.object_id;
+        for (int i = 0; i < node.num_lights; i++) {
+          int emitter_index = i + node.first_prim_index;
+          LightTreePrimitive &prim = light_prims[emitter_index];
+          BoundBox bbox = prim.calculate_bbox(scene);
+          OrientationBounds bcone = prim.calculate_bcone(scene);
+          float energy = prim.calculate_energy(scene);
+
+          light_tree_emitters[emitter_index].energy = energy;
+          for (int i = 0; i < 3; i++) {
+            light_tree_emitters[emitter_index].bounding_box_min[i] = bbox.min[i];
+            light_tree_emitters[emitter_in

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list