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

Move math types over to nalgebra with Generic dimensions > 2 and f32/f64 support #96

Merged
merged 22 commits into from
May 4, 2023
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
79 changes: 45 additions & 34 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,65 @@ name: CI
on: [push, pull_request]

jobs:
ci:
name: CI with ${{ matrix.rust }} on ${{ matrix.os }}
check-fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check

clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
components: clippy
- name: Run clippy
run: cargo clippy --all-targets --all-features -- -D warnings

build-and-test-no-simd:
name: CI with ${{ matrix.rust }} on ${{ matrix.os }} [no SIMD]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
rust: [stable, nightly]

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Setup Rust toolchain
uses: actions-rs/toolchain@v1
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: rustfmt, clippy

- name: cargo build
uses: actions-rs/cargo@v1
with:
command: build
args: --workspace
run: cargo build

- name: cargo test
uses: actions-rs/cargo@v1
with:
command: test

- name: cargo fmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check

- name: cargo clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --workspace --all-targets --all-features -- -D warnings
if: matrix.rust == 'nightly'

# - name: Run cargo-tarpaulin
# uses: actions-rs/[email protected]
# if: matrix.os == 'ubuntu-latest' && matrix.rust == 'stable'
run: cargo test

- name: Upload coverage report to codecov.io
uses: codecov/codecov-action@v1
if: matrix.os == 'ubuntu-latest' && matrix.rust == 'stable'

build-and-test-simd:
name: CI with nightly on ${{ matrix.os }} [SIMD]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]

steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@nightly

- name: cargo build
run: cargo build --features simd

- name: cargo test
run: cargo test --features simd
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased] - ReleaseDate

### Added

- BVH now works with 2d+ dimensions
- BVH now works with f32/f64
- `simd` feature flag, allows for optimizations via explicit SIMD instructions on nightly

### Changed

- Moved from glam to nalgebra
- Code uppercase acronyms changed to API conventions (BVH -> Bvh)
- Major performance improvements on BVH optimization
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ version = "0.7.2"
edition = "2018"
authors = [
"Sven-Hendrik Haase <[email protected]>",
"Alexander Dmitriev <[email protected]>"
"Alexander Dmitriev <[email protected]>",
svenstaro marked this conversation as resolved.
Show resolved Hide resolved
"Marios Staikopoulos <[email protected]>",
]
readme = "README.md"
repository = "https://github.com/svenstaro/bvh"
Expand All @@ -18,9 +19,9 @@ resolver = "2"
approx = "0.5"
rand = "0.8"
log = "0.4"
num = "0.4"
glam = "0.23"
serde = { optional = true, version = "1", features = ["derive"] }
num = "0.4.0"
nalgebra = { version = "0.32.2", features = ["default", "serde-serialize"] }

[dev-dependencies]
proptest = "1.0"
Expand All @@ -30,7 +31,7 @@ doc-comment = "0.3"

[features]
bench = []
serde = ["dep:serde", "glam/serde"]
simd = []

[profile.release]
lto = true
Expand Down
34 changes: 25 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,32 @@ iterative traversal of the BVH.
## Example

```rust
use bvh::aabb::{AABB, Bounded};
use bvh::aabb::{Aabb, Bounded};
use bvh::bounding_hierarchy::BHShape;
use bvh::bvh::BVH;
use bvh::{Point3, Vector3};
use bvh::bvh::Bvh;
use bvh::ray::Ray;
use nalgebra::{Point3, Vector3};

let origin = Point3::new(0.0,0.0,0.0);
let direction = Vector3::new(1.0,0.0,0.0);
let ray = Ray::new(origin, direction);

struct Sphere {
position: Point3,
position: Point3<f32>,
radius: f32,
node_index: usize,
}

impl Bounded for Sphere {
fn aabb(&self) -> AABB {
impl Bounded<f32, 3> for Sphere {
fn aabb(&self) -> Aabb<f32, 3> {
let half_size = Vector3::new(self.radius, self.radius, self.radius);
let min = self.position - half_size;
let max = self.position + half_size;
AABB::with_bounds(min, max)
Aabb::with_bounds(min, max)
}
}

impl BHShape for Sphere {
impl BHShape<f32, 3> for Sphere {
fn set_bh_node_index(&mut self, index: usize) {
self.node_index = index;
}
Expand All @@ -67,10 +67,22 @@ for i in 0..1000u32 {
});
}

let bvh = BVH::build(&mut spheres);
let bvh = Bvh::build(&mut spheres);
let hit_sphere_aabbs = bvh.traverse(&ray, &spheres);
```

## Explicit SIMD

This crate features some manually written SIMD instructions, currently only for the `x86_64` architecture.
While nalgebra provides us with generic SIMD optimization (and it does a great job for the most part) -
some important functions, such as ray-aabb-intersection have been optimized by hand.

The currently optimized intersections for ray-aabb are:
Type: f32, Dimension: 2,3,4
Type: f64, Dimension: 2,3,4

svenstaro marked this conversation as resolved.
Show resolved Hide resolved
To enable these optimziations, you must build with the `nightly` toolchain and enable the `simd` flag.

## Optimization

This crate provides BVH updating, which is also called optimization. With BVH optimization
Expand Down Expand Up @@ -155,6 +167,10 @@ These performance measurements show that traversing a BVH is much faster than tr

### Optimization

> **Warning**
> The optimization benchmarks here are no longer current, and perform around 1/4 as fast as the current implementation.
> This section needs to be revisited.

The benchmarks for how long it takes to update the scene also contain a randomization process which takes some time.

```C
Expand Down
26 changes: 13 additions & 13 deletions examples/simple.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
use bvh::aabb::{Bounded, AABB};
use bvh::aabb::{Aabb, Bounded};
use bvh::bounding_hierarchy::BHShape;
use bvh::bvh::BVH;
use bvh::bvh::Bvh;
use bvh::ray::Ray;
use bvh::{Point3, Vector3};
use nalgebra::{Point, SVector};

#[derive(Debug)]
struct Sphere {
position: Point3,
position: Point<f32, 3>,
radius: f32,
node_index: usize,
}

impl Bounded for Sphere {
fn aabb(&self) -> AABB {
let half_size = Vector3::new(self.radius, self.radius, self.radius);
impl Bounded<f32, 3> for Sphere {
fn aabb(&self) -> Aabb<f32, 3> {
let half_size = SVector::<f32, 3>::new(self.radius, self.radius, self.radius);
let min = self.position - half_size;
let max = self.position + half_size;
AABB::with_bounds(min, max)
Aabb::with_bounds(min, max)
}
}

impl BHShape for Sphere {
impl BHShape<f32, 3> for Sphere {
fn set_bh_node_index(&mut self, index: usize) {
self.node_index = index;
}
Expand All @@ -33,18 +33,18 @@ 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 position = Point::<f32, 3>::new(i as f32, i as f32, i as f32);
let radius = (i % 10) as f32 + 1.0;
spheres.push(Sphere {
position,
radius,
node_index: 0,
});
}
let bvh = BVH::build(&mut spheres);
let bvh = Bvh::build(&mut spheres);

let origin = Point3::new(0.0, 0.0, 0.0);
let direction = Vector3::new(1.0, 0.0, 0.0);
let origin = Point::<f32, 3>::new(0.0, 0.0, 0.0);
let direction = SVector::<f32, 3>::new(1.0, 0.0, 0.0);
let ray = Ray::new(origin, direction);
let hit_sphere_aabbs = bvh.traverse(&ray, &spheres);
dbg!(hit_sphere_aabbs);
Expand Down
Loading