[Bf-blender-cvs] [d32f60b85e4] soc-2022-many-lights-sampling: begin implementation of cycles light tree

Jebbly noreply at git.blender.org
Fri Jun 10 16:32:58 CEST 2022


Commit: d32f60b85e4c296622350bf6d8814f4f8ed1127f
Author: Jebbly
Date:   Wed Apr 13 17:50:17 2022 -0500
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rBd32f60b85e4c296622350bf6d8814f4f8ed1127f

begin implementation of cycles light tree

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

M	intern/cycles/blender/addon/presets.py
M	intern/cycles/blender/addon/properties.py
M	intern/cycles/blender/addon/ui.py
M	intern/cycles/blender/sync.cpp
M	intern/cycles/scene/CMakeLists.txt
M	intern/cycles/scene/integrator.cpp
M	intern/cycles/scene/integrator.h
M	intern/cycles/scene/light.cpp
A	intern/cycles/scene/light_tree.cpp
A	intern/cycles/scene/light_tree.h
M	intern/cycles/scene/scene.cpp
M	intern/cycles/scene/scene.h

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

diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py
index cc6d574da99..82c3091a619 100644
--- a/intern/cycles/blender/addon/presets.py
+++ b/intern/cycles/blender/addon/presets.py
@@ -49,6 +49,8 @@ class AddPresetSampling(AddPresetBase, Operator):
         "cycles.samples",
         "cycles.adaptive_threshold",
         "cycles.adaptive_min_samples",
+        "cycles.use_light_tree",
+        "cycles.splitting_threshold",
         "cycles.time_limit",
         "cycles.use_denoising",
         "cycles.denoiser",
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index b444a806f8d..a391be0bca2 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -471,6 +471,19 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
         default='MULTIPLE_IMPORTANCE_SAMPLING',
     )
 
+    use_light_tree: BoolProperty(
+        name="Light Tree",
+        description="Samples many lights more efficiently",
+        default=False,
+    )
+
+    splitting_threshold: FloatProperty(
+        name="Splitting",
+        description="Amount of lights to sample at a time, from one light at 0.0, to adaptively more lights as needed, to all lights at 1.0",
+        min=0.0, max=1.0,
+        default=0.85,
+    )
+
     min_light_bounces: IntProperty(
         name="Min Light Bounces",
         description="Minimum number of light bounces. Setting this higher reduces noise in the first bounces, "
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 88be546746d..0194664c222 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -310,6 +310,34 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
                 layout.row().prop(cscene, "use_layer_samples")
                 break
 
+class CYCLES_RENDER_PT_sampling_light_tree(CyclesButtonsPanel, Panel):
+    bl_label = "Many Lights Sampling"
+    bl_parent_id = "CYCLES_RENDER_PT_sampling"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.scene.cycles.feature_set == 'EXPERIMENTAL')
+
+    def draw_header(self, context):
+        layout = self.layout
+        scene = context.scene
+        cscene = scene.cycles
+
+        layout.prop(cscene, "use_light_tree", text="")
+
+    def draw(self, context):
+        layout = self.layout
+        layout.use_property_split = True
+        layout.use_property_decorate = False
+
+        scene = context.scene
+        cscene = scene.cycles
+
+        layout.active = cscene.use_light_tree
+        col = layout.column(align=True)
+        col.prop(cscene, "splitting_threshold", text="Split Threshold")
+
 
 class CYCLES_RENDER_PT_subdivision(CyclesButtonsPanel, Panel):
     bl_label = "Subdivision"
@@ -2269,6 +2297,7 @@ classes = (
     CYCLES_RENDER_PT_sampling_render,
     CYCLES_RENDER_PT_sampling_render_denoise,
     CYCLES_RENDER_PT_sampling_advanced,
+    CYCLES_RENDER_PT_sampling_light_tree,
     CYCLES_RENDER_PT_light_paths,
     CYCLES_RENDER_PT_light_paths_max_bounces,
     CYCLES_RENDER_PT_light_paths_clamping,
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index 1028c940772..e008443531f 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -340,6 +340,8 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
     integrator->set_motion_blur(view_layer.use_motion_blur);
   }
 
