Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved instance bounding box computation #117

Merged
merged 1 commit into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/lib/accelerators/bvh.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,44 @@ struct boundingBox get_root_bbox(const struct bvh *bvh) {
return load_bbox_from_node(&bvh->nodes[0]);
}

struct boundingBox get_transformed_root_bbox(const struct bvh *bvh, const struct matrix4x4 *mat) {
// This algorithm recursively traverses the BVH in order to get a better approximation of the
// bounding box of the transformed BVH. An area threshold, expressed as a fraction of the area
// of the root node, is used to stop recursion early: For nodes that have a smaller area, the
// bounding box of the node is used as a proxy for the bounding box of the elements contained
// in the subtree. Thus, the smaller the threshold, the more precise the algorithm is, at the
// cost of more iterations.
const float area_threshold = 0.1f * bboxHalfArea((struct boundingBox[]) { get_root_bbox(bvh) });

index_t stack[MAX_BVH_DEPTH + 1];
index_t top = 0;
size_t stack_size = 0;
struct boundingBox bbox = emptyBBox;

while (true) {
struct bvh_node* node = &bvh->nodes[top];
struct boundingBox node_bbox = load_bbox_from_node(node);

// Stop recursing at a fixed depth, when we hit a leaf, or when the surface area of the bounding
// box is lower than the given threshold.
if (stack_size >= MAX_BVH_DEPTH + 1 ||
node->index.prim_count > 0 ||
bboxHalfArea(&node_bbox) < area_threshold)
{
tform_bbox(&node_bbox, *mat);
extendBBox(&bbox, &node_bbox);
if (stack_size <= 0)
break;
top = stack[--stack_size];
} else {
stack[stack_size++] = node->index.first_child_or_prim + 0;
top = node->index.first_child_or_prim + 1;
}
}

return bbox;
}

struct bvh *build_mesh_bvh(const struct mesh *mesh) {
return build_bvh_generic(mesh, get_poly_bbox_and_center, mesh->polygons.count);
}
Expand Down
4 changes: 4 additions & 0 deletions src/lib/accelerators/bvh.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ struct bvh;
/// Returns the bounding box of the root of the given BVH
struct boundingBox get_root_bbox(const struct bvh *bvh);

/// Returns the transformed bounding box of the BVH, using a better approximation than transforming
/// the root bounding box.
struct boundingBox get_transformed_root_bbox(const struct bvh *bvh, const struct matrix4x4 *);

/// Builds a BVH for a given mesh
/// @param mesh Mesh containing polygons to process
/// @param count Amount of polygons given
Expand Down
3 changes: 1 addition & 2 deletions src/lib/renderer/instance.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,7 @@ static void getMeshBBoxAndCenter(const struct instance *instance, struct boundin
mesh->rayOffset = 0.0f;
return;
}
*bbox = get_root_bbox(mesh->bvh);
tform_bbox(bbox, instance->composite.A);
*bbox = get_transformed_root_bbox(mesh->bvh, &instance->composite.A);
*center = bboxCenter(bbox);
mesh->rayOffset = rayOffset(*bbox);
}
Expand Down
Loading