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

optimizations and other improvements #80

Closed
wants to merge 38 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
38a2bd2
conversion to 64bit, implemented add/remove of a node, add sphere, ca…
dbenson24 Jun 15, 2021
a4691fd
fix lints
dbenson24 Jun 15, 2021
196560c
parallelize bvh build using rayon
dbenson24 Jul 11, 2021
07c4c05
testing rayon parallelization further
dbenson24 Jul 11, 2021
3deb2e3
bench test for flamegraph
dbenson24 Jul 11, 2021
e5cc3ec
fixing bugs in add/remove, change optimize to just add then remove th…
dbenson24 Jul 14, 2021
3b002e3
more qbvh testing
dbenson24 Jul 15, 2021
192eed9
reduced allocations in bvh build
dbenson24 Jul 18, 2021
1a152b4
completely remove allocations, bit of incorrect logic tho
dbenson24 Jul 18, 2021
12e6ead
Revert "completely remove allocations, bit of incorrect logic tho"
dbenson24 Jul 18, 2021
da98c79
refactor to prevent stack overflows
dbenson24 Jul 18, 2021
5e15776
rewrite to use interoptopus for the ffi bindings
dbenson24 Sep 21, 2021
8bd25ed
use smallvec for traversal to avoid panics, handle 0 sized bvhs, fix …
dbenson24 Dec 2, 2021
d2dc3bf
start convex generation
dbenson24 Dec 19, 2021
169dc30
update interoptopus and prep for f32/f64 features
dbenson24 Jan 6, 2022
c0d0d99
refactoring of f64 into real type, move ffi bindings to subcrate
dbenson24 Jan 7, 2022
71a080f
merge with upstream, fix optimize bug
dbenson24 Jan 8, 2022
d72ff4e
fix docs
dbenson24 Jan 8, 2022
2d23f39
add 100p sponza intersection bench
dbenson24 Jan 9, 2022
fbc607c
refactor into 32 and 64bit sub crates, optimize build using thread_lo…
dbenson24 Jan 14, 2022
c52c1ca
running cargo-fix
dbenson24 Jan 14, 2022
f8479a6
remove unneeded clone on optimize
dbenson24 Jan 14, 2022
b2e5d86
Merge branch 'master' of https://github.com/svenstaro/bvh
dbenson24 Jan 14, 2022
468190e
finish merging with upstream, add missing documentation
dbenson24 Jan 14, 2022
902b0c6
rename packages to prepare for upstreaming
dbenson24 Jan 14, 2022
fe22c91
changes to support ray tracing
dbenson24 Jan 15, 2022
93cd4e6
adjust trait lifetimes, add sphere and ray normals, fix building empt…
dbenson24 Jan 16, 2022
b137f65
remove dyn dispatch from iterator, fix sphere compilation error
dbenson24 Jan 19, 2022
9e40523
add best_first traversal to bvh, run cargo fmt
dbenson24 Jan 19, 2022
f80bf0a
put ray normal calc back in
dbenson24 Jan 20, 2022
e8fe6de
fix clippy errors, delete svg file
dbenson24 Feb 12, 2022
fd0b05e
get rid of transmute using a safer way
dbenson24 Feb 12, 2022
88a9155
run cargo fmt
dbenson24 Feb 12, 2022
c55c37d
fix all clippy warnings
dbenson24 Feb 12, 2022
016ac8d
move triangle impl, fix test failure
dbenson24 Feb 12, 2022
0b822d4
fix subcrate profiles, small tweaks
dbenson24 Feb 14, 2022
64263c9
fix all clippy errors in the benchmarks
dbenson24 Feb 15, 2022
904b86e
move ffi to a standalone repo + crate
dbenson24 Mar 16, 2022
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
37 changes: 4 additions & 33 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,41 +1,12 @@
[package]
name = "bvh"
description = "A fast BVH using SAH"
version = "0.6.0"
edition = "2018"
authors = [
"Sven-Hendrik Haase <[email protected]>",
"Alexander Dmitriev <[email protected]>"
]
readme = "README.md"
repository = "https://github.com/svenstaro/bvh"
documentation = "https://docs.rs/crate/bvh"
keywords = ["bvh", "bounding", "volume", "sah", "aabb"]
license = "MIT"

[dependencies]
approx = "0.5"
rand = "0.8"
log = "0.4"
num = "0.4"
glam = "0.20"
serde = { optional = true, version = "1", features = ["derive"] }

[dev-dependencies]
proptest = "1.0"
obj-rs = "0.7"
float_eq = "0.7"
criterion = "0.3"

[features]
bench = []
# Unfortunately can't use "serde" as the feature name until https://github.com/rust-lang/cargo/issues/5565 lands
serde_impls = ["serde", "glam/serde"]
[workspace]
members = ["bvh", "bvh-f64"]

