Skip to content

Commit

Permalink
Merge bvh
Browse files Browse the repository at this point in the history
  • Loading branch information
xelatihy committed Jan 29, 2024
1 parent 4e871d0 commit 12d9029
Show file tree
Hide file tree
Showing 4 changed files with 437 additions and 551 deletions.
336 changes: 335 additions & 1 deletion libs/yocto/yocto_bvh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ inline void parallel_for_batch(vec2i num, Func&& func) {
} // namespace yocto

// -----------------------------------------------------------------------------
// IMPLEMENTATION FOR BVH BUILD
// COMMON BVH FUCTIONS
// -----------------------------------------------------------------------------
namespace yocto {

Expand Down Expand Up @@ -341,6 +341,340 @@ static void refit_bvh(bvh_tree& bvh, const vector<bbox3f>& bboxes) {
}
}

// Intersect ray with a bvh.
template <typename Intersect>
static shape_intersection intersect_elements_bvh(const bvh_tree& bvh,
Intersect&& intersect_element, const ray3f& ray_, bool find_any) {
// check empty
if (bvh.nodes.empty()) return {};

// node stack
auto node_stack = array<int, 128>{};
auto node_cur = 0;
node_stack[node_cur++] = 0;

// shared variables
auto intersection = shape_intersection{};

// copy ray to modify it
auto ray = ray_;

// prepare ray for fast queries
auto ray_dinv = vec3f{1 / ray.d.x, 1 / ray.d.y, 1 / ray.d.z};
auto ray_dsign = vec3i{(ray_dinv.x < 0) ? 1 : 0, (ray_dinv.y < 0) ? 1 : 0,
(ray_dinv.z < 0) ? 1 : 0};

// walking stack
while (node_cur) {
// grab node
auto& node = bvh.nodes[node_stack[--node_cur]];

// intersect bbox
// if (!intersect_bbox(ray, ray_dinv, ray_dsign, node.bbox)) continue;
if (!intersect_bbox(ray, ray_dinv, node.bbox)) continue;

// intersect node, switching based on node type
// for each type, iterate over the the primitive list
if (node.internal) {
// for internal nodes, attempts to proceed along the
// split axis from smallest to largest nodes
if (ray_dsign[node.axis]) {
node_stack[node_cur++] = node.start + 0;
node_stack[node_cur++] = node.start + 1;
} else {
node_stack[node_cur++] = node.start + 1;
node_stack[node_cur++] = node.start + 0;
}
} else {
for (auto idx : range(node.num)) {
auto primitive = bvh.primitives[node.start + idx];
auto eintersection = intersect_element(primitive, ray);
if (!eintersection.hit) continue;
intersection = {
primitive, eintersection.uv, eintersection.distance, true};
ray.tmax = eintersection.distance;
}
}

// check for early exit
if (find_any && intersection.hit) return intersection;
}

return intersection;
}

// Intersect ray with a bvh.
template <typename Overlap>
static shape_intersection overlap_elements_bvh(const bvh_tree& bvh,
Overlap&& overlap_element, vec3f pos, float max_distance, bool find_any) {
// check if empty
if (bvh.nodes.empty()) return {};

// node stack
auto node_stack = array<int, 128>{};
auto node_cur = 0;
node_stack[node_cur++] = 0;

// hit
auto intersection = shape_intersection{};

// walking stack
while (node_cur) {
// grab node
auto& node = bvh.nodes[node_stack[--node_cur]];

// intersect bbox
if (!overlap_bbox(pos, max_distance, node.bbox)) continue;

// intersect node, switching based on node type
// for each type, iterate over the the primitive list
if (node.internal) {
// internal node
node_stack[node_cur++] = node.start + 0;
node_stack[node_cur++] = node.start + 1;
} else {
for (auto idx : range(node.num)) {
auto primitive = bvh.primitives[node.start + idx];
auto eintersection = overlap_element(primitive, pos, max_distance);
if (!eintersection.hit) continue;
intersection = {
primitive, eintersection.uv, eintersection.distance, true};
max_distance = eintersection.distance;
}
}

// check for early exit
if (find_any && intersection.hit) return intersection;
}

return intersection;
}

} // namespace yocto