+  integrator->set_use_light_tree(get_boolean(cscene, "use_light_tree"));
+  integrator->set_splitting_threshold(get_float(cscene, "splitting_threshold"));
   integrator->set_light_sampling_threshold(get_float(cscene, "light_sampling_threshold"));
 
   SamplingPattern sampling_pattern = (SamplingPattern)get_enum(
diff --git a/intern/cycles/scene/CMakeLists.txt b/intern/cycles/scene/CMakeLists.txt
index 4904bf247ba..32e9fd09b82 100644
--- a/intern/cycles/scene/CMakeLists.txt
+++ b/intern/cycles/scene/CMakeLists.txt
@@ -25,6 +25,7 @@ set(SRC
   integrator.cpp
   jitter.cpp
   light.cpp
+  light_tree.cpp
   mesh.cpp
   mesh_displace.cpp
   mesh_subdivision.cpp
@@ -64,6 +65,7 @@ set(SRC_HEADERS
   image_vdb.h
   integrator.h
   light.h
+  light_tree.h
   jitter.h
   mesh.h
   object.h
diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp
index fda6ecc8d14..7df74614d93 100644
--- a/intern/cycles/scene/integrator.cpp
+++ b/intern/cycles/scene/integrator.cpp
@@ -84,7 +84,9 @@ NODE_DEFINE(Integrator)
   SOCKET_FLOAT(adaptive_threshold, "Adaptive Threshold", 0.01f);
   SOCKET_INT(adaptive_min_samples, "Adaptive Min Samples", 0);
 
-  SOCKET_FLOAT(light_sampling_threshold, "Light Sampling Threshold", 0.01f);
+  SOCKET_FLOAT(light_sampling_threshold, "Light Sampling Threshold", 0.05f);
+  SOCKET_BOOLEAN(use_light_tree, "Use light tree to optimize many light sampling", false);
+  SOCKET_FLOAT(splitting_threshold, "Splitting threshold (NEED EDITING)", 0.85f);
 
   static NodeEnum sampling_pattern_enum;
   sampling_pattern_enum.insert("sobol", SAMPLING_PATTERN_SOBOL);
diff --git a/intern/cycles/scene/integrator.h b/intern/cycles/scene/integrator.h
index d54a44b6177..1d9604d58f1 100644
--- a/intern/cycles/scene/integrator.h
+++ b/intern/cycles/scene/integrator.h
@@ -68,6 +68,8 @@ class Integrator : public Node {
   NODE_SOCKET_API(int, start_sample)
 
   NODE_SOCKET_API(float, light_sampling_threshold)
+  NODE_SOCKET_API(bool, use_light_tree)
+  NODE_SOCKET_API(float, splitting_threshold)
 
   NODE_SOCKET_API(bool, use_adaptive_sampling)
   NODE_SOCKET_API(int, adaptive_min_samples)
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 5e311d3051f..402fca968ac 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -24,6 +24,8 @@
 #include "util/progress.h"
 #include "util/task.h"
 
+#include <iostream>
+
 CCL_NAMESPACE_BEGIN
 
 static void shade_background_pixels(Device *device,
@@ -389,6 +391,7 @@ void LightManager::device_update_distribution(Device *,
   }
 
   float trianglearea = totarea;
+  std::cout << "TOTAL AREA: " << trianglearea << std::endl;
   /* point lights */
   bool use_lamp_mis = false;
   int light_index = 0;
diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp
new file mode 100644
index 00000000000..c0baa35ab74
--- /dev/null
+++ b/intern/cycles/scene/light_tree.cpp
@@ -0,0 +1,208 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "scene/light_tree.h"
+
+CCL_NAMESPACE_BEGIN
+
+float OrientationBounds::calculate_measure() const
+{
+  float theta_w = fminf(M_PI_F, theta_o + theta_e);
+  float cos_theta_o = cosf(theta_o);
+  float sin_theta_o = sinf(theta_o);
+
+  return M_2PI_F * (1 - cos_theta_o) +
+         M_PI_2_F * (2 * theta_w * sin_theta_o - cosf(theta_o - 2 * theta_w) -
+                     2 * theta_o * sin_theta_o + cos_theta_o);
+}
+
+OrientationBounds merge(const OrientationBounds& cone_a, 
+						const OrientationBounds& cone_b)
+{
+  /* Set cone a to always have the greater theta_o. */
+  const OrientationBounds *a = &cone_a;
+  const OrientationBounds *b = &cone_b;
+  if (cone_b.theta_o > cone_a.theta_o) {
+    a = &cone_b;
+    b = &cone_a;
+  }
+
+  float theta_d = safe_acosf(dot(a->axis, b->axis));
+  float theta_e = fmaxf(a->theta_e, b->theta_e);
+
+  /* Return axis and theta_o of a if it already contains b. */
+  if (a->theta_o >= fminf(M_PI_F, theta_d + b->theta_o)) {
+    return OrientationBounds({a->axis, a->theta_o, theta_e});
+  }
+  else {
+    /* Compute new theta_o that contains both a and b. */
+    float theta_o = (theta_d + a->theta_o + b->theta_o) / 2;
+
+    if (theta_o > M_PI_F) {
+      return OrientationBounds({a->axis, M_PI_F, theta_e});
+    }
+
+    /* TODO: test if vectors can just be averaged. */
+    /* Rotate new axis to be between a and b. */
+    float theta_r = theta_o - a->theta_o;
+    float3 new_axis = rotate_around_axis(a->axis, cross(a->axis, b->axis), theta_r);
+    new_axis = normalize(new_axis);
+
+    return OrientationBounds({new_axis, theta_o, theta_e});
+  }
+}
+
+void LightTreeBuildNode::init_leaf(
+    uint offset, uint n, const BoundBox &b, const OrientationBounds &c, float e, float e_var)
+{
+  bbox = b;
+  bcone = c;
+  energy = e;
+  energy_variance = e_var;
+  first_prim_index = offset;
+  num_lights = n;
+
+  children[0] = children[1] = nullptr;
+  is_leaf = true;
+}
+
+void LightTreeBuildNode::init_interior(LightTreeBuildNode *c0, LightTreeBuildNode *c1)
+{
+  bbox = merge(c0->bbox, c1->bbox);
+  bcone = merge(c0->bcone, c1->bcone);
+  energy = c0->energy + c1->energy;
+  energy_variance = c0->energy_variance + c1->energy_variance;
+  first_prim_index = 0;
+  num_lights = 0;
+
+  children[0] = c0;
+  children[1] = c1;
+  is_leaf = false;
+}
+
+LightTree::LightTree(const vector<LightTreePrimitive> &prims, Scene *scene, uint max_lights_in_leaf)
+{
+  prims_ = prims;
+  scene_ = scene;
+  max_lights_in_leaf_ = max_lights_in_leaf;
+
+  vector<LightTreePrimitiveInfo> build_data(prims.size());
+  for (int i = 0; i < prims.size(); i++) {
+    LightTreePrimitiveInfo prim_info;
+    prim_info.bbox = calculate_bbox(prims[i]);
+    prim_info.bcone = calculate_bcone(prims[i]);
+    prim_info.energy = calculate_energy(prims[i]);
+    prim_info.centroid = prim_info.bbox.center();
+    prim_info.prim_num = i;
+    build_data.push_back(prim_info);
+  }
+
+  int total_nodes = 0;
+  vector<LightTreePrimitive> ordered_prims;
+  LightTreeBuildNode *root;
+  root = recursive_build(build_data, 0, prims.size(), total_nodes, ordered_prims);
+  prims_ = ordered_prims;
+}
+
+LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &primitive_info,
+                                               int start,
+                                               int end,
+                                               int &total_nodes,
+                                               vector<LightTreePrimitive> &ordered_prims)
+{
+  LightTreeBuildNode *node = new LightTreeBuildNode();
+  total_nodes++;
+  BoundBox node

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list