[Bf-blender-cvs] [8ad56a0749e] soc-2022-many-lights-sampling: Fix: light tree fails with instanced objects

Jeffrey Liu noreply at git.blender.org
Thu Jul 21 22:46:43 CEST 2022


Commit: 8ad56a0749e0bab4ad0664cdf97798ba30be9af8
Author: Jeffrey Liu
Date:   Thu Jul 21 16:44:00 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB8ad56a0749e0bab4ad0664cdf97798ba30be9af8

Fix: light tree fails with instanced objects

This fixes the issue with instanced objects. The issue was related to
the fact that instanced objects were overwriting the same areas of the
lookup table for the triangle to light tree array.

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

M	intern/cycles/kernel/data_arrays.h
M	intern/cycles/kernel/integrator/shade_surface.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/object.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 a22200c58eb..28fcfb4a2cf 100644
--- a/intern/cycles/kernel/data_arrays.h
+++ b/intern/cycles/kernel/data_arrays.h
@@ -65,6 +65,7 @@ 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, object_lookup_offset)
 KERNEL_DATA_ARRAY(uint, triangle_to_tree)
 
 /* particles */
diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h
index 7d403a84c1b..56fbad6711a 100644
--- a/intern/cycles/kernel/integrator/shade_surface.h
+++ b/intern/cycles/kernel/integrator/shade_surface.h
@@ -87,7 +87,9 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
       float3 ray_P = INTEGRATOR_STATE(state, ray, P);
       const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
       const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
-      pdf *= light_tree_pdf(kg, ray_P, N, sd->prim);
+      uint lookup_offset = kernel_data_fetch(object_lookup_offset, sd->object);
+      uint prim_offset = kernel_data_fetch(object_prim_offset, sd->object);
+      pdf *= light_tree_pdf(kg, ray_P, N, sd->prim - prim_offset + lookup_offset);
     }
     float mis_weight = light_sample_mis_weight_forward(kg, bsdf_pdf, pdf);
     L *= mis_weight;
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 3a193df9f17..8371bf71671 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -313,6 +313,7 @@ void LightManager::device_update_distribution(Device *device,
   bool light_tree_enabled = scene->integrator->get_use_light_tree();
   vector<LightTreePrimitive> light_prims;
   vector<LightTreePrimitive> distant_lights;
+  vector<uint> object_lookup_offsets(scene->objects.size());
 
   /* When we keep track of the light index, only contributing lights will be added to the device.
    * Therefore, we want to keep track of the light's index on the device.
@@ -353,16 +354,19 @@ void LightManager::device_update_distribution(Device *device,
     if (progress.get_cancel())
       return;
 
-    /* Count emissive triangles. */
-    Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
-    size_t mesh_num_triangles = mesh->num_triangles();
-    total_triangles += mesh_num_triangles;
-
     if (!object_usable_as_light(object)) {
       object_id++;
       continue;
     }
 
+    if (light_tree_enabled) {
+      object_lookup_offsets[object_id] = total_triangles;
+    }
+
+    /* Count emissive triangles. */
+    Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
+    size_t mesh_num_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()) ?
@@ -374,7 +378,7 @@ void LightManager::device_update_distribution(Device *device,
          * triangles. Right now, point lights are the main concern. */
         if (light_tree_enabled) {
           LightTreePrimitive light_prim;
-          light_prim.prim_id = i + mesh->prim_offset;
+          light_prim.prim_id = i;
           light_prim.object_id = object_id;
           light_prims.push_back(light_prim);
         }
@@ -383,6 +387,7 @@ void LightManager::device_update_distribution(Device *device,
       }
     }
 
+    total_triangles += mesh_num_triangles;
     object_id++;
   }
 
