[Bf-blender-cvs] [b323b40af64] soc-2022-many-lights-sampling: Cycles: support emissive triangles in light tree

Jeffrey Liu noreply at git.blender.org
Tue Jun 21 06:15:21 CEST 2022


Commit: b323b40af648c2a46bf1193c16ecc35916f26dba
Author: Jeffrey Liu
Date:   Tue Jun 21 00:05:55 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rBb323b40af648c2a46bf1193c16ecc35916f26dba

Cycles: support emissive triangles in light tree

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

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

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

diff --git a/intern/cycles/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h
index 1c9684e006c..ebc6d8280a2 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -77,29 +77,22 @@ ccl_device float light_tree_emitter_importance(KernelGlobals kg,
                                                const float3 N,
                                                int emitter_index)
 {
-  ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution,
-                                                                              emitter_index);
-  const int prim = kdistribution->prim;
+  ccl_global const KernelLightTreeEmitter *kemitter = &kernel_tex_fetch(__light_tree_emitters,
+                                                                        emitter_index);
 
-  if (prim >= 0) {
-    /* to-do: handle case for mesh lights. */
-  }
-
-  /* If we're not at a mesh light, then we should be at a point, spot, or area light. */
-  const int lamp = -prim - 1;
-  const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
-  const float radius = klight->spot.radius;
-  const float3 bbox_min = make_float3(
-      klight->co[0] - radius, klight->co[1] - radius, klight->co[2] - radius);
-  const float3 bbox_max = make_float3(
-      klight->co[0] + radius, klight->co[1] + radius, klight->co[2] + radius);
-  const float3 bcone_axis = make_float3(
-      klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
-  const float3 rgb_strength = make_float3(
-      klight->strength[0], klight->strength[1], klight->strength[2]);
+  /* Convert the data from the struct into float3 for calculations. */
+  const float3 bbox_min = make_float3(kemitter->bounding_box_min[0],
+                                      kemitter->bounding_box_min[1],
+                                      kemitter->bounding_box_min[2]);
+  const float3 bbox_max = make_float3(kemitter->bounding_box_max[0],
+                                      kemitter->bounding_box_max[1],
+                                      kemitter->bounding_box_max[2]);
+  const float3 bcone_axis = make_float3(kemitter->bounding_cone_axis[0],
+                                        kemitter->bounding_cone_axis[1],
+                                        kemitter->bounding_cone_axis[2]);
 
   return light_tree_node_importance(
-      P, N, bbox_min, bbox_max, bcone_axis, M_PI_F, M_PI_2_F, linear_rgb_to_gray(kg, rgb_strength));
+      P, N, bbox_min, bbox_max, bcone_axis, kemitter->theta_o, kemitter->theta_e, kemitter->energy);
 }
 
 ccl_device float light_tree_cluster_importance(KernelGlobals kg,
@@ -193,10 +186,36 @@ ccl_device bool light_tree_sample(KernelGlobals kg,
     emitter_cdf += emitter_pdf;
     if (tree_u < emitter_cdf) {
       *pdf_factor *= emitter_pdf;
-      if (UNLIKELY(light_select_reached_max_bounces(kg, prim_index, bounce))) {
+      ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_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? */
+      const int prim = kdistribution->prim;
+
+      if (prim >= 0) {
+        /* Mesh light. */
+        const int object = kdistribution->mesh_light.object_id;
+
+        /* Exclude synthetic meshes from shadow catcher pass. */
+        if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) &&
+            !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) {
+          return false;
+        }
+
+        const int shader_flag = kdistribution->mesh_light.shader_flag;
+        triangle_light_sample<in_volume_segment>(kg, prim, object, randu, randv, time, ls, P);
+        ls->shader |= shader_flag;
+        return (ls->pdf > 0.0f);
+      }
+
+      const int lamp = -prim - 1;
+
+      if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
         return false;
       }
-      return light_sample<in_volume_segment>(kg, prim_index, randu, randv, P, path_flag, ls);
+
+      return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls);
     }
   }
 
diff --git a/intern/cycles/kernel/textures.h b/intern/cycles/kernel/textures.h
index 58f0a312d9a..b08409be7c7 100644
--- a/intern/cycles/kernel/textures.h
+++ b/intern/cycles/kernel/textures.h
@@ -62,6 +62,7 @@ KERNEL_TEX(float2, __light_background_conditional_cdf)
 
 /* light tree */
 KERNEL_TEX(KernelLightTreeNode, __light_tree_nodes)
