parent
6d9d95ddad
commit
93125b2e0b
Binary file not shown.
Binary file not shown.
|
|
@ -299,7 +299,7 @@ void setup_cornell_box() {
|
||||||
g_scene->add_mesh(tall_box);
|
g_scene->add_mesh(tall_box);
|
||||||
|
|
||||||
// Metal sphere (replacing the glass box, positioned on the right side)
|
// Metal sphere (replacing the glass box, positioned on the right side)
|
||||||
auto metal_sphere = create_sphere(0.5f, 16, 8, metal_id);
|
auto metal_sphere = create_sphere(0.5f, 16, 8, /*metal_id*/white_id);
|
||||||
metal_sphere->set_position(Vec3(0.55f, -1.5f, 0.35f));
|
metal_sphere->set_position(Vec3(0.55f, -1.5f, 0.35f));
|
||||||
metal_sphere->upload_to_gpu();
|
metal_sphere->upload_to_gpu();
|
||||||
g_scene->add_mesh(metal_sphere);
|
g_scene->add_mesh(metal_sphere);
|
||||||
|
|
|
||||||
|
|
@ -129,29 +129,57 @@ void BVH::build_recursive_(uint node_idx, uint first_prim, uint prim_count) {
|
||||||
const uint LEAF_SIZE = 4;
|
const uint LEAF_SIZE = 4;
|
||||||
|
|
||||||
if (prim_count <= LEAF_SIZE) {
|
if (prim_count <= LEAF_SIZE) {
|
||||||
// Create leaf node
|
|
||||||
node.left_first_ = first_prim;
|
node.left_first_ = first_prim;
|
||||||
node.count_ = prim_count;
|
node.count_ = prim_count;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find best split
|
// Calculate current depth
|
||||||
int axis;
|
uint current_depth = 0;
|
||||||
float split_pos;
|
uint idx = node_idx;
|
||||||
|
while (idx > 0) {
|
||||||
|
idx = (idx - 1) / 2;
|
||||||
|
current_depth++;
|
||||||
|
}
|
||||||
|
const uint MAX_DEPTH = 32;
|
||||||
|
|
||||||
|
// Force leaf if max depth reached
|
||||||
|
if (current_depth >= MAX_DEPTH) {
|
||||||
|
node.left_first_ = first_prim;
|
||||||
|
node.count_ = prim_count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find best split using SAH
|
||||||
|
int axis = 0;
|
||||||
|
float split_pos = 0.0f;
|
||||||
float split_cost = find_best_split_(first_prim, prim_count, axis, split_pos);
|
float split_cost = find_best_split_(first_prim, prim_count, axis, split_pos);
|
||||||
if (split_cost == std::numeric_limits<float>::max()) {
|
|
||||||
node.left_first_ = first_prim;
|
|
||||||
node.count_ = prim_count;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if split is beneficial
|
// SAH cost comparison (normalized)
|
||||||
float no_split_cost = prim_count * bounds.surface_area();
|
// C_split = C_trav + (N_left * SA_left + N_right * SA_right) / SA_parent
|
||||||
if (split_cost >= no_split_cost) {
|
// C_leaf = N * C_int
|
||||||
// Create leaf node
|
// With C_trav = 1, C_int = 1:
|
||||||
node.left_first_ = first_prim;
|
// Split if C_split < C_leaf
|
||||||
node.count_ = prim_count;
|
// (Constants are used in find_best_split_ for cost calculation)
|
||||||
return;
|
|
||||||
|
if (split_cost == std::numeric_limits<float>::max() || split_cost >= static_cast<float>(prim_count)) {
|
||||||
|
// SAH says no split is beneficial, but force split if too many prims
|
||||||
|
const uint MAX_PRIMS_PER_LEAF = 8;
|
||||||
|
if (prim_count <= MAX_PRIMS_PER_LEAF) {
|
||||||
|
node.left_first_ = first_prim;
|
||||||
|
node.count_ = prim_count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Force median split as fallback
|
||||||
|
AABB cb = calculate_centroid_bounds_(first_prim, prim_count);
|
||||||
|
for (int a = 0; a < 3; ++a) {
|
||||||
|
float extent = cb.max_[a] - cb.min_[a];
|
||||||
|
if (extent > EPSILON) {
|
||||||
|
axis = a;
|
||||||
|
split_pos = (cb.min_[a] + cb.max_[a]) * 0.5f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partition primitives
|
// Partition primitives
|
||||||
|
|
@ -192,6 +220,8 @@ float BVH::find_best_split_(uint first_prim, uint prim_count, int &axis, float &
|
||||||
axis = 0, split_pos = 0.0f;
|
axis = 0, split_pos = 0.0f;
|
||||||
|
|
||||||
AABB centroid_bounds = calculate_centroid_bounds_(first_prim, prim_count);
|
AABB centroid_bounds = calculate_centroid_bounds_(first_prim, prim_count);
|
||||||
|
AABB parent_bounds = calculate_bounds_(first_prim, prim_count);
|
||||||
|
float parent_sa = parent_bounds.surface_area();
|
||||||
|
|
||||||
// Try each axis
|
// Try each axis
|
||||||
for (int a = 0; a < 3; ++a) {
|
for (int a = 0; a < 3; ++a) {
|
||||||
|
|
@ -199,7 +229,7 @@ float BVH::find_best_split_(uint first_prim, uint prim_count, int &axis, float &
|
||||||
if (extent < EPSILON)
|
if (extent < EPSILON)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Try multiple split positions
|
// Try multiple split positions using 16 bins
|
||||||
const int NUM_BINS = 16;
|
const int NUM_BINS = 16;
|
||||||
for (int i = 1; i < NUM_BINS; ++i) {
|
for (int i = 1; i < NUM_BINS; ++i) {
|
||||||
float t = static_cast<float>(i) / NUM_BINS;
|
float t = static_cast<float>(i) / NUM_BINS;
|
||||||
|
|
@ -222,11 +252,14 @@ float BVH::find_best_split_(uint first_prim, uint prim_count, int &axis, float &
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate SAH cost
|
// Calculate normalized SAH cost
|
||||||
if (left_count == 0 || right_count == 0)
|
if (left_count == 0 || right_count == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float cost = left_count * left_bounds.surface_area() + right_count * right_bounds.surface_area();
|
float cost = 1.0f; // Traversal cost
|
||||||
|
if (parent_sa > 0.0f) {
|
||||||
|
cost += (left_count * left_bounds.surface_area() + right_count * right_bounds.surface_area()) / parent_sa;
|
||||||
|
}
|
||||||
|
|
||||||
if (cost < best_cost) {
|
if (cost < best_cost) {
|
||||||
best_cost = cost;
|
best_cost = cost;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue