[Bf-blender-cvs] [ec81cfab34f] soc-2022-many-lights-sampling: Cycles: implement calculation for light tree pdf
Jeffrey Liu
noreply at git.blender.org
Sat Jul 9 06:57:06 CEST 2022
Commit: ec81cfab34f5cb3fd495f439c114744ea7eeddca
Author: Jeffrey Liu
Date: Thu Jul 7 15:28:56 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rBec81cfab34f5cb3fd495f439c114744ea7eeddca
Cycles: implement calculation for light tree pdf
===================================================================
M intern/cycles/kernel/data_arrays.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
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 42e6e88509d..a22200c58eb 100644
--- a/intern/cycles/kernel/data_arrays.h
+++ b/intern/cycles/kernel/data_arrays.h
@@ -64,6 +64,8 @@ KERNEL_DATA_ARRAY(float2, light_background_conditional_cdf)
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, triangle_to_tree)
/* particles */
KERNEL_DATA_ARRAY(KernelParticle, particles)
diff --git a/intern/cycles/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h
index 57f2792cc35..cf7e9c2ee18 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -243,7 +243,7 @@ ccl_device int light_tree_sample(KernelGlobals kg,
/* We should never reach this point. */
assert(false);
- return false;
+ return -1;
}
/* to-do: assign relative importances for the background and distant lights.
@@ -289,7 +289,7 @@ ccl_device int light_tree_sample_distant_lights(KernelGlobals kg,
ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch(
light_tree_distant_group, i);
- const int lamp = -kdistant->prim_id - 1;
+ const int lamp = kdistant->prim_id;
if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
return false;
@@ -298,6 +298,10 @@ ccl_device int light_tree_sample_distant_lights(KernelGlobals kg,
return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls);
}
}
+
+ /* We should never reach this point. */
+ assert(false);
+ return -1;
}
ccl_device bool light_tree_sample_from_position(KernelGlobals kg,
@@ -329,4 +333,81 @@ ccl_device bool light_tree_sample_from_position(KernelGlobals kg,
return ret;
}
+/* 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)
+{
+ float pdf = kernel_data.integrator.pdf_light_tree;
+
+ const int emitter = (prim >= 0) ? kernel_data_fetch(triangle_to_tree, prim) : 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);
+
+ /* 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++) {
+ int prim = i - kleaf->child_index; /* At a leaf node, the negative value is the index into first prim. */
+ const float importance = light_tree_emitter_importance(kg, P, N, prim);
+ if (i == emitter) {
+ emitter_importance = importance;
+ }
+ total_importance += importance;
+ }
+ pdf *= emitter_importance / total_importance;
+
+ /* Next, we find the probability of traversing to that leaf node. */
+ int child_index = parent;
+ parent = kleaf->parent_index;
+ while (parent != -1) {
+ const ccl_global KernelLightTreeNode *kparent = &kernel_data_fetch(light_tree_nodes, parent);
+
+ const int left_index = parent + 1;
+ const int right_index = kparent->child_index;
+ const ccl_global KernelLightTreeNode *kleft = &kernel_data_fetch(light_tree_nodes, left_index);
+ const ccl_global KernelLightTreeNode *kright = &kernel_data_fetch(light_tree_nodes, right_index);
+
+ const float left_importance = light_tree_cluster_importance(kg, P, N, kleft);
+ const float right_importance = light_tree_cluster_importance(kg, P, N, kright);
+ const float left_probability = left_importance / (left_importance + right_importance);
+
+ /* If the child index matches the left index, then we must've traversed left, otherwise right. */
+ if (left_index == child_index) {
+ pdf *= left_probability;
+ }
+ else {
+ pdf *= (1 - left_probability);
+ }
+
+ child_index = parent;
+ parent = kparent->parent_index;
+ }
+
+ return pdf;
+}
+
+ccl_device float distant_lights_pdf(KernelGlobals kg, const float3 P, const float3 N, const int prim)
+{
+ float pdf = (1 - kernel_data.integrator.pdf_light_tree);
+
+ /* The light_to_tree array doubles as a lookup table for
+ * both the light tree as well as the distant lights group.*/
+ const int distant_light = kernel_data_fetch(light_to_tree, prim);
+ const int num_distant_lights = kernel_data.integrator.num_distant_lights;
+
+ float emitter_importance = 0.0f;
+ float total_importance = 0.0f;
+ for (int i = 0; i < num_distant_lights; i++) {
+ float importance = light_tree_distant_light_importance(kg, P, N, i);
+ if (i == distant_light) {
+ emitter_importance = importance;
+ }
+ total_importance += importance;
+ }
+
+ pdf *= emitter_importance / total_importance;
+ return pdf;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 3e9fcd19609..fc43a1b735a 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -1523,8 +1523,11 @@ typedef struct KernelLightTreeNode {
float energy_variance; /* interior nodes use the energy variance for the splitting heuristic. */
};
+ /* Parent. */
+ int parent_index;
+
/* Padding. */
- int pad1, pad2;
+ int pad1;
} KernelLightTreeNode;
static_assert_align(KernelLightTreeNode, 16);
@@ -1554,8 +1557,8 @@ typedef struct KernelLightTreeEmitter {
} lamp;
};
- /* Padding. */
- int pad1;
+ /* Parent. */
+ int parent_index;
} KernelLightTreeEmitter;
static_assert_align(KernelLightTreeEmitter, 16);
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 242665387ca..aeb8cd7a341 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -305,6 +305,7 @@ void LightManager::device_update_distribution(Device *device,
size_t num_background_lights = 0;
size_t num_distant_lights = 0;
size_t num_triangles = 0;
+ size_t total_triangles = 0;
bool background_mis = false;
@@ -360,6 +361,7 @@ void LightManager::device_update_distribution(Device *device,
/* Count emissive triangles. */
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
size_t mesh_num_triangles = mesh->num_triangles();
+ total_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()) ?
@@ -393,9 +395,15 @@ void LightManager::device_update_distribution(Device *device,
LightTree light_tree(light_prims, scene, 8);
light_prims = light_tree.get_prims();
+ /* 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 *triangle_array = dscene->triangle_to_tree.alloc(total_triangles);
+
/* 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());
+ KernelLightTreeEmitter *light_tree_emitters = dscene->light_tree_emitters.alloc(light_prims.size());
float light_tree_energy = 0.0f;
for (int index = 0; index < linearized_bvh.size(); index++) {
const PackedLightTreeNode &node = linearized_bvh[index];
@@ -413,70 +421,73 @@ void LightManager::device_update_distribution(Device *device,
light_tree_nodes[index].theta_o = node.bcone.theta_o;
light_tree_nodes[index].theta_e = node.bcone.theta_e;
+ light_tree_nodes[index].parent_index = node.parent_index;
+
/* Here we need to make a distinction between interior and leaf nodes. */
if (node.is_leaf_node) {
light_tree_nodes[index].num_prims = node.num_lights;
light_tree_nodes[index].child_index = -node.first_prim_index;
- }
- else {
- light_tree_nodes[index].energy_variance = node.energy_variance;
- 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(light_prims.size());
- for (int index = 0; index < light_prims.size(); 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;
- if (prim.prim_id >= 0) {
- light_tree_emitters[index].mesh_light.object_id = prim.object_id;
+ for (int i = 0; i < node.num_lights; i++) {
+ int emitter_index = i + node.first_prim_index;
+ LightTreePrimitive &prim = light_prims[emitter_index];
+ BoundBox bbox = prim.calculate_bbox(scene);
+ OrientationBounds bcone = prim.calculate_bcone(scene);
+ float energy = prim.calculate_energy(scene);
+
+ light_tree_emitters[emitter_index].energy = energy;
+ for (int i = 0; i < 3; i++) {
+ light_tree_emitters[emitter_index].bounding_box_min[i] = bbox.min[i];
+ light_tree_emitters[emitter_in
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list