+KERNEL_TEX(KernelLightTreeEmitter, __light_tree_emitters)
 
 /* particles */
 KERNEL_TEX(KernelParticle, __particles)
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 069c179fc73..5a5e1bcc220 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -1526,6 +1526,27 @@ typedef struct KernelLightTreeNode {
 } KernelLightTreeNode;
 static_assert_align(KernelLightTreeNode, 16);
 
+typedef struct KernelLightTreeEmitter {
+  /* Bounding box. */
+  float bounding_box_min[3];
+  float bounding_box_max[3];
+
+  /* Bounding cone. */
+  float bounding_cone_axis[3];
+  float theta_o;
+  float theta_e;
+
+  /* Energy. */
+  float energy;
+
+  /* If this is positive, this is a triangle. Otherwise, it's a light source. */
+  int prim_id;
+
+  /* Padding. */
+  int pad1, pad2, pad3;
+} KernelLightTreeEmitter;
+static_assert_align(KernelLightTreeEmitter, 16);
+
 typedef struct KernelParticle {
   int index;
   float age;
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index e9407554cbe..7d07b3797ab 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -350,6 +350,7 @@ void LightManager::device_update_distribution(Device *,
     LightTree light_tree(light_prims, scene, 8);
     light_prims = light_tree.get_prims();
 
+    /* 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());
     for (int index = 0; index < linearized_bvh.size(); index++) {
@@ -374,8 +375,28 @@ void LightManager::device_update_distribution(Device *,
         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(num_distribution);
+    for (int index = 0; index < num_distribution; 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;
+    }
+    dscene->light_tree_emitters.copy_to_device();
   }
 
   /* triangles */
@@ -1099,6 +1120,7 @@ void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_ba
 {
   /* to-do: check if the light tree member variables need to be wrapped in a conditional too*/
   dscene->light_tree_nodes.free();
+  dscene->light_tree_emitters.free();
   dscene->light_distribution.free();
   dscene->lights.free();
   if (free_background) {
diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp
index 22930586d43..252f15ab997 100644
--- a/intern/cycles/scene/light_tree.cpp
+++ b/intern/cycles/scene/light_tree.cpp
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: Apache-2.0
  * Copyright 2011-2022 Blender Foundation */
 
+#include "scene/mesh.h"
+#include "scene/object.h"
 #include "scene/light_tree.h"
 
 CCL_NAMESPACE_BEGIN
@@ -62,7 +64,27 @@ BoundBox LightTreePrimitive::calculate_bbox(Scene *scene) const
   BoundBox bbox = BoundBox::empty;
 
   if (prim_id >= 0) {
-    /* to-do: handle mesh lights in the future. */
+    Object *object = scene->objects[object_id];
+    Mesh *mesh = static_cast<Mesh*>(object->get_geometry());
+    Mesh::Triangle triangle = mesh->get_triangle(prim_id - mesh->prim_offset);
+
+    float3 p[3] = {mesh->get_verts()[triangle.v[0]],
+                   mesh->get_verts()[triangle.v[1]],
+                   mesh->get_verts()[triangle.v[2]]};
+
+    /* instanced mesh lights have not applied their transform at this point.
+     * in this case, these points have to be transformed to get the proper
+     * spatial bound. */
+    if (!mesh->transform_applied) {
+      const Transform &tfm = object->get_tfm();
+      for (int i = 0; i < 3; i++) {
+        p[i] = transform_point(&tfm, p[i]);
+      }
+    }
+
+    for (int i = 0; i < 3; i++) {
+      bbox.grow(p[i]);
+    }
   }
   else {
     Light *lamp = scene->lights[lamp_id];
@@ -102,7 +124,29 @@ OrientationBounds LightTreePrimitive::calculate_bcone(Scene *scene) const
   OrientationBounds bcone = OrientationBounds::empty;
 
   if (prim_id >= 0) {
-    /* to-do: handle mesh lights in the future. */
+    Object *object = scene->objects[object_id];
+    Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
+    Mesh::Triangle triangle = mesh->get_triangle(prim_id - mesh->prim_offset);
+
+    float3 p[3] = {mesh->get_verts()[triangle.v[0]],
+                   mesh->get_verts()[triangle.v[1]],
+                   mesh->get_verts()[triangle.v[2]]};
+
+    /* instanced mesh lights have not applied their transform at this point.
+     * in this case, these points have to be transformed to get the proper
+     * spatial bound. */
+    if (!mesh->transform_applied) {
+      const Transform &tfm = object->get_tfm(

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list