// -----------------------------------------------------------------------------
// BVH FOR SHAPE ELEMENTS
// -----------------------------------------------------------------------------
namespace yocto {

// Build shape bvh
bvh_tree make_points_bvh(const vector<int>& points,
const vector<vec3f>& positions, const vector<float>& radius,
bool highquality) {
// build primitives
auto bboxes = vector<bbox3f>(points.size());
for (auto idx : range(bboxes.size())) {
auto& p = points[idx];
bboxes[idx] = point_bounds(positions[p], radius[p]);
}

// build nodes
return make_bvh(bboxes, highquality);
}
bvh_tree make_lines_bvh(const vector<vec2i>& lines,
const vector<vec3f>& positions, const vector<float>& radius,
bool highquality) {
// build primitives
auto bboxes = vector<bbox3f>(lines.size());
for (auto idx : range(bboxes.size())) {
auto& l = lines[idx];
bboxes[idx] = line_bounds(
positions[l.x], positions[l.y], radius[l.x], radius[l.y]);
}

// build nodes
return make_bvh(bboxes, highquality);
}
bvh_tree make_triangles_bvh(const vector<vec3i>& triangles,
const vector<vec3f>& positions, bool highquality) {
// build primitives
auto bboxes = vector<bbox3f>(triangles.size());
for (auto idx : range(bboxes.size())) {
auto& t = triangles[idx];
bboxes[idx] = triangle_bounds(
positions[t.x], positions[t.y], positions[t.z]);
}

// build nodes
return make_bvh(bboxes, highquality);
}
bvh_tree make_quads_bvh(const vector<vec4i>& quads,
const vector<vec3f>& positions, bool highquality) {
// build primitives
auto bboxes = vector<bbox3f>(quads.size());
for (auto idx : range(bboxes.size())) {
auto& q = quads[idx];
bboxes[idx] = quad_bounds(
positions[q.x], positions[q.y], positions[q.z], positions[q.w]);
}

// build nodes
return make_bvh(bboxes, highquality);
}

void refit_points_bvh(bvh_tree& bvh, const vector<int>& points,
const vector<vec3f>& positions, const vector<float>& radius) {
// build primitives
auto bboxes = vector<bbox3f>(points.size());
for (auto idx : range(bboxes.size())) {
auto& p = points[idx];
bboxes[idx] = point_bounds(positions[p], radius[p]);
}

// update nodes
refit_bvh(bvh, bboxes);
}
void refit_lines_bvh(bvh_tree& bvh, const vector<vec2i>& lines,
const vector<vec3f>& positions, const vector<float>& radius) {
// build primitives
auto bboxes = vector<bbox3f>(lines.size());
for (auto idx : range(bboxes.size())) {
auto& l = lines[idx];
bboxes[idx] = line_bounds(
positions[l.x], positions[l.y], radius[l.x], radius[l.y]);
}

// update nodes
refit_bvh(bvh, bboxes);
}
void refit_triangles_bvh(bvh_tree& bvh, const vector<vec3i>& triangles,
const vector<vec3f>& positions) {
// build primitives
auto bboxes = vector<bbox3f>(triangles.size());
for (auto idx : range(bboxes.size())) {
auto& t = triangles[idx];
bboxes[idx] = triangle_bounds(
positions[t.x], positions[t.y], positions[t.z]);
}

// update nodes
refit_bvh(bvh, bboxes);
}
void refit_quads_bvh(
bvh_tree& bvh, const vector<vec4i>& quads, const vector<vec3f>& positions) {
// build primitives
auto bboxes = vector<bbox3f>(quads.size());
for (auto idx : range(bboxes.size())) {
auto& q = quads[idx];
bboxes[idx] = quad_bounds(
positions[q.x], positions[q.y], positions[q.z], positions[q.w]);
}

// update nodes
refit_bvh(bvh, bboxes);
}

// Intersect ray with a bvh.
shape_intersection intersect_points_bvh(const bvh_tree& bvh,
const vector<int>& points, const vector<vec3f>& positions,
const vector<float>& radius, const ray3f& ray, bool find_any) {
return intersect_elements_bvh(
bvh,
[&points, &positions, &radius](int idx, const ray3f& ray) {
auto& p = points[idx];
return intersect_point(ray, positions[p], radius[p]);
},
ray, find_any);
}
shape_intersection intersect_lines_bvh(const bvh_tree& bvh,
const vector<vec2i>& lines, const vector<vec3f>& positions,
const vector<float>& radius, const ray3f& ray, bool find_any) {
return intersect_elements_bvh(
bvh,
[&lines, &positions, &radius](int idx, const ray3f& ray) {
auto& l = lines[idx];
return intersect_line(
ray, positions[l.x], positions[l.y], radius[l.x], radius[l.y]);
},
ray, find_any);
}
shape_intersection intersect_triangles_bvh(const bvh_tree& bvh,
const vector<vec3i>& triangles, const vector<vec3f>& positions,
const ray3f& ray, bool find_any) {
return intersect_elements_bvh(
bvh,
[&triangles, &positions](int idx, const ray3f& ray) {
auto& t = triangles[idx];
return intersect_triangle(
ray, positions[t.x], positions[t.y], positions[t.z]);
},
ray, find_any);
}
shape_intersection intersect_quads_bvh(const bvh_tree& bvh,
const vector<vec4i>& quads, const vector<vec3f>& positions,
const ray3f& ray, bool find_any) {
return intersect_elements_bvh(
bvh,
[&quads, &positions](int idx, const ray3f& ray) {
auto& t = quads[idx];
return intersect_quad(ray, positions[t.x], positions[t.y],
positions[t.z], positions[t.w]);
},
ray, find_any);
}

// Find a shape element that overlaps a point within a given distance
// max distance, returning either the closest or any overlap depending on
// `find_any`. Returns the point distance, the instance id, the shape element
// index and the element barycentric coordinates.
shape_intersection overlap_points_bvh(const bvh_tree& bvh,
const vector<int>& points, const vector<vec3f>& positions,
const vector<float>& radius, vec3f pos, float max_distance, bool find_any) {
return overlap_elements_bvh(
bvh,
[&points, &positions, &radius](int idx, vec3f pos, float max_distance) {
auto& p = points[idx];
return overlap_point(pos, max_distance, positions[p], radius[p]);
},
pos, max_distance, find_any);
}
shape_intersection overlap_lines_bvh(const bvh_tree& bvh,
const vector<vec2i>& lines, const vector<vec3f>& positions,
const vector<float>& radius, vec3f pos, float max_distance, bool find_any) {
return overlap_elements_bvh(
bvh,
[&lines, &positions, &radius](int idx, vec3f pos, float max_distance) {
auto& l = lines[idx];
return overlap_line(pos, max_distance, positions[l.x], positions[l.y],
radius[l.x], radius[l.y]);
},
pos, max_distance, find_any);
}
shape_intersection overlap_triangles_bvh(const bvh_tree& bvh,
const vector<vec3i>& triangles, const vector<vec3f>& positions,
const vector<float>& radius, vec3f pos, float max_distance, bool find_any) {
return overlap_elements_bvh(
bvh,
[&triangles, &positions, &radius](
int idx, vec3f pos, float max_distance) {
auto& t = triangles[idx];
return overlap_triangle(pos, max_distance, positions[t.x],
positions[t.y], positions[t.z], radius[t.x], radius[t.y],
radius[t.z]);
},
pos, max_distance, find_any);
}
shape_intersection overlap_quads_bvh(const bvh_tree& bvh,
const vector<vec4i>& quads, const vector<vec3f>& positions,
const vector<float>& radius, vec3f pos, float max_distance, bool find_any) {
return overlap_elements_bvh(
bvh,
[&quads, &positions, &radius](int idx, vec3f pos, float max_distance) {
auto& q = quads[idx];
return overlap_quad(pos, max_distance, positions[q.x], positions[q.y],
positions[q.z], positions[q.w], radius[q.x], radius[q.y],
radius[q.z], radius[q.w]);
},
pos, max_distance, find_any);
}

} // namespace yocto

// -----------------------------------------------------------------------------
// BVH FOR SHAPE AND SCENE
// -----------------------------------------------------------------------------
namespace yocto {

shape_bvh make_shape_bvh(const shape_data& shape, bool highquality) {
// bvh
auto sbvh = shape_bvh{};
Expand Down
Loading

0 comments on commit 12d9029

Please sign in to comment.