[profile.release]
lto = true
codegen-units = 1
debug = true

[profile.bench]
lto = true
codegen-units = 1
debug = true
49 changes: 49 additions & 0 deletions bvh-f64/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[package]
name = "bvh-f64"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need a specialized crate for this? Can't we use traits for this to have Rust do the specialization?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I tried a few approaches to this. It might be a possibility with nalgebra backing things to have the float be a generic on everything, but with glam there's no trait to abstract dvec3 from vec3 so we would have to wrap that ourselves. This trick using separate crates in the workspace is something I got from the author of nalgebra and how he builds rapier (2d 3d 32 and 64bit). When the workspace is all setup with this cargo test runs the test for all the versions and you'll get compiler errors from rust analyzer for both at the same time

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would very much like to see this move to nalgebra, it would make the usage much cleaner via Bvh<T>. This would definitely be possible with the nalgebra vector types and number bounds.

Heck, because of the AABB's, assuming there are no dot products/cross products (which I don't think there are - haven't checked), it should work with integer types as well, and maybe even unsigned types (but there would have to be better bounds checking).

I could try and help get this working with nalgebra as well.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that would be pretty cool.

Copy link
Collaborator

@marstaik marstaik Apr 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how to approach this for now though, should I wait for these changes to get merged in? There are a lot of stacked up changes in this MR, so it might be easier to do after all the merge.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm it might be easier for me to port it now, and have this PR rebase on it. Otherwise we would be splitting code and then remerging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has nalgebra fixed the issues that made this crate switch from nalgebra to glam previously?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Elabajaba do you happen to know what those issues would be? I could look into it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iirc the main issues with nalgebra used to be compile times, slower runtime performance for non-simd types, and the confusing docs. I haven't really used nalgebra for a few years at this point, so I'm not sure how it compares these days.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that most of those issues have been addressed. It does still have a slower compilation time than glam

description = "A fast dynamic BVH using SAH"
version = "0.6.0"
edition = "2018"
authors = [
"Sven-Hendrik Haase <[email protected]>",
"Alexander Dmitriev <[email protected]>"
]
readme = "README.md"
repository = "https://github.com/svenstaro/bvh"
documentation = "https://docs.rs/crate/bvh"
keywords = ["bvh", "bounding", "volume", "sah", "aabb"]
license = "MIT"


[lib]
name = "bvh_f64"
path = "../src/lib.rs"
required-features = ["f64"]
doctest = false

[dependencies]
approx = "0.5"
rand = "0.8"
log = "0.4"
num = "0.4"
glam = "0.20"
rayon = "1.5.1"
smallvec = "1.6.1"
serde = { optional = true, version = "1", features = ["derive"] }


[dev-dependencies]
proptest = "1.0"
obj-rs = "0.7"
float_eq = "0.7"
criterion = "0.3"
itertools = "0.10.1"
serde = { version = "1", features = ["derive"] }
glam = { version = "0.20", features = ["serde"] }
serde_json = "1"

[features]
default = ["f64"]
bench = []
f64 = []
# Unfortunately can't use "serde" as the feature name until https://github.com/rust-lang/cargo/issues/5565 lands
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was stabilized in Rust 1.60.

serde_impls = ["serde", "glam/serde"]
47 changes: 47 additions & 0 deletions bvh/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[package]
name = "bvh"
description = "A fast dynamic BVH using SAH"
version = "0.6.0"
edition = "2018"
authors = [
"Sven-Hendrik Haase <[email protected]>",
"Alexander Dmitriev <[email protected]>"
]
readme = "README.md"
repository = "https://github.com/svenstaro/bvh"
documentation = "https://docs.rs/crate/bvh"
keywords = ["bvh", "bounding", "volume", "sah", "aabb"]
license = "MIT"


[lib]
name = "bvh"
path = "../src/lib.rs"
required-features = []

[dependencies]
approx = "0.5"
rand = "0.8"
log = "0.4"
num = "0.4"
glam = "0.20"
rayon = "1.5.1"
smallvec = "1.6.1"
serde = { optional = true, version = "1", features = ["derive"] }


[dev-dependencies]
proptest = "1.0"
obj-rs = "0.7"
float_eq = "0.7"
criterion = "0.3"
itertools = "0.10.1"
serde = { version = "1", features = ["derive"] }
glam = { version = "0.20", features = ["serde"] }
serde_json = "1"

[features]
default = []
bench = []
# Unfortunately can't use "serde" as the feature name until https://github.com/rust-lang/cargo/issues/5565 lands
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was stabilized in Rust 1.60.

