7 releases (4 breaking)
0.5.0 | Dec 17, 2024 |
---|---|
0.4.1 | Dec 4, 2024 |
0.4.0 | Nov 27, 2024 |
0.3.0 | Nov 22, 2024 |
0.1.0 | Nov 3, 2024 |
#181 in Game dev
Used in bye_octomap_rs
4MB
3K
SLoC
Oktree
Fast octree implementation.
Able to operate with Position
or Volume
data.
Could be used with the Bevy game engine or as a standalone tree.
Available methods:
-
Unsigned operations
-
Floating point operations (Bevy integration)
To enable bevy integrations:
[dependencies]
oktree = { version = "0.5.0", features = ["bevy"] }
Optimizations:
Unsigned
arithmetics, bitwise operations.- Tree structure is represented by flat, reusable pools. Removed data is marked only.
- Few memory allocations.
Smallvec
andHeapless
structures are used. - No smart pointers (
Rc
,RefCell
e.t.c)
Compensation for the inconvenience is perfomance.
Benchmark
Octree dimensions: 4096x4096x4096
Operation | Quantity | Time |
---|---|---|
insertion | 65536 cells | 21 ms |
removing | 65536 cells | 1.5 ms |
find | 65536 searches in 65536 cells | 12 ms |
ray intersection | 4096 rays against 65536 cells | 37 ms |
sphere intersection | 4096 spheres against 65536 cells | 8 ms |
box intersection | 4096 boxes against 65536 cells | 7 ms |
Run benchmark:
cargo bench --all-features
Examples
Simple
You have to specify the type for the internal tree structure.
It must be any Unsigned
type (u8
, u16
, u32
, u64
, u128
or usize
).
Implement Position
or Volume
for the handled type, so that it can return it's spatial coordinates.
use bevy::math::{
bounding::{Aabb3d, BoundingSphere, RayCast3d},
Dir3, Vec3,
};
use oktree::prelude::*;
fn main() -> Result<(), TreeError> {
let aabb = Aabb::new(TUVec3::splat(16), 16u8);
let mut tree = Octree::from_aabb_with_capacity(aabb?, 10);
let c1 = DummyCell::new(TUVec3::splat(1u8));
let c2 = DummyCell::new(TUVec3::splat(8u8));
let c1_id = tree.insert(c1)?;
let c2_id = tree.insert(c2)?;
// Searching by position
assert_eq!(tree.find(&TUVec3::new(1, 1, 1)), Some(c1_id));
assert_eq!(tree.find(&TUVec3::new(8, 8, 8)), Some(c2_id));
assert_eq!(tree.find(&TUVec3::new(1, 2, 8)), None);
assert_eq!(tree.find(&TUVec3::splat(100)), None);
// Searching for the ray intersection
let ray = RayCast3d::new(Vec3::new(1.5, 7.0, 1.9), Dir3::NEG_Y, 100.0);
// Hit!
assert_eq!(
tree.ray_cast(&ray),
HitResult {
element: Some(ElementId(0)),
distance: 5.0
}
);
assert_eq!(tree.remove(ElementId(0)), Ok(()));
// Miss!
assert_eq!(
tree.ray_cast(&ray),
HitResult {
element: None,
distance: 0.0
}
);
let c1 = DummyCell::new(TUVec3::splat(1u8));
let c1_id = tree.insert(c1)?;
// Aabb intersection
let aabb = Aabb3d::new(Vec3::splat(2.0), Vec3::splat(2.0));
assert_eq!(tree.intersect(&aabb), vec![c1_id]);
// Sphere intersection
let sphere = BoundingSphere::new(Vec3::splat(2.0), 2.0);
assert_eq!(tree.intersect(&sphere), vec![c1_id]);
Ok(())
}
struct DummyCell {
position: TUVec3<u8>,
}
impl Position for DummyCell {
type U = u8;
fn position(&self) -> TUVec3<u8> {
self.position
}
}
impl DummyCell {
fn new(position: TUVec3<u8>) -> Self {
DummyCell { position }
}
}
Bevy
Run bevy visual example:
cargo run --release --example bevy_tree --all-features
no_std
no_std
is supported, but you steel need to specify a global allocator.
See example with a custom allocator.
Run no_std
example
cargo run --no-default-features --features bevy --example no_std
Contribution guide
Feature and pull requests are welcomed.
- Clone the Oktree repo
git clone https://github.com/exor2008/oktree
-
Implement awesome feature
-
Run tests
cargo test --all-targets --all-features --release
- Make sure clippy is happy
cargo clippy --all-targets --all-features
- Run examples
cargo run --all-features --example simple
cargo run --all-features --example bevy_tree
cargo run --no-default-features --features bevy --example no_std
- Run benchmark
cargo bench --all-features
- Check the docs
cargo doc --no-deps --open --all-features
- Start pull request
Dependencies
~0.9–13MB
~156K SLoC