[Bf-blender-cvs] [59fffd32626] soc-2022-many-lights-sampling: Fix: Cycles light tree construction/traversal bugs
Jeffrey Liu
noreply at git.blender.org
Sat Jun 18 10:01:55 CEST 2022
Commit: 59fffd326262122d291829188a3ec75f04c53980
Author: Jeffrey Liu
Date: Sat Jun 18 04:01:50 2022 -0400
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB59fffd326262122d291829188a3ec75f04c53980
Fix: Cycles light tree construction/traversal bugs
===================================================================
M intern/cycles/kernel/light/light_tree.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/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h
index 7cff13b7c97..87c49ebc30c 100644
--- a/intern/cycles/kernel/light/light_tree.h
+++ b/intern/cycles/kernel/light/light_tree.h
@@ -21,7 +21,7 @@ ccl_device float light_tree_bounding_box_angle(const float3 bbox_min,
corners[6] = make_float3(bbox_max.x, bbox_max.y, bbox_min.z);
corners[7] = bbox_max;
for (int i = 0; i < 8; ++i) {
- float3 point_to_corner = normalize(P - corners[i]);
+ float3 point_to_corner = normalize(corners[i] - P);
const float cos_theta_u = dot(point_to_centroid, point_to_corner);
theta_u = fmaxf(fast_acosf(cos_theta_u), theta_u);
}
@@ -41,9 +41,12 @@ ccl_device float light_tree_node_importance(const float3 P,
const float energy)
{
const float3 centroid = 0.5f * bbox_min + 0.5f * bbox_max;
- const float3 point_to_centroid = normalize(P - centroid);
+ const float3 point_to_centroid = normalize(centroid - P);
- const float distance_squared = len_squared(P - centroid);
+ /* Since we're not using the splitting heuristic, we clamp
+ * the distance to half the radius of the cluster. */
+ const float distance_squared = fminf(len_squared(centroid - P),
+ 0.25f * len_squared(bbox_max - centroid));
const float theta = fast_acosf(dot(bcone_axis, -point_to_centroid));
const float theta_i = fast_acosf(dot(point_to_centroid, N));
@@ -51,17 +54,15 @@ ccl_device float light_tree_node_importance(const float3 P,
/* 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);
- /* to-do: this is also a rough heuristic to see if any contribution is possible.
- * In the paper, this is only theta_e, but this seems to be off for point lights. */
- if (theta_prime >= theta_o + theta_e) {
+ const float theta_prime = fmaxf(theta - theta_o - theta_u, 0);
+ if (theta_prime >= theta_e) {
return 0;
}
- const float cos_theta_prime = cosf(theta_prime);
+ const float cos_theta_prime = fast_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));
+ if (theta_i - theta_u > 0) {
+ cos_theta_i_prime = fabsf(fast_cosf(theta_i - theta_u));
}
/* to-do: find a good approximation for this value. */
@@ -160,11 +161,16 @@ ccl_device bool light_tree_sample(KernelGlobals kg,
const float left_probability = left_importance / (left_importance + right_importance);
if (tree_u < left_probability) {
+ index = index + 1;
knode = left;
+ tree_u = tree_u * (left_importance + right_importance) / left_importance;
*pdf_factor *= left_probability;
}
else {
+ index = knode->child_index;
knode = right;
+ tree_u = (tree_u * (left_importance + right_importance) - left_importance) /
+ right_importance;
*pdf_factor *= (1 - left_probability);
}
}
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 86a235815c7..aa04bf4986c 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -352,6 +352,7 @@ void LightManager::device_update_distribution(Device *,
for (int index = 0; index < linearized_bvh.size(); index++) {
const PackedLightTreeNode &node = linearized_bvh[index];
+ light_tree_nodes[index].energy = node.energy;
for (int i = 0; i < 3; i++) {
light_tree_nodes[index].bounding_box_min[i] = node.bbox.min[i];
light_tree_nodes[index].bounding_box_max[i] = node.bbox.max[i];
@@ -536,6 +537,7 @@ void LightManager::device_update_distribution(Device *,
* the light has been sampled through the light distribution.
* Therefore, we override it for now and adjust the pdf manually in the light tree.*/
if (scene->integrator->get_use_light_tree()) {
+ kintegrator->pdf_triangles = 1.0f;
kintegrator->pdf_lights = 1.0f;
}
else {
diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp
index 35c3d11104e..d50f257e6c7 100644
--- a/intern/cycles/scene/light_tree.cpp
+++ b/intern/cycles/scene/light_tree.cpp
@@ -37,9 +37,9 @@ OrientationBounds merge(const OrientationBounds& cone_a,
}
else {
/* Compute new theta_o that contains both a and b. */
- float theta_o = (theta_d + a->theta_o + b->theta_o) / 2;
+ float theta_o = (theta_d + a->theta_o + b->theta_o) * 0.5f;
- if (theta_o > M_PI_F) {
+ if (theta_o >= M_PI_F) {
return OrientationBounds({a->axis, M_PI_F, theta_e});
}
@@ -158,7 +158,7 @@ LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &p
LightTreeBuildNode *node = new LightTreeBuildNode();
total_nodes++;
BoundBox node_bbox = BoundBox::empty;
- OrientationBounds node_bcone;
+ OrientationBounds node_bcone = OrientationBounds::empty;
BoundBox centroid_bounds = BoundBox::empty;
float energy_total = 0.0;
float energy_squared_total = 0.0;
@@ -178,7 +178,7 @@ LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &p
float energy_variance = (energy_squared_total / num_prims) - (energy_total / num_prims) * (energy_total / num_prims);
/* to-do: find a better way to handle when all centroids overlap. */
- if (num_prims == 1 || centroid_bounds.area() == 0.0f) {
+ if (num_prims == 1 || len(centroid_bounds.size()) == 0.0f) {
int first_prim_offset = ordered_prims.size();
/* to-do: reduce this? */
for (int i = start; i < end; i++) {
@@ -257,7 +257,8 @@ void LightTree::split_saoh(const BoundBox ¢roid_bbox,
int& min_dim,
int& min_bucket)
{
- /* to-do: test without using this in the calculation, since it's the same for every bucket. */
+ /* Even though this factor is used for every bucket, we use it to compare
+ * the min_cost and total_energy (when deciding between creating a leaf or interior node. */
const float inv_total_cost = 1 / (bbox.area() * bcone.calculate_measure());
const float max_extent = max3(centroid_bbox.size());
@@ -305,22 +306,26 @@ void LightTree::split_saoh(const BoundBox ¢roid_bbox,
bcone_R = OrientationBounds::empty;
for (int left = 0; left <= split; left++) {
- energy_L += buckets[left].energy;
- bbox_L.grow(buckets[left].bbox);
- bcone_L = merge(bcone_L, buckets[left].bcone);
+ if (buckets[left].bbox.valid()) {
+ energy_L += buckets[left].energy;
+ bbox_L.grow(buckets[left].bbox);
+ bcone_L = merge(bcone_L, buckets[left].bcone);
+ }
}
for (int right = split + 1; right < LightTreeBucketInfo::num_buckets; right++) {
- energy_R += buckets[right].energy;
- bbox_R.grow(buckets[right].bbox);
- bcone_R = merge(bcone_R, buckets[right].bcone);
+ if (buckets[right].bbox.valid()) {
+ energy_R += buckets[right].energy;
+ bbox_R.grow(buckets[right].bbox);
+ bcone_R = merge(bcone_R, buckets[right].bcone);
+ }
}
/* Calculate the cost of splitting using the heuristic as described in the paper. */
- float left = energy_L * bbox_L.area() * bcone_L.calculate_measure();
- float right = energy_R * bbox_R.area() * bcone_R.calculate_measure();
+ float left = (bbox_L.valid()) ? energy_L * bbox_L.area() * bcone_L.calculate_measure() : 0.0f;
+ float right = (bbox_R.valid()) ? energy_R * bbox_R.area() * bcone_R.calculate_measure() : 0.0f;
float regularization = max_extent * inv_extent;
- bucket_costs[split] = regularization * left * right * inv_total_cost;
+ bucket_costs[split] = regularization * (left + right) * inv_total_cost;
if (bucket_costs[split] < min_cost) {
min_cost = bucket_costs[split];
diff --git a/intern/cycles/scene/light_tree.h b/intern/cycles/scene/light_tree.h
index 09afbb06e1f..7e2c427eea5 100644
--- a/intern/cycles/scene/light_tree.h
+++ b/intern/cycles/scene/light_tree.h
@@ -87,6 +87,10 @@ struct LightTreePrimitive {
/* Light Tree Bucket Info
* */
struct LightTreeBucketInfo {
+ LightTreeBucketInfo()
+ : energy(0.0f), bbox(BoundBox::empty), bcone(OrientationBounds::empty), count(0)
+ {}
+
float energy; /* Total energy in the partition */
BoundBox bbox;
OrientationBounds bcone;
More information about the Bf-blender-cvs
mailing list