[Bf-blender-cvs] [a7cd05d1502] soc-2022-many-lights-sampling: Cycles: use bit-trail for light tree pdf

Jeffrey Liu noreply at git.blender.org
Mon Aug 15 23:51:39 CEST 2022


Commit: a7cd05d15028dc71d341bf21ca6b49dcf3b9e784
Author: Jeffrey Liu
Date:   Mon Aug 15 17:50:47 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rBa7cd05d15028dc71d341bf21ca6b49dcf3b9e784

Cycles: use bit-trail for light tree pdf

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

M	intern/cycles/kernel/integrator/shade_light.h
M	intern/cycles/kernel/integrator/shade_surface.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

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

diff --git a/intern/cycles/kernel/integrator/shade_light.h b/intern/cycles/kernel/integrator/shade_light.h
index 697b9d13ca8..0857463ba53 100644
--- a/intern/cycles/kernel/integrator/shade_light.h
+++ b/intern/cycles/kernel/integrator/shade_light.h
@@ -63,7 +63,7 @@ ccl_device_inline void integrate_light(KernelGlobals kg,
     const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
     if (kernel_data.integrator.use_light_tree) {
       const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
-      ls.pdf *= light_tree_pdf(kg, ray_P, N, ~ls.lamp);
+      ls.pdf *= light_tree_pdf(kg, state, ray_P, N, ~ls.lamp);
     }
     const float mis_weight = light_sample_mis_weight_forward(kg, mis_ray_pdf, ls.pdf);
     light_eval *= mis_weight;
diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h
index e9a27924969..0b32680c017 100644
--- a/intern/cycles/kernel/integrator/shade_surface.h
+++ b/intern/cycles/kernel/integrator/shade_surface.h
@@ -133,7 +133,7 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
       const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
       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);
