Skip to content

Commit

Permalink
Cleanup Bvh
Browse files Browse the repository at this point in the history
  • Loading branch information
xelatihy committed Jan 30, 2024
1 parent caea8ac commit b05bfb9
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 159 deletions.
237 changes: 79 additions & 158 deletions libs/yocto/yocto_raycasting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,18 @@ static pair<int, int> split_middle(vector<int>& primitives,
const int bvh_max_prims = 4;

// Build BVH nodes
static bvh_tree make_bvh(const vector<bbox3f>& bboxes, bool highquality) {
template <typename BBox>
static bvh_tree make_elements_bvh(size_t num, bool highquality, BBox&& bbox) {
// bvh
auto bvh = bvh_tree{};

// prepare to build nodes
bvh.nodes.clear();
bvh.nodes.reserve(bboxes.size() * 2);
bvh.nodes.reserve(num * 2);

// prepare bboxes
auto bboxes = vector<bbox3f>(num);
for (auto idx : range((int)num)) bboxes[idx] = bbox(idx);

// prepare primitives
bvh.primitives.resize(bboxes.size());
Expand Down Expand Up @@ -297,7 +302,8 @@ static bvh_tree make_bvh(const vector<bbox3f>& bboxes, bool highquality) {
}

// Update bvh
static void refit_bvh(bvh_tree& bvh, const vector<bbox3f>& bboxes) {
template <typename BBox>
static void refit_elements_bvh(bvh_tree& bvh, BBox&& bbox) {
for (auto nodeid = (int)bvh.nodes.size() - 1; nodeid >= 0; nodeid--) {
auto& node = bvh.nodes[nodeid];
node.bbox = invalidb3f;
Expand All @@ -307,7 +313,7 @@ static void refit_bvh(bvh_tree& bvh, const vector<bbox3f>& bboxes) {
}
} else {
for (auto idx : range(node.num)) {
node.bbox = merge(node.bbox, bboxes[bvh.primitives[node.start + idx]]);
node.bbox = merge(node.bbox, bbox(bvh.primitives[node.start + idx]));
}
}
}
Expand Down Expand Up @@ -433,107 +439,73 @@ namespace yocto {
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);
return make_elements_bvh(points.size(), highquality, [&](int idx) {
auto& p = points[idx];
return point_bounds(positions[p], radius[p]);
});
}
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);
return make_elements_bvh(lines.size(), highquality, [&](int idx) {
auto& l = lines[idx];
return line_bounds(
positions[l.x], positions[l.y], radius[l.x], radius[l.y]);
});
}
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);
return make_elements_bvh(triangles.size(), highquality, [&](int idx) {
auto& t = triangles[idx];
return triangle_bounds(positions[t.x], positions[t.y], positions[t.z]);
});
}
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);
return make_elements_bvh(quads.size(), highquality, [&](int idx) {
auto& q = quads[idx];
return quad_bounds(
positions[q.x], positions[q.y], positions[q.z], positions[q.w]);
});
}

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);
refit_elements_bvh(bvh, [&](int idx) {
auto& p = points[idx];
return point_bounds(positions[p], radius[p]);
});
}
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);
refit_elements_bvh(bvh, [&](int idx) {
auto& l = lines[idx];
return line_bounds(
positions[l.x], positions[l.y], radius[l.x], radius[l.y]);
});
}
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);
refit_elements_bvh(bvh, [&](int idx) {
auto& t = triangles[idx];
return triangle_bounds(positions[t.x], positions[t.y], positions[t.z]);
});
}
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);
refit_elements_bvh(bvh, [&](int idx) {
auto& q = quads[idx];
return quad_bounds(
positions[q.x], positions[q.y], positions[q.z], positions[q.w]);
});
}

