[Bf-blender-cvs] [6ecbc49d82b] soc-2022-many-lights-sampling: Fix crashes and poor results with many lights on a line or same location
Brecht Van Lommel
noreply at git.blender.org
Thu Oct 20 20:29:57 CEST 2022
Commit: 6ecbc49d82b2f25cd59ea326d43dab0d7d4706c7
Author: Brecht Van Lommel
Date: Thu Oct 20 18:56:32 2022 +0200
Branches: soc-2022-many-lights-sampling
https://developer.blender.org/rB6ecbc49d82b2f25cd59ea326d43dab0d7d4706c7
Fix crashes and poor results with many lights on a line or same location
Better handle such degenerate cases.
===================================================================
M intern/cycles/scene/light_tree.cpp
===================================================================
diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp
index 87e26ba2250..775b4c0bc73 100644
--- a/intern/cycles/scene/light_tree.cpp
+++ b/intern/cycles/scene/light_tree.cpp
@@ -341,7 +341,7 @@ LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &p
float energy_variance = (energy_squared_total / num_prims) - sqr(energy_total / num_prims);
bool try_splitting = num_prims > 1 && len(centroid_bounds.size()) > 0.0f;
- int min_dim, min_bucket;
+ int min_dim = -1, min_bucket = 0;
bool should_split = false;
if (try_splitting) {
/* Find the best place to split the primitives into 2 nodes.
@@ -351,36 +351,46 @@ LightTreeBuildNode *LightTree::recursive_build(vector<LightTreePrimitiveInfo> &p
should_split = num_prims > max_lights_in_leaf_ || min_cost < energy_total;
}
if (should_split) {
- /* Partition the primitives between start and end into the appropriate split,
- * based on the minimum dimension and minimum bucket returned from split_saoh.
- * This is an O(n) algorithm where we iterate from the left and right side,
- * and swaps the appropriate left and right elements until complete. */
- int left = start, right = end - 1;
- float bounding_dimension = (min_bucket + 1) * (centroid_bounds.size()[min_dim] /
- LightTreeBucketInfo::num_buckets) +
- centroid_bounds.min[min_dim];
- while (left < right) {
- while (primitive_info[left].centroid[min_dim] <= bounding_dimension && left < end) {
- left++;
- }
+ int middle;
+
+ if (min_dim != -1) {
+ /* Partition the primitives between start and end into the appropriate split,
+ * based on the minimum dimension and minimum bucket returned from split_saoh.
+ * This is an O(n) algorithm where we iterate from the left and right side,
+ * and swaps the appropriate left and right elements until complete. */
+ int left = start, right = end - 1;
+ float bounding_dimension = (min_bucket + 1) * (centroid_bounds.size()[min_dim] /
+ LightTreeBucketInfo::num_buckets) +
+ centroid_bounds.min[min_dim];
+ while (left < right) {
+ while (primitive_info[left].centroid[min_dim] <= bounding_dimension && left < end) {
+ left++;
+ }
- while (primitive_info[right].centroid[min_dim] > bounding_dimension && right >= start) {
- right--;
- }
+ while (primitive_info[right].centroid[min_dim] > bounding_dimension && right >= start) {
+ right--;
+ }
- if (left < right) {
- LightTreePrimitiveInfo temp = primitive_info[left];
- primitive_info[left] = primitive_info[right];
- primitive_info[right] = temp;
+ if (left < right) {
+ LightTreePrimitiveInfo temp = primitive_info[left];
+ primitive_info[left] = primitive_info[right];
+ primitive_info[right] = temp;
+ }
}
+
+ middle = left;
+ }
+ else {
+ /* Degenerate case with many lights in the same place. */
+ middle = (start + end) / 2;
}
/* At this point, we should expect right to be just past left,
* where left points to the first element that belongs to the right node. */
LightTreeBuildNode *left_node = recursive_build(
- primitive_info, start, left, total_nodes, ordered_prims, bit_trail, depth + 1);
+ primitive_info, start, middle, total_nodes, ordered_prims, bit_trail, depth + 1);
LightTreeBuildNode *right_node = recursive_build(primitive_info,
- left,
+ middle,
end,
total_nodes,
ordered_prims,
@@ -417,7 +427,15 @@ float LightTree::min_split_saoh(const BoundBox ¢roid_bbox,
{
/* 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 bbox_area = bbox.area();
+ const bool has_area = bbox_area != 0.0f;
+ const float total_area = has_area ? bbox_area : len(bbox.size());
+ const float total_cost = total_area * bcone.calculate_measure();
+ if (total_cost == 0.0f) {
+ return FLT_MAX;
+ }
+
+ const float inv_total_cost = 1.0f / total_cost;
const float3 extent = centroid_bbox.size();
const float max_extent = max4(extent.x, extent.y, extent.z, 0.0f);
@@ -480,10 +498,10 @@ float LightTree::min_split_saoh(const BoundBox ¢roid_bbox,
}
/* Calculate the cost of splitting using the heuristic as described in the paper. */
- 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;
+ const float area_L = has_area ? bbox_L.area() : len(bbox_L.size());
+ const float area_R = has_area ? bbox_R.area() : len(bbox_R.size());
+ float left = (bbox_L.valid()) ? energy_L * area_L * bcone_L.calculate_measure() : 0.0f;
+ float right = (bbox_R.valid()) ? energy_R * area_R * bcone_R.calculate_measure() : 0.0f;
float regularization = max_extent * inv_extent;
bucket_costs[split] = regularization * (left + right) * inv_total_cost;
More information about the Bf-blender-cvs
mailing list