+      pdf *= light_tree_pdf(kg, state, 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/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h
index c15e6ebed37..0cdc5b58e8f 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -82,44 +82,20 @@ ccl_device float light_tree_node_importance(const float3 P,
 
 /* This is uniformly sampling the reservoir for now. */
 ccl_device float light_tree_emitter_reservoir_weight(KernelGlobals kg,
-                                                     const float randu,
-                                                     const float randv,
-                                                     const float time,
                                                      const float3 P,
                                                      const float3 N,
-                                                     const int bounce,
-                                                     const uint32_t path_flag,
                                                      int emitter_index)
 {
-  LightSample ls ccl_optional_struct_init;
   ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
                                                                          emitter_index);
-  bool sampled = true;
   const int prim = kemitter->prim_id;
-  if (prim >= 0) {
-    /* Mesh light. */
-    const int object = kemitter->mesh_light.object_id;
-
-    /* Exclude synthetic meshes from shadow catcher pass. */
-    if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) &&
-        !(kernel_data_fetch(object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) {
-      return 0.0f;
-    }
-
-    const int shader_flag = kemitter->mesh_light.shader_flag;
-    triangle_light_sample<false>(kg, prim, object, randu, randv, time, &ls, P);
-    ls.shader |= shader_flag;
 
-    sampled = ls.pdf > 0.0f;
-  }
-  else {
+  /* Triangles are handled normally for now. */
+  if (prim < 0) {
     const int lamp = -prim - 1;
 
-    if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
-      return 0.0f;
-    }
-
     const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
+    float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
 
     if (klight->type == LIGHT_SPOT) {
       /* to-do: since spot light importance sampling isn't the best,
@@ -141,14 +117,28 @@ ccl_device float light_tree_emitter_reservoir_weight(KernelGlobals kg,
         return 0.0f;
       }
     }
-    else {
-      sampled = light_sample<false>(kg, lamp, randu, randv, P, path_flag, &ls);
-    }
-  }
+    else if (klight->type == LIGHT_AREA) {
+      /* area light */
+      float3 axisu = make_float3(
+          klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
+      float3 axisv = make_float3(
+          klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
+      float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
+      bool is_round = (klight->area.invarea < 0.0f);
+
+      if (dot(light_P - P, Ng) > 0.0f) {
+        return 0.0f;
+      }
 
-  
-  if (sampled == 0.0f) {
-    return 0.0f;
+      if (!is_round) {
+        if (klight->area.tan_spread > 0.0f) {
+          if (!light_spread_clamp_area_light(
+                  P, Ng, &light_P, &axisu, &axisv, klight->area.tan_spread)) {
+            return 0.0f;
+          }
+        }
+      }
+    }
   }
 
   return 1.0f;
@@ -327,7 +317,7 @@ ccl_device bool light_tree_sample(KernelGlobals kg,
       }
 
       const float light_weight = light_tree_emitter_reservoir_weight(
-          kg, time, *randu, randv, P, N, bounce, path_flag, selected_light);
+          kg, P, N, selected_light);
       if (light_weight == 0.0f) {
         stack_index--;
         continue;
@@ -508,7 +498,11 @@ ccl_device bool 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)
+ccl_device float light_tree_pdf(KernelGlobals kg,
+                                ConstIntegratorState state,
+                                const float3 P,
+                                const float3 N,
+                                const int prim)
 {
   float distant_light_importance = light_tree_distant_light_importance(
       kg, P, N, kernel_data.integrator.num_distant_lights);
@@ -525,52 +519,124 @@ ccl_device float light_tree_pdf(KernelGlobals kg, const float3 P, const float3 N
                                     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);
+  ccl_global const KernelLightTreeNode *kleaf = &kernel_data_fetch(light_tree_nodes,
+                                                                   kemitter->parent_index);
 
-  /* 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++) {
-    /* At a leaf node, the negative value is the index into first prim. */
-    int prim = i - kleaf->child_index;
-    const float importance = light_tree_emitter_importance(kg, P, N, prim);
-    if (prim == emitter) {
-      emitter_importance = importance;
+  /* We generate a random number to use for selecting a light. */
+  RNGState rng_state;
+  path_state_rng_load(state, &rng_state);
+  float randu = path_state_rng_1D_hash(kg, &rng_state, 0x6a21694c);
+
+  /* We traverse to the leaf node and
+   * find the probability of selecting the target light. */
+  const int stack_size = 32;
+  int stack[stack_size];
+  float pdfs[stack_size];
+  int stack_index = 0;
+  stack[0] = 0;
+  pdfs[0] = 1.0f;
+
+  float light_tree_pdf = 0.0f;
+  float light_leaf_pdf = 0.0f;
+  float total_weight = 0.0f;
+  float target_weight = 0.0f;
+
+  uint bit_trail = kleaf->bit_trail;
+  while (stack_index >= 0) {
+    const float pdf = pdfs[stack_index];
+    const int index = stack[stack_index];
+    const ccl_global KernelLightTreeNode *knode = &kernel_data_fetch(light_tree_nodes, index);
+
+    if (knode->child_index <= 0) {
+      int selected_light = -1;
+      float light_weight = 0.0f;
+
+      /* If we're at the leaf node containing the light we need, 
+       * then we iterate through the lights to find the target emitter.
+       * Otherwise, we randomly select one. */
+      if (index == emitter) {
+        light_tree_pdf = pdf;
+
+        float target_emitter_importance = 0.0f;
+        float total_emitter_importance = 0.0f;
+        for (int i = 0; i < knode->num_prims; i++) {
+          const int prim_index = -knode->child_index + i;
+          float light_importance = light_tree_emitter_importance(kg, P, N, prim_index);
+          ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(
+              light_tree_emitters, prim_index);
+          if (kemitter->prim_id == prim) {
+            selected_light = prim_index;
+            light_weight = light_tree_emitter_reservoir_weight(kg, P, N, selected_light);
+            target_weight = light_weight;
+            target_emitter_importance = light_importance;
+          }
+          total_emitter_importance += light_importance;
+        }
+
+        light_leaf_pdf = target_emitter_importance / total_emitter_importance;
+      }
+      else {
+        float light_probability = 1.0f;
+        const int selected_light = light_tree_cluster_select_emitter(
+            kg, &randu, P, N, knode, &light_probability);
+        light_weight = light_tree_emitter_reservoir_weight(kg, P, N, selected_light);
+      }
+
+      if (selected_light < 0) {
+        stack_index--;
+        continue;
+      }
+
+      if (light_weight == 0.0f) {
+        stack_index--;
+        continue;
+      }
+      total_weight += light_weight;
+
+      stack_index--;
+      continue;
+    }
+
+    /* At an interior node, the left child is directly after the parent,
+     * while the right child is stored as the child index.
+     * We adaptively split if the variance is high enough. */
+    const int left_index = index + 1;
+    const int right_index = knode->child_index;
+    if (light_tree_should_split(kg, P, knode) && stack_index < stack_size - 1) {
+      stack[stack_index] = left_index;

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list