// Intersect ray with a bvh.
Expand All @@ -542,7 +514,7 @@ shape_intersection intersect_points_bvh(const bvh_tree& bvh,
const vector<float>& radius, const ray3f& ray, bool find_any) {
return intersect_elements_bvh(
bvh,
[&points, &positions, &radius](int idx, const ray3f& ray) {
[&](int idx, const ray3f& ray) {
auto& p = points[idx];
return intersect_point(ray, positions[p], radius[p]);
},
Expand All @@ -553,7 +525,7 @@ shape_intersection intersect_lines_bvh(const bvh_tree& bvh,
const vector<float>& radius, const ray3f& ray, bool find_any) {
return intersect_elements_bvh(
bvh,
[&lines, &positions, &radius](int idx, const ray3f& ray) {
[&](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]);
Expand All @@ -565,7 +537,7 @@ shape_intersection intersect_triangles_bvh(const bvh_tree& bvh,
const ray3f& ray, bool find_any) {
return intersect_elements_bvh(
bvh,
[&triangles, &positions](int idx, const ray3f& ray) {
[&](int idx, const ray3f& ray) {
auto& t = triangles[idx];
return intersect_triangle(
ray, positions[t.x], positions[t.y], positions[t.z]);
Expand All @@ -577,7 +549,7 @@ shape_intersection intersect_quads_bvh(const bvh_tree& bvh,
const ray3f& ray, bool find_any) {
return intersect_elements_bvh(
bvh,
[&quads, &positions](int idx, const ray3f& ray) {
[&](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]);
Expand Down Expand Up @@ -652,112 +624,65 @@ shape_bvh make_shape_bvh(const shape_data& shape, bool highquality) {
auto sbvh = shape_bvh{};

// build primitives
auto bboxes = vector<bbox3f>{};
if (!shape.points.empty()) {
bboxes = vector<bbox3f>(shape.points.size());
for (auto idx : range(shape.points.size())) {
auto& point = shape.points[idx];
bboxes[idx] = point_bounds(shape.positions[point], shape.radius[point]);
}
sbvh.bvh = make_points_bvh(
shape.points, shape.positions, shape.radius, highquality);
} else if (!shape.lines.empty()) {
bboxes = vector<bbox3f>(shape.lines.size());
for (auto idx : range(shape.lines.size())) {
auto& line = shape.lines[idx];
bboxes[idx] = line_bounds(shape.positions[line.x],
shape.positions[line.y], shape.radius[line.x], shape.radius[line.y]);
}
sbvh.bvh = make_lines_bvh(
shape.lines, shape.positions, shape.radius, highquality);
} else if (!shape.triangles.empty()) {
bboxes = vector<bbox3f>(shape.triangles.size());
for (auto idx : range(shape.triangles.size())) {
auto& triangle = shape.triangles[idx];
bboxes[idx] = triangle_bounds(shape.positions[triangle.x],
shape.positions[triangle.y], shape.positions[triangle.z]);
}
sbvh.bvh = make_triangles_bvh(
shape.triangles, shape.positions, highquality);
} else if (!shape.quads.empty()) {
bboxes = vector<bbox3f>(shape.quads.size());
for (auto idx : range(shape.quads.size())) {
auto& quad = shape.quads[idx];
bboxes[idx] = quad_bounds(shape.positions[quad.x],
shape.positions[quad.y], shape.positions[quad.z],
shape.positions[quad.w]);
}
sbvh.bvh = make_quads_bvh(shape.quads, shape.positions, highquality);
}

// build nodes
sbvh.bvh = make_bvh(bboxes, highquality);

// done
return sbvh;
}

scene_bvh make_scene_bvh(
const scene_data& scene, bool highquality, bool noparallel) {
// bvh
auto sbvh = scene_bvh{};
auto bvh = scene_bvh{};

// build shape bvh
sbvh.shapes.resize(scene.shapes.size());
bvh.shapes.resize(scene.shapes.size());
if (noparallel) {
for (auto idx : range(scene.shapes.size())) {
sbvh.shapes[idx] = make_shape_bvh(scene.shapes[idx], highquality);
bvh.shapes[idx] = make_shape_bvh(scene.shapes[idx], highquality);
}
} else {
parallel_for(scene.shapes.size(), [&](size_t idx) {
sbvh.shapes[idx] = make_shape_bvh(scene.shapes[idx], highquality);
bvh.shapes[idx] = make_shape_bvh(scene.shapes[idx], highquality);
});
}

// instance bboxes
auto bboxes = vector<bbox3f>(scene.instances.size());
for (auto idx : range(bboxes.size())) {
auto& instance = scene.instances[idx];
bboxes[idx] = sbvh.shapes[instance.shape].bvh.nodes.empty()
? invalidb3f
: transform_bbox(instance.frame,
sbvh.shapes[instance.shape].bvh.nodes[0].bbox);
}

// build nodes
sbvh.bvh = make_bvh(bboxes, highquality);
bvh.bvh = make_elements_bvh(
scene.instances.size(), highquality, [&](int idx) {
auto& instance = scene.instances[idx];
auto& sbvh = bvh.shapes[instance.shape].bvh;
return sbvh.nodes.empty()
? invalidb3f
: transform_bbox(instance.frame, sbvh.nodes[0].bbox);
});

// done
return sbvh;
return bvh;
}

void update_shape_bvh(shape_bvh& sbvh, const shape_data& shape) {
// build primitives
auto bboxes = vector<bbox3f>{};
// update primitives
if (!shape.points.empty()) {
bboxes = vector<bbox3f>(shape.points.size());
for (auto idx : range(bboxes.size())) {
auto& p = shape.points[idx];
bboxes[idx] = point_bounds(shape.positions[p], shape.radius[p]);
}
refit_points_bvh(sbvh.bvh, shape.points, shape.positions, shape.radius);
} else if (!shape.lines.empty()) {
bboxes = vector<bbox3f>(shape.lines.size());
for (auto idx : range(bboxes.size())) {
auto& l = shape.lines[idx];
bboxes[idx] = line_bounds(shape.positions[l.x], shape.positions[l.y],
shape.radius[l.x], shape.radius[l.y]);
}
refit_lines_bvh(sbvh.bvh, shape.lines, shape.positions, shape.radius);
} else if (!shape.triangles.empty()) {
bboxes = vector<bbox3f>(shape.triangles.size());
for (auto idx : range(bboxes.size())) {
auto& t = shape.triangles[idx];
bboxes[idx] = triangle_bounds(
shape.positions[t.x], shape.positions[t.y], shape.positions[t.z]);
}
refit_triangles_bvh(sbvh.bvh, shape.triangles, shape.positions);
} else if (!shape.quads.empty()) {
bboxes = vector<bbox3f>(shape.quads.size());
for (auto idx : range(bboxes.size())) {
auto& q = shape.quads[idx];
bboxes[idx] = quad_bounds(shape.positions[q.x], shape.positions[q.y],
shape.positions[q.z], shape.positions[q.w]);
}
refit_quads_bvh(sbvh.bvh, shape.quads, shape.positions);
}

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

void update_scene_bvh(scene_bvh& sbvh, const scene_data& scene,
Expand All @@ -767,16 +692,12 @@ void update_scene_bvh(scene_bvh& sbvh, const scene_data& scene,
update_shape_bvh(sbvh.shapes[shape], scene.shapes[shape]);
}

// handle instances
auto bboxes = vector<bbox3f>(scene.instances.size());
for (auto idx : range(bboxes.size())) {
// update nodes
refit_elements_bvh(sbvh.bvh, [&](int idx) {
auto& instance = scene.instances[idx];
bboxes[idx] = transform_bbox(
return transform_bbox(
instance.frame, sbvh.shapes[instance.shape].bvh.nodes[0].bbox);
}

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

// Compute scene bounding box
Expand Down
2 changes: 1 addition & 1 deletion libs/yocto/yocto_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ static float sample_scattering_pdf(
return sample_phasefunction_pdf(material.scanisotropy, outgoing, incoming);
}

// Generates a ray from a camera for yimg::image plane coordinate uv and
// Generates a ray from a camera for image plane coordinate uv and
// the lens coordinates luv.
static ray3f eval_camera(
const camera_data& camera, vec2f image_uv, vec2f lens_uv) {
Expand Down

0 comments on commit b05bfb9

Please sign in to comment.