Skip to content

Commit

Permalink
name and doc refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
aevyrie committed Dec 23, 2024
1 parent 0001d49 commit 7671bbe
Show file tree
Hide file tree
Showing 33 changed files with 1,666 additions and 1,696 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ bevy = { version = "0.15.0", default-features = false, features = [
noise = "0.9"
turborand = "0.10"
criterion = "0.5"
bytemuck = "1.19.0"
# bevy_hanabi = "0.14"
bytemuck = "1.20"
bevy_hanabi = "0.14"

[[bench]]
name = "benchmarks"
Expand Down
38 changes: 15 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,28 @@
[![crates.io](https://img.shields.io/crates/v/big_space)](https://crates.io/crates/big_space)
[![docs.rs](https://docs.rs/big_space/badge.svg)](https://docs.rs/big_space)
[![test suite](https://github.com/aevyrie/big_space/actions/workflows/rust.yml/badge.svg)](https://github.com/aevyrie/big_space/actions/workflows/rust.yml)
[![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-main-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking)

A floating origin plugin for [Bevy](https://github.com/bevyengine/bevy).
![Big space logo](https://raw.githubusercontent.com/aevyrie/big_space/refs/heads/main/assets/bigspacebanner.svg)

https://user-images.githubusercontent.com/2632925/215318129-5bab3095-a7dd-455b-a4b6-71840cde096c.mp4

### [Read the docs](https://docs.rs/big_space)
Huge worlds, high performance, no dependencies, ecosystem compatibility.
[Read the docs](https://docs.rs/big_space)

</div>

## Features

Lots of space to play in.

This is a floating origin plugin, useful if you want to work with very large or very small scales. It works with bevy's existing `f32`-based `Transform`s, which means it's largely compatible with the bevy ecosystem. The plugin positions entities within large fixed precision grids, effectively adding precision to the location of objects.

Additionally, you can use reference frames to nest high precision coordinate systems. For example you might want to put all entities on a planet's surface into the same reference frame. You can then rotate this reference frame with the planet, and orbit that planet around a star.

The plugin is generic over a few integer types, to trade off scale and precision for memory use. Some fun numbers with a worst case precision of 0.5mm:
- `i8`: 2,560 km = 74% of the diameter of the Moon
- `i16`: 655,350 km = 85% of the diameter of the Moon's orbit around Earth
- `i32`: 0.0045 light years = ~4 times the width of the solar system
- `i64`: 19.5 million light years = ~100 times the width of the milky way galaxy
- `i128`: 3.6e+26 light years = ~3.9e+15 times the width of the observable universe

This can also be used for small scales. With a cell edge length of `1e-11`, and using `i128`, there is enough precision to render objects the size of quarks anywhere in the observable universe.
## Highlights

From the docs: https://docs.rs/big_space/latest/big_space/precision/trait.GridPrecision.html
- Enough precision to render protons across the observable universe.
- Uses `Transform`, making it compatible with most of the Bevy ecosystem.
- No added dependencies.
- Absolute coordinates without drift, unlike camera-relative or periodic recentering solutions.
- Chunks the world into integer grids, from `i8` up to `i128`.
- Grids can be nested.
- Spatial hashing for fast grid cell lookups and neighbor search.
- Spatial partitioning to group sets of disconnected entities.
- 3-5x faster than Bevy's transform propagation for wide hierarchies.
- 👉 [Extensive documentation you should read.](https://docs.rs/big_space)

# Bevy Version Support
## Bevy Version Support

| bevy | big_space |
| ---- | --------- |
Expand Down
63 changes: 28 additions & 35 deletions benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ criterion_main!(benches);
fn global_transform(c: &mut Criterion) {
let mut group = c.benchmark_group("propagation");
group.bench_function("global_transform", |b| {
let frame = ReferenceFrame::default();
let grid = Grid::default();
let local_cell = GridCell { x: 1, y: 1, z: 1 };
let local_transform = Transform::from_xyz(9.0, 200.0, 500.0);
b.iter(|| {
black_box(frame.global_transform(&local_cell, &local_transform));
black_box(grid.global_transform(&local_cell, &local_transform));
});
});
}
Expand All @@ -38,13 +38,10 @@ fn deep_hierarchy(c: &mut Criterion) {
let mut group = c.benchmark_group(format!("deep_hierarchy {N_SPAWN}"));

fn setup(mut commands: Commands) {
commands.spawn_big_space::<i32>(ReferenceFrame::new(10000.0, 0.0), |root| {
let mut parent = root.spawn_frame_default(()).id();
commands.spawn_big_space::<i32>(Grid::new(10000.0, 0.0), |root| {
let mut parent = root.spawn_grid_default(()).id();
for _ in 0..N_SPAWN {
let child = root
.commands()
.spawn(BigReferenceFrameBundle::<i32>::default())
.id();
let child = root.commands().spawn(BigGridBundle::<i32>::default()).id();
root.commands().entity(parent).add_child(child);
parent = child;
}
Expand All @@ -61,7 +58,7 @@ fn deep_hierarchy(c: &mut Criterion) {
let mut app = App::new();
app.add_plugins((
MinimalPlugins,
SpatialHashPlugin::<i32>::default(),
GridHashPlugin::<i32>::default(),
BigSpacePlugin::<i32>::default(),
))
.add_systems(Startup, setup)
Expand All @@ -83,7 +80,7 @@ fn wide_hierarchy(c: &mut Criterion) {
let mut group = c.benchmark_group(format!("wide_hierarchy {N_SPAWN}"));

fn setup(mut commands: Commands) {
commands.spawn_big_space::<i32>(ReferenceFrame::new(10000.0, 0.0), |root| {
commands.spawn_big_space::<i32>(Grid::new(10000.0, 0.0), |root| {
for _ in 0..N_SPAWN {
root.spawn_spatial(());
}
Expand All @@ -100,7 +97,7 @@ fn wide_hierarchy(c: &mut Criterion) {
let mut app = App::new();
app.add_plugins((
MinimalPlugins,
SpatialHashPlugin::<i32>::default(),
GridHashPlugin::<i32>::default(),
BigSpacePlugin::<i32>::default(),
))
.add_systems(Startup, setup)
Expand All @@ -125,7 +122,7 @@ fn spatial_hashing(c: &mut Criterion) {
const N_MOVE: usize = 1_000;

fn setup(mut commands: Commands) {
commands.spawn_big_space::<i32>(ReferenceFrame::new(1.0, 0.0), |root| {
commands.spawn_big_space::<i32>(Grid::new(1.0, 0.0), |root| {
let rng = Rng::with_seed(342525);
let values: Vec<_> = repeat_with(|| {
[
Expand All @@ -150,7 +147,7 @@ fn spatial_hashing(c: &mut Criterion) {
}

let mut app = App::new();
app.add_plugins(SpatialHashPlugin::<i32>::default())
app.add_plugins(GridHashPlugin::<i32>::default())
.add_systems(Startup, setup)
.update();

Expand All @@ -167,12 +164,12 @@ fn spatial_hashing(c: &mut Criterion) {
});
});

let map = app.world().resource::<SpatialHashMap<i32>>();
let map = app.world().resource::<HashGrid<i32>>();
let first = map
.all_entries()
.find(|(_, entry)| !entry.entities.is_empty())
.unwrap();
group.bench_function("SpatialHashMap::get", |b| {
group.bench_function("HashGrid::get", |b| {
b.iter(|| {
black_box(map.get(first.0).unwrap());
});
Expand All @@ -188,13 +185,9 @@ fn spatial_hashing(c: &mut Criterion) {
});
});

// let parent = app
// .world_mut()
// .query::<&SpatialHash<i32>>()
// .get(app.world(), ent)
// .unwrap();
// let map = app.world().resource::<SpatialHashMap<i32>>();
// let entry = map.get(parent).unwrap();
// let parent = app .world_mut() .query::<&GridCellHash<i32>>() .get(app.world(), ent)
// .unwrap(); let map = app.world().resource::<HashGrid<i32>>(); let entry =
// map.get(parent).unwrap();

// group.bench_function("Neighbors radius: 4", |b| {
// b.iter(|| {
Expand All @@ -212,7 +205,7 @@ fn spatial_hashing(c: &mut Criterion) {
// });

fn setup_uniform<const HALF_EXTENT: i32>(mut commands: Commands) {
commands.spawn_big_space::<i32>(ReferenceFrame::new(1.0, 0.0), |root| {
commands.spawn_big_space::<i32>(Grid::new(1.0, 0.0), |root| {
for x in HALF_EXTENT.neg()..HALF_EXTENT {
for y in HALF_EXTENT.neg()..HALF_EXTENT {
for z in HALF_EXTENT.neg()..HALF_EXTENT {
Expand All @@ -226,16 +219,16 @@ fn spatial_hashing(c: &mut Criterion) {
// Uniform Grid Population 1_000

let mut app = App::new();
app.add_plugins(SpatialHashPlugin::<i32>::default())
app.add_plugins(GridHashPlugin::<i32>::default())
.add_systems(Startup, setup_uniform::<5>)
.update();

let parent = app
.world_mut()
.query_filtered::<Entity, With<BigSpace>>()
.single(app.world());
let spatial_map = app.world().resource::<SpatialHashMap<i32>>();
let hash = SpatialHash::__new_manual(parent, &GridCell { x: 0, y: 0, z: 0 });
let spatial_map = app.world().resource::<HashGrid<i32>>();
let hash = GridCellHash::__new_manual(parent, &GridCell { x: 0, y: 0, z: 0 });
let entry = spatial_map.get(&hash).unwrap();

assert_eq!(spatial_map.nearby(entry).count(), 27);
Expand All @@ -254,16 +247,16 @@ fn spatial_hashing(c: &mut Criterion) {
// Uniform Grid Population 1_000_000

let mut app = App::new();
app.add_plugins(SpatialHashPlugin::<i32>::default())
app.add_plugins(GridHashPlugin::<i32>::default())
.add_systems(Startup, setup_uniform::<50>)
.update();

let parent = app
.world_mut()
.query_filtered::<Entity, With<BigSpace>>()
.single(app.world());
let spatial_map = app.world().resource::<SpatialHashMap<i32>>();
let hash = SpatialHash::__new_manual(parent, &GridCell { x: 0, y: 0, z: 0 });
let spatial_map = app.world().resource::<HashGrid<i32>>();
let hash = GridCellHash::__new_manual(parent, &GridCell { x: 0, y: 0, z: 0 });
let entry = spatial_map.get(&hash).unwrap();

assert_eq!(spatial_map.nearby(entry).count(), 27);
Expand Down Expand Up @@ -324,7 +317,7 @@ fn hash_filtering(c: &mut Criterion) {
.add_systems(Update, translate)
.update();
app.update();
app.add_plugins((SpatialHashPlugin::<i32>::default(),));
app.add_plugins((GridHashPlugin::<i32>::default(),));
group.bench_function("No Filter Plugin", |b| {
b.iter(|| {
black_box(app.update());
Expand All @@ -336,7 +329,7 @@ fn hash_filtering(c: &mut Criterion) {
.add_systems(Update, translate)
.update();
app.update();
app.add_plugins((SpatialHashPlugin::<i32, With<Player>>::default(),));
app.add_plugins((GridHashPlugin::<i32, With<Player>>::default(),));
group.bench_function("With Player Plugin", |b| {
b.iter(|| {
black_box(app.update());
Expand All @@ -348,7 +341,7 @@ fn hash_filtering(c: &mut Criterion) {
.add_systems(Update, translate)
.update();
app.update();
app.add_plugins((SpatialHashPlugin::<i32, Without<Player>>::default(),));
app.add_plugins((GridHashPlugin::<i32, Without<Player>>::default(),));
group.bench_function("Without Player Plugin", |b| {
b.iter(|| {
black_box(app.update());
Expand All @@ -360,9 +353,9 @@ fn hash_filtering(c: &mut Criterion) {
.add_systems(Update, translate)
.update();
app.update();
app.add_plugins((SpatialHashPlugin::<i32>::default(),))
.add_plugins((SpatialHashPlugin::<i32, With<Player>>::default(),))
.add_plugins((SpatialHashPlugin::<i32, Without<Player>>::default(),));
app.add_plugins((GridHashPlugin::<i32>::default(),))
.add_plugins((GridHashPlugin::<i32, With<Player>>::default(),))
.add_plugins((GridHashPlugin::<i32, Without<Player>>::default(),));
group.bench_function("All Plugins", |b| {
b.iter(|| {
black_box(app.update());
Expand Down
8 changes: 4 additions & 4 deletions examples/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fn setup(
..default()
});

commands.spawn_big_space::<i64>(ReferenceFrame::new(1.0, 0.01), |root| {
commands.spawn_big_space::<i64>(Grid::new(1.0, 0.01), |root| {
root.spawn_spatial((
Mesh3d(mesh_handle.clone()),
MeshMaterial3d(matl_handle.clone()),
Expand All @@ -79,15 +79,15 @@ fn setup(
Mover::<2>,
));

root.with_frame(ReferenceFrame::new(0.2, 0.01), |new_frame| {
new_frame.insert((
root.with_grid(Grid::new(0.2, 0.01), |new_grid| {
new_grid.insert((
Mesh3d(mesh_handle.clone()),
MeshMaterial3d(matl_handle.clone()),
Transform::from_xyz(0.0, 1.0, 0.0),
Rotator,
Mover::<3>,
));
new_frame.spawn_spatial((
new_grid.spawn_spatial((
Mesh3d(mesh_handle),
MeshMaterial3d(matl_handle),
Transform::from_xyz(0.0, 0.5, 0.0),
Expand Down
6 changes: 3 additions & 3 deletions examples/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn ui_text_system(
(With<BigSpaceDebugText>, Without<FunFactText>),
>,
mut fun_text: Query<&mut Text, (With<FunFactText>, Without<BigSpaceDebugText>)>,
ref_frames: ReferenceFrames<i128>,
grids: Grids<i128>,
time: Res<Time>,
origin: Query<(Entity, GridTransformReadOnly<i128>), With<FloatingOrigin>>,
camera: Query<&CameraController>,
Expand All @@ -169,11 +169,11 @@ fn ui_text_system(
translation.x, translation.y, translation.z
);

let Some(ref_frame) = ref_frames.parent_frame(origin_entity) else {
let Some(grid) = grids.parent_grid(origin_entity) else {
return;
};

let real_position = ref_frame.grid_position_double(origin_pos.cell, origin_pos.transform);
let real_position = grid.grid_position_double(origin_pos.cell, origin_pos.transform);
let real_position_f64_text = format!(
"Combined (f64): {}x, {}y, {}z",
real_position.x, real_position.y, real_position.z
Expand Down
10 changes: 5 additions & 5 deletions examples/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const DISTANCE: i128 = 2_000_000;
/// this issue.
fn toggle_plugin(
input: Res<ButtonInput<KeyCode>>,
ref_frames: ReferenceFrames<i128>,
grids: Grids<i128>,
mut text: Query<&mut Text>,
mut disabled: Local<bool>,
mut floating_origin: Query<(Entity, &mut GridCell<i128>), With<FloatingOrigin>>,
Expand All @@ -39,10 +39,10 @@ fn toggle_plugin(
*disabled = !*disabled;
}

let this_frame = ref_frames.parent_frame(floating_origin.single().0).unwrap();
let this_grid = grids.parent_grid(floating_origin.single().0).unwrap();

let mut origin_cell = floating_origin.single_mut().1;
let index_max = DISTANCE / this_frame.cell_edge_length() as i128;
let index_max = DISTANCE / this_grid.cell_edge_length() as i128;
let increment = index_max / 100;

let msg = if *disabled {
Expand All @@ -64,7 +64,7 @@ fn toggle_plugin(
"Floating Origin Enabled"
};

let dist = index_max.saturating_sub(origin_cell.x) * this_frame.cell_edge_length() as i128;
let dist = index_max.saturating_sub(origin_cell.x) * this_grid.cell_edge_length() as i128;

let thousands = |num: i128| {
num.to_string()
Expand Down Expand Up @@ -108,7 +108,7 @@ fn setup_ui(mut commands: Commands) {

fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn_big_space_default::<i128>(|root| {
let d = DISTANCE / root.frame().cell_edge_length() as i128;
let d = DISTANCE / root.grid().cell_edge_length() as i128;
let distant_grid_cell = GridCell::<i128>::new(d, d, d);

// Normally, we would put the floating origin on the camera. However in this example, we
Expand Down
Loading

0 comments on commit 7671bbe

Please sign in to comment.