[Bf-blender-cvs] [ef7d2d931a5] soc-2022-many-lights-sampling: Cycles: integrate light tree sampling into device kernel (WIP)
Jeffrey Liu
noreply at git.blender.org
Tue Jun 14 08:13:59 CEST 2022
Commit: ef7d2d931a5ead8ea983f8ad4cfb48734a6c6e21
Author: Jeffrey Liu
Date: Tue Jun 14 01:58:42 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rBef7d2d931a5ead8ea983f8ad4cfb48734a6c6e21
Cycles: integrate light tree sampling into device kernel (WIP)
===================================================================
M intern/cycles/kernel/CMakeLists.txt
M intern/cycles/kernel/integrator/shade_surface.h
A intern/cycles/kernel/light/light_tree.h
===================================================================
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 473bdb67920..c1279bfba51 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -246,6 +246,7 @@ set(SRC_KERNEL_INTEGRATOR_HEADERS
set(SRC_KERNEL_LIGHT_HEADERS
light/light.h
+ light/light_tree.h
light/background.h
light/common.h
light/sample.h
diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h
index ce1398859b7..d08ddca2291 100644
--- a/intern/cycles/kernel/integrator/shade_surface.h
+++ b/intern/cycles/kernel/integrator/shade_surface.h
@@ -14,6 +14,7 @@
#include "kernel/integrator/volume_stack.h"
#include "kernel/light/light.h"
+#include "kernel/light/light_tree.h"
#include "kernel/light/sample.h"
CCL_NAMESPACE_BEGIN
@@ -114,9 +115,17 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
float light_u, light_v;
path_state_rng_2D(kg, rng_state, PRNG_LIGHT_U, &light_u, &light_v);
- if (!light_distribution_sample_from_position(
- kg, light_u, light_v, sd->time, sd->P, bounce, path_flag, &ls)) {
- return;
+ if (kg->__data.integrator.use_light_tree) {
+ if (!light_tree_sample_from_position(
+ kg, rng_state, light_u, light_v, sd->time, sd->N, sd->P, bounce, path_flag, &ls)) {
+ return;
+ }
+ }
+ else {
+ if (!light_distribution_sample_from_position(
+ kg, light_u, light_v, sd->time, sd->P, bounce, path_flag, &ls)) {
+ return;
+ }
}
}
diff --git a/intern/cycles/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h
new file mode 100644
index 00000000000..19e57c88152
--- /dev/null
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -0,0 +1,202 @@
+#pragma once
+
+#include "kernel/light/light.h"
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device float light_tree_bounding_box_angle(KernelGlobals kg,
+ const float3 bbox_min,
+ const float3 bbox_max,
+ const float3 P)
+{
+ return 0;
+}
+
+/* This is the general function for calculating the importance of either a cluster or an emitter.
+ * Both of the specialized functions obtain the necessary data before calling this function.
+ * to-do: find a better way to handle this? */
+ccl_device float light_tree_node_importance(const float3 P,
+ const float3 N,
+ const float3 bbox_min,
+ const float3 bbox_max,
+ const float3 bcone_axis,
+ const float theta_o,
+ const float theta_e,
+ const float energy)
+{
+ const float3 centroid = 0.5f * bbox_min + 0.5f * bbox_max;
+ const float3 point_to_centroid = P - centroid;
+ const float3 point_to_bbox_max = P - bbox_max;
+
+ const float distance_squared = len_squared(point_to_centroid);
+
+ const float theta = fast_acosf(dot(bcone_axis, -point_to_centroid));
+ const float theta_i = fast_acosf(dot(point_to_centroid, N));
+ const float theta_u = fast_acosf(dot(point_to_centroid, point_to_bbox_max));
+
+ /* to-do: compare this with directly using fmaxf and cosf. */
+ /* Avoid using cosine until needed. */
+ const float theta_prime = fmaxf(theta_i - theta_u, 0);
+ if (theta_prime >= theta_e) {
+ return 0;
+ }
+ const float cos_theta_prime = cosf(theta_prime);
+
+ float cos_theta_i_prime = 1;
+ if (theta - theta_o - theta_u > 0) {
+ cos_theta_i_prime = fabsf(cosf(theta - theta_o - theta_u));
+ }
+
+ /* to-do: find a good approximation for this value. */
+ const float f_a = 1;
+
+ float importance = f_a * cos_theta_i_prime * energy / distance_squared * cos_theta_prime;
+ return importance;
+}
+
+ccl_device float light_tree_emitter_importance(KernelGlobals kg,
+ const float3 P,
+ const float3 N,
+ int emitter_index)
+{
+ ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution,
+ emitter_index);
+ const int prim = kdistribution->prim;
+
+ if (prim >= 0) {
+ /* to-do: handle case for mesh lights. */
+ }
+ else {
+ const int lamp = -prim - 1;
+ const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ if (klight->type == LIGHT_POINT) {
+ 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 rgb_strength = make_float3(
+ klight->strength[0], klight->strength[1], klight->strength[2]);
+
+ /* to-do: only the radius and invarea from the spotlight properties is used for a point light,
+ * but we still need to choose an arbitrary direction. Maybe this can be replaced with something else? */
+ const float3 bcone_axis = make_float3(
+ klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[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));
+ }
+ }
+
+}
+
+ccl_device float light_tree_cluster_importance(KernelGlobals kg,
+ const float3 P,
+ const float3 N,
+ const ccl_global KernelLightTreeNode *knode)
+{
+ /* Convert the data from the struct into float3 for calculations. */
+ const float3 bbox_min = make_float3(
+ knode->bounding_box_min[0], knode->bounding_box_min[1], knode->bounding_box_min[2]);
+ const float3 bbox_max = make_float3(
+ knode->bounding_box_max[0], knode->bounding_box_max[1], knode->bounding_box_max[2]);
+ const float3 bcone_axis = make_float3(
+ knode->bounding_cone_axis[0], knode->bounding_cone_axis[1], knode->bounding_cone_axis[1]);
+
+ return light_tree_node_importance(
+ P, N, bbox_min, bbox_max, bcone_axis, knode->theta_o, knode->theta_e, knode->energy);
+}
+
+
+/* to-do: for now, we're not going to worry about being in a volume for now,
+ * but this seems to be a good way to differentiate whether we're in a volume or not. */
+template<bool in_volume_segment>
+ccl_device bool light_tree_sample(KernelGlobals kg,
+ ccl_private const RNGState *rng_state,
+ float randu,
+ const float randv,
+ const float time,
+ const float3 N,
+ const float3 P,
+ const int bounce,
+ const uint32_t path_flag,
+ ccl_private LightSample *ls,
+ float *pdf_factor)
+{
+ /* First traverse the light tree until a leaf node is reached. */
+ /* Also keep track of the probability of traversing to a given node, */
+ /* so that we can scale our PDF accordingly later. */
+ int index = 0;
+
+ /* to-do: is it better to generate a new random sample for each step of the traversal? */
+ float tree_u = path_state_rng_1D(kg, rng_state, 1);
+ const ccl_global KernelLightTreeNode *knode = &kernel_tex_fetch(__light_tree_nodes, index);
+ while (knode->child_index > 0) {
+ /* At an interior node, the left child is directly next to the parent,
+ * while the right child is stored as the child index. */
+ const ccl_global KernelLightTreeNode *left = &kernel_tex_fetch(__light_tree_nodes, index + 1);
+ const ccl_global KernelLightTreeNode *right = &kernel_tex_fetch(__light_tree_nodes, knode->child_index);
+
+ const float left_importance{light_tree_cluster_importance(kg, P, N, left)};
+ const float right_importance{light_tree_cluster_importance(kg, P, N, right)};
+ const float left_probability = left_importance / (left_importance + right_importance);
+
+ if (tree_u < left_probability) {
+ knode = left;
+ *pdf_factor *= left_probability;
+ }
+ else {
+ knode = right;
+ *pdf_factor *= (1 - left_probability);
+ }
+ }
+
+ /* Once we're at a leaf node, we can sample from the cluster of primitives inside.
+ * Right now, this is done by incrementing the CDF by the PDF.
+ * However, we first need to calculate the total importance so that we can normalize the CDF. */
+ float total_emitter_importance = 0.0f;
+ for (int i = 0; i < knode->num_prims; i++) {
+ const int prim_index = -knode->child_index + i;
+ total_emitter_importance += light_tree_emitter_importance(kg, P, N, prim_index);
+ }
+ const float inv_total_importance = 1 / total_emitter_importance;
+
+
+ /* Once we have the total importance, we can normalize the CDF and sample it. */
+ float emitter_cdf = 0.0f;
+ for (int i = 0; i < knode->num_prims; i++) {
+ const int prim_index = -knode->child_index + i;
+ /* to-do: is there any way to cache these values, so that recalculation isn't needed?
+ * At the very least, we can maybe store the total importance during light tree construction
+ * so that the first for loop isn't necessary. */
+ const float emitter_pdf{light_tree_emitter_importance(kg, P, N, prim_index)};
+ emitter_cdf += emitter_pdf * inv_total_importance;
+ if (tree_u < emitter_cdf) {
+ *pdf_factor *= emitter_pdf;
+ return light_sample<in_volume_segment>(kg, prim_index, randu, randv, P, path_flag, ls);
+ }
+ }
+
+ /* We should never reach this point. */
+ assert(false);
+}
+
+ccl_device bool light_tree_sample_from_position(KernelGlobals kg,
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list