@@ -398,8 +403,13 @@ void LightManager::device_update_distribution(Device *device,
     /* 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 *object_offsets = dscene->object_lookup_offset.alloc(object_lookup_offsets.size());
     uint *triangle_array = dscene->triangle_to_tree.alloc(total_triangles);
 
+    for (int i = 0; i < object_lookup_offsets.size(); i++) {
+      object_offsets[i] = object_lookup_offsets[i];
+    }
+
     /* 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());
@@ -445,13 +455,12 @@ void LightManager::device_update_distribution(Device *device,
           light_tree_emitters[emitter_index].theta_o = bcone.theta_o;
           light_tree_emitters[emitter_index].theta_e = bcone.theta_e;
 
-          light_tree_emitters[emitter_index].prim_id = prim.prim_id;
-
           if (prim.prim_id >= 0) {
             light_tree_emitters[emitter_index].mesh_light.object_id = prim.object_id;
 
             int shader_flag = 0;
             Object *object = scene->objects[prim.object_id];
+            Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
             if (!(object->get_visibility() & PATH_RAY_CAMERA)) {
               shader_flag |= SHADER_EXCLUDE_CAMERA;
             }
@@ -471,11 +480,13 @@ void LightManager::device_update_distribution(Device *device,
               shader_flag |= SHADER_EXCLUDE_SHADOW_CATCHER;
             }
 
+            light_tree_emitters[emitter_index].prim_id = prim.prim_id + mesh->prim_offset;
             light_tree_emitters[emitter_index].mesh_light.shader_flag = shader_flag;
-            triangle_array[prim.prim_id] = emitter_index;
+            triangle_array[prim.prim_id + object_lookup_offsets[prim.object_id]] = emitter_index;
           }
           else {
             Light *lamp = scene->lights[prim.lamp_id];
+            light_tree_emitters[emitter_index].prim_id = prim.prim_id;
             light_tree_emitters[emitter_index].lamp.size = lamp->size;
             light_tree_emitters[emitter_index].lamp.pad = 1.0f;
             light_array[~prim.prim_id] = emitter_index;
@@ -557,6 +568,7 @@ void LightManager::device_update_distribution(Device *device,
     dscene->light_tree_emitters.copy_to_device();
     dscene->light_tree_distant_group.copy_to_device();
     dscene->light_to_tree.copy_to_device();
+    dscene->object_lookup_offset.copy_to_device();
     dscene->triangle_to_tree.copy_to_device();
   }
 
@@ -764,6 +776,7 @@ void LightManager::device_update_distribution(Device *device,
       dscene->light_tree_emitters.free();
       dscene->light_tree_distant_group.free();
       dscene->light_to_tree.free();
+      dscene->object_lookup_offset.free();
       dscene->triangle_to_tree.free();
     }
     dscene->light_distribution.free();
diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp
index 2c3c8cb880f..2db19912f50 100644
--- a/intern/cycles/scene/light_tree.cpp
+++ b/intern/cycles/scene/light_tree.cpp
@@ -73,7 +73,7 @@ BoundBox LightTreePrimitive::calculate_bbox(Scene *scene) const
   if (prim_id >= 0) {
     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);
+    Mesh::Triangle triangle = mesh->get_triangle(prim_id);
 
     float3 p[3] = {mesh->get_verts()[triangle.v[0]],
                    mesh->get_verts()[triangle.v[1]],
@@ -133,7 +133,7 @@ OrientationBounds LightTreePrimitive::calculate_bcone(Scene *scene) const
   if (prim_id >= 0) {
     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);
+    Mesh::Triangle triangle = mesh->get_triangle(prim_id);
 
     float3 p[3] = {mesh->get_verts()[triangle.v[0]],
                    mesh->get_verts()[triangle.v[1]],
@@ -196,8 +196,8 @@ float LightTreePrimitive::calculate_energy(Scene *scene) const
   if (prim_id >= 0) {
     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);
-    Shader *shader = static_cast<Shader*>(mesh->get_used_shaders()[mesh->get_shader()[prim_id - mesh->prim_offset]]);
+    Mesh::Triangle triangle = mesh->get_triangle(prim_id);
+    Shader *shader = static_cast<Shader*>(mesh->get_used_shaders()[mesh->get_shader()[prim_id]]);
 
     /* to-do: need a better way to handle this when textures are used. */
     if (!shader->is_constant_emission(&strength)) {
diff --git a/intern/cycles/scene/light_tree.h b/intern/cycles/scene/light_tree.h
index 0a768d32b2f..ff333a0d3b0 100644
--- a/intern/cycles/scene/light_tree.h
+++ b/intern/cycles/scene/light_tree.h
@@ -67,7 +67,7 @@ struct LightTreePrimitiveInfo {
 /* Light Tree Primitive
  * Struct that indexes into the scene's triangle and light arrays. */
 struct LightTreePrimitive {
-  /* prim_id >= 0 is an index into the global triangle index,
+  /* prim_id >= 0 is an index into an object's local triangle index,
    * otherwise -prim_id-1 is an index into device lights array.
    * */
   int prim_id;
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index 2126b23d82e..b3848c58501 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -558,10 +558,12 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
 
 void ObjectManager::device_update_prim_offsets(Device *device, DeviceScene *dscene, Scene *scene)
 {
-  BVHLayoutMask layout_mask = device->get_bvh_layout_mask();
-  if (layout_mask != BVH_LAYOUT_METAL && layout_mask != BVH_LAYOUT_MULTI_METAL &&
-      layout_mask != BVH_LAYOUT_MULTI_METAL_EMBREE) {
-    return;
+  if (!scene->integrator->get_use_light_tree()) {
+    BVHLayoutMask layout_mask = device->get_bvh_layout_mask();
+    if (layout_mask != BVH_LAYOUT_METAL && layout_mask != BVH_LAYOUT_MULTI_METAL &&
+        layout_mask != BVH_LAYOUT_MULTI_METAL_EMBREE) {
+      return;
+    }
   }
 
   /* On MetalRT, primitive / curve segment offsets can't be baked at BVH build time. Intersection
diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list