serde_impls = ["serde", "glam/serde"]
18 changes: 10 additions & 8 deletions examples/simple.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use bvh::aabb::{Bounded, AABB};
use bvh::bounding_hierarchy::BHShape;
use bvh::bvh::BVH;
use bvh::ray::Ray;
use bvh::{Point3, Vector3};
use bvh::{
aabb::{Bounded, AABB},
bounding_hierarchy::BHShape,
bvh::BVH,
ray::Ray,
Point3, Real, Vector3,
};

#[derive(Debug)]
struct Sphere {
position: Point3,
radius: f32,
radius: Real,
node_index: usize,
}

Expand All @@ -33,8 +35,8 @@ impl BHShape for Sphere {
pub fn main() {
let mut spheres = Vec::new();
for i in 0..1000000u32 {
let position = Point3::new(i as f32, i as f32, i as f32);
let radius = (i % 10) as f32 + 1.0;
let position = Point3::new(i as Real, i as Real, i as Real);
let radius = (i % 10) as Real + 1.0;
spheres.push(Sphere {
position,
radius,
Expand Down
36 changes: 18 additions & 18 deletions src/axis.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Axis enum for indexing three-dimensional structures.

#![allow(unused)]
use crate::{Point3, Vector3};
use crate::{Point3, Real, Vector3};
use std::fmt::{Display, Formatter, Result};
use std::ops::{Index, IndexMut};

Expand All @@ -23,7 +23,6 @@ struct MyType<T>(T);
/// [`Point3`] and [`Vector3`] are also indexable using `Axis`.
///
/// ```
/// extern crate bvh;
///
/// use bvh::axis::Axis;
/// use bvh::Point3;
Expand Down Expand Up @@ -63,19 +62,19 @@ impl Display for Axis {
}

/// Make slices indexable by `Axis`.
impl Index<Axis> for [f32] {
type Output = f32;
impl Index<Axis> for [Real] {
type Output = Real;

fn index(&self, axis: Axis) -> &f32 {
fn index(&self, axis: Axis) -> &Real {
&self[axis as usize]
}
}

/// Make `Point3` indexable by `Axis`.
impl Index<Axis> for Point3 {
type Output = f32;
type Output = Real;

fn index(&self, axis: Axis) -> &f32 {
fn index(&self, axis: Axis) -> &Real {
match axis {
Axis::X => &self.x,
Axis::Y => &self.y,
Expand All @@ -86,9 +85,9 @@ impl Index<Axis> for Point3 {

/// Make `Vector3` indexable by `Axis`.
impl Index<Axis> for MyType<Vector3> {
type Output = f32;
type Output = Real;

fn index(&self, axis: Axis) -> &f32 {
fn index(&self, axis: Axis) -> &Real {
match axis {
Axis::X => &self.0.x,
Axis::Y => &self.0.y,
Expand All @@ -98,15 +97,15 @@ impl Index<Axis> for MyType<Vector3> {
}

/// Make slices mutably accessible by `Axis`.
impl IndexMut<Axis> for [f32] {
fn index_mut(&mut self, axis: Axis) -> &mut f32 {
impl IndexMut<Axis> for [Real] {
fn index_mut(&mut self, axis: Axis) -> &mut Real {
&mut self[axis as usize]
}
}

/// Make `Point3` mutably accessible by `Axis`.
impl IndexMut<Axis> for Point3 {
fn index_mut(&mut self, axis: Axis) -> &mut f32 {
fn index_mut(&mut self, axis: Axis) -> &mut Real {
match axis {
Axis::X => &mut self.x,
Axis::Y => &mut self.y,
Expand All @@ -117,7 +116,7 @@ impl IndexMut<Axis> for Point3 {

/// Make `Vector3` mutably accessible by `Axis`.
impl IndexMut<Axis> for MyType<Vector3> {
fn index_mut(&mut self, axis: Axis) -> &mut f32 {
fn index_mut(&mut self, axis: Axis) -> &mut Real {
match axis {
Axis::X => &mut self.0.x,
Axis::Y => &mut self.0.y,
Expand All @@ -128,28 +127,29 @@ impl IndexMut<Axis> for MyType<Vector3> {

#[cfg(test)]
mod test {
use crate::axis::Axis;
use crate::{axis::Axis, Real};
use proptest::prelude::*;

#[cfg(not(miri))]
proptest! {
// Test whether accessing arrays by index is the same as accessing them by `Axis`.
#[test]
fn test_index_by_axis(tpl: (f32, f32, f32)) {
fn test_index_by_axis(tpl: (Real, Real, Real)) {
let a = [tpl.0, tpl.1, tpl.2];

assert!((a[0] - a[Axis::X]).abs() < f32::EPSILON && (a[1] - a[Axis::Y]).abs() < f32::EPSILON && (a[2] - a[Axis::Z]).abs() < f32::EPSILON);
assert!((a[0] - a[Axis::X]).abs() < Real::EPSILON && (a[1] - a[Axis::Y]).abs() < Real::EPSILON && (a[2] - a[Axis::Z]).abs() < Real::EPSILON);
}

// Test whether arrays can be mutably set, by indexing via `Axis`.
#[test]
fn test_set_by_axis(tpl: (f32, f32, f32)) {
fn test_set_by_axis(tpl: (Real, Real, Real)) {
let mut a = [0.0, 0.0, 0.0];

a[Axis::X] = tpl.0;
a[Axis::Y] = tpl.1;
a[Axis::Z] = tpl.2;

assert!((a[0] - tpl.0).abs() < f32::EPSILON && (a[1] - tpl.1).abs() < f32::EPSILON && (a[2] - tpl.2).abs() < f32::EPSILON);
assert!((a[0] - tpl.0).abs() < Real::EPSILON && (a[1] - tpl.1).abs() < Real::EPSILON && (a[2] - tpl.2).abs() < Real::EPSILON);
}
}
}
28 changes: 23 additions & 5 deletions src/bounding_hierarchy.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
//! This module defines the `BoundingHierarchy` trait.

use crate::aabb::Bounded;
use crate::ray::Ray;
use crate::aabb::AABB;

/// Describes a shape as referenced by a [`BoundingHierarchy`] leaf node.
/// Knows the index of the node in the [`BoundingHierarchy`] it is in.
///
/// [`BoundingHierarchy`]: struct.BoundingHierarchy.html
///
#[allow(clippy::upper_case_acronyms)]
pub trait BHShape: Bounded {
pub trait BHShape: Bounded + Sync + Send {
/// Sets the index of the referenced [`BoundingHierarchy`] node.
///
/// [`BoundingHierarchy`]: struct.BoundingHierarchy.html
Expand All @@ -34,6 +34,7 @@ pub trait BoundingHierarchy {
/// use bvh::aabb::{AABB, Bounded};
/// use bvh::bounding_hierarchy::BoundingHierarchy;
/// use bvh::{Point3, Vector3};
/// use bvh::Real;
/// # use bvh::bounding_hierarchy::BHShape;
/// # pub struct UnitBox {
/// # pub id: i32,
Expand Down Expand Up @@ -72,7 +73,7 @@ pub trait BoundingHierarchy {
/// # fn create_bhshapes() -> Vec<UnitBox> {
/// # let mut shapes = Vec::new();
/// # for i in 0..1000 {
/// # let position = Point3::new(i as f32, i as f32, i as f32);
/// # let position = Point3::new(i as Real, i as Real, i as Real);
/// # shapes.push(UnitBox::new(i, position));
/// # }
/// # shapes
Expand Down Expand Up @@ -107,6 +108,7 @@ pub trait BoundingHierarchy {
/// use bvh::bvh::BVH;
/// use bvh::{Point3, Vector3};
/// use bvh::ray::Ray;
/// use bvh::Real;
/// # use bvh::bounding_hierarchy::BHShape;
/// # pub struct UnitBox {
/// # pub id: i32,
Expand Down Expand Up @@ -145,7 +147,7 @@ pub trait BoundingHierarchy {
/// # fn create_bvh() -> (BVH, Vec<UnitBox>) {
/// # let mut shapes = Vec::new();
/// # for i in 0..1000 {
/// # let position = Point3::new(i as f32, i as f32, i as f32);
/// # let position = Point3::new(i as Real, i as Real, i as Real);
/// # shapes.push(UnitBox::new(i, position));
/// # }
/// # let bvh = BVH::build(&mut shapes);
Expand All @@ -163,11 +165,27 @@ pub trait BoundingHierarchy {
/// [`BoundingHierarchy`]: trait.BoundingHierarchy.html
/// [`AABB`]: ../aabb/struct.AABB.html
///
fn traverse<'a, Shape: BHShape>(&'a self, ray: &Ray, shapes: &'a [Shape]) -> Vec<&Shape>;
fn traverse<'a, Shape: BHShape>(
&'a self,
test: &impl IntersectionAABB,
shapes: &'a [Shape],
) -> Vec<&Shape>;

/// Prints the [`BoundingHierarchy`] in a tree-like visualization.
///
/// [`BoundingHierarchy`]: trait.BoundingHierarchy.html
///
fn pretty_print(&self) {}
}

/// This trait can be implemented on anything that can intersect with an `AABB`
/// Used to traverse the `BVH`
///
/// [`AABB`]: ../aabb/struct.AABB.html
///
/// [`BVH`]: ../bvh/struct.BVH.html
///
pub trait IntersectionAABB {
/// Returns true if there is an intersection with the given `AABB`
fn intersects_aabb(&self, aabb: &AABB) -> bool;
}
Loading