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

Instances #44

Closed
tigrazone opened this issue Feb 17, 2022 · 8 comments
Closed

Instances #44

tigrazone opened this issue Feb 17, 2022 · 8 comments
Labels
question Further information is requested

Comments

@tigrazone
Copy link

Hello!
How to use library with instances?
I need BLAS and TLAS.
Can you create example for it?
Thank you

@madmann91 madmann91 added the question Further information is requested label Feb 23, 2022
@madmann91
Copy link
Owner

Hello! You may take a look at the example on custom primitives. An instance is just a primitive like any other, which itself contains a BVH and a matrix. Before intersecting the instance, you transform the ray by the inverse of the matrix. That's basically it.

@Silverlan
Copy link

Hello! You may take a look at the example on custom primitives. An instance is just a primitive like any other, which itself contains a BVH and a matrix. Before intersecting the instance, you transform the ray by the inverse of the matrix. That's basically it.

Are custom primitives still supported? I noticed that the example for them is no longer available, and I need a BVH with OBBs as primitives.

@madmann91
Copy link
Owner

Yes, they are still supported. The interface is a bit lower-level in the new version, so you only need an axis-aligned bounding box and a center point for each primitive you need to insert in the BVH. For you, this means something like:

std::vector<BBox> bboxes(obbs.size());
std::vector<Vec3> centers(obbs.size());
executor.for_each(0, tris.size(), [&] (size_t begin, size_t end) {
    for (size_t i = begin; i < end; ++i) {
        bboxes[i]  = get_box(obbs[i]);
        centers[i] = obbs[i].pos;
    }
});

typename bvh::v2::DefaultBuilder<Node>::Config config;
config.quality = bvh::v2::DefaultBuilder<Node>::Quality::High;
auto bvh = bvh::v2::DefaultBuilder<Node>::build(thread_pool, bboxes, centers, config);

You can get the AABB of an OBB this way (you do not need to transform the 8 points of a 3D OBB):

// Assuming the corners are obtained by multiplying the matrix with (+-1, +-1, +-1)
struct OBB {
    Mat3x3 mat;
    Vec3 pos;
};

inline Box3 get_bbox(const OBB& obb) {
    auto abs_mat = abs(obb.mat);
    auto half_extents = abs_mat * Vec3 { 1, 1, 1 };
    return Box3 { obb.pos - half_extents, obb.pos + half_extents };
};

@Silverlan
Copy link

Yes, they are still supported. The interface is a bit lower-level in the new version, so you only need an axis-aligned bounding box and a center point for each primitive you need to insert in the BVH. For you, this means something like:

std::vector<BBox> bboxes(obbs.size());
std::vector<Vec3> centers(obbs.size());
executor.for_each(0, tris.size(), [&] (size_t begin, size_t end) {
    for (size_t i = begin; i < end; ++i) {
        bboxes[i]  = get_box(obbs[i]);
        centers[i] = obbs[i].pos;
    }
});

typename bvh::v2::DefaultBuilder<Node>::Config config;
config.quality = bvh::v2::DefaultBuilder<Node>::Quality::High;
auto bvh = bvh::v2::DefaultBuilder<Node>::build(thread_pool, bboxes, centers, config);

You can get the AABB of an OBB this way (you do not need to transform the 8 points of a 3D OBB):

// Assuming the corners are obtained by multiplying the matrix with (+-1, +-1, +-1)
struct OBB {
    Mat3x3 mat;
    Vec3 pos;
};

inline Box3 get_bbox(const OBB& obb) {
    auto abs_mat = abs(obb.mat);
    auto half_extents = abs_mat * Vec3 { 1, 1, 1 };
    return Box3 { obb.pos - half_extents, obb.pos + half_extents };
};

Thanks, that works! But what about updates/refitting? In version 1 I could use the HierarchyRefitter, but I see no equivalent in version 2. I create the bvh like you describe:

bvh = ::bvh::v2::DefaultBuilder<pragma::bvh::Node>::build(GetThreadPool(), bboxes, centers, config);

After creation I need to update the bboxes/centers every frame, but I see no way to access those after the bvh has been built. Can the ReinsertionOptimizer be used for refitting somehow?

::bvh::v2::ReinsertionOptimizer<Node>::optimize(GetThreadPool(), bvh);

@madmann91
Copy link
Owner

madmann91 commented Feb 12, 2024

You can update the bounding boxes of every node in a for loop like so:

// It's important to process the nodes in reverse order, as this makes
// sure that children are processed before their parents.
for (auto& node : std::ranges::reverse_view { bvh.nodes }) {
  if (node.is_leaf()) {
    // refit node according to contents
    ...
  } else {
    auto& left  = bvh.nodes[node.index.first_id];
    auto& right = bvh.nodes[node.index.first_id + 1];
    node.set_bbox(left.get_bbox().extend(right.get_bbox()));
  }
}

I should probably add a method for this. Anyway, this method is very fast but should not be run in parallel as it expects the children to have been processed before the parents. The method used in the previous version of the repository works in parallel but is only faster when the BVH is extremely large.

@tigrazone
Copy link
Author

I need example for use in vulkan, for example.
Bvh can be create on CPU but usage on GPU

@madmann91
Copy link
Owner

madmann91 commented Feb 19, 2024

Yes, they are still supported. The interface is a bit lower-level in the new version, so you only need an axis-aligned bounding box and a center point for each primitive you need to insert in the BVH. For you, this means something like:

std::vector<BBox> bboxes(obbs.size());
std::vector<Vec3> centers(obbs.size());
executor.for_each(0, tris.size(), [&] (size_t begin, size_t end) {
    for (size_t i = begin; i < end; ++i) {
        bboxes[i]  = get_box(obbs[i]);
        centers[i] = obbs[i].pos;
    }
});

typename bvh::v2::DefaultBuilder<Node>::Config config;
config.quality = bvh::v2::DefaultBuilder<Node>::Quality::High;
auto bvh = bvh::v2::DefaultBuilder<Node>::build(thread_pool, bboxes, centers, config);

You can get the AABB of an OBB this way (you do not need to transform the 8 points of a 3D OBB):

// Assuming the corners are obtained by multiplying the matrix with (+-1, +-1, +-1)
struct OBB {
    Mat3x3 mat;
    Vec3 pos;
};

inline Box3 get_bbox(const OBB& obb) {
    auto abs_mat = abs(obb.mat);
    auto half_extents = abs_mat * Vec3 { 1, 1, 1 };
    return Box3 { obb.pos - half_extents, obb.pos + half_extents };
};

Thanks, that works! But what about updates/refitting? In version 1 I could use the HierarchyRefitter, but I see no equivalent in version 2. I create the bvh like you describe:

bvh = ::bvh::v2::DefaultBuilder<pragma::bvh::Node>::build(GetThreadPool(), bboxes, centers, config);

After creation I need to update the bboxes/centers every frame, but I see no way to access those after the bvh has been built. Can the ReinsertionOptimizer be used for refitting somehow?

::bvh::v2::ReinsertionOptimizer<Node>::optimize(GetThreadPool(), bvh);

There is now a refitting method which allows you to refit the BVH serially (since #74 has been merged). I might add a parallel version later.

@madmann91
Copy link
Owner

I need example for use in vulkan, for example. Bvh can be create on CPU but usage on GPU

Just look at the traversal code in bvh.h. You can also look at https://madmann91.github.io/2021/01/06/bvhs-part-2.html for an introduction to BVH traversal. This article contains implementation code that you can just port to your target language (GLSL/HLSL).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants