From 8721911b495c4d3c6966f3467813389d32503797 Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Mon, 17 Jun 2024 01:41:03 -0700 Subject: [PATCH] Explicit `BigSpace`s (#22) Changes the design of the plugin to work with multiple, independent high-precision hierarchies at the root with the `BigSpace` component at the root of each of these hierarchies. Closes #17 Closes #19 Closes #21 --- Cargo.toml | 10 + README.md | 10 +- assets/models/low_poly_spaceship/license.txt | 11 + assets/models/low_poly_spaceship/scene.bin | Bin 0 -> 149784 bytes assets/models/low_poly_spaceship/scene.gltf | 470 +++++++++++++ examples/debug.rs | 92 ++- examples/demo.rs | 111 ++-- examples/error.rs | 148 ++--- examples/error_child.rs | 152 ++--- examples/planets.rs | 420 ++++++++---- examples/split_screen.rs | 270 ++++++++ src/bundles.rs | 69 ++ src/camera.rs | 63 +- src/commands.rs | 211 ++++++ src/debug.rs | 14 +- src/floating_origins.rs | 87 +++ src/grid_cell.rs | 85 ++- src/lib.rs | 427 ++++-------- src/plugin.rs | 117 ++++ src/precision.rs | 30 + src/propagation.rs | 220 ------ src/reference_frame/local_origin.rs | 662 +++++++++---------- src/reference_frame/mod.rs | 31 +- src/reference_frame/propagation.rs | 181 +++++ src/tests.rs | 96 +++ src/validation.rs | 296 +++++++++ 26 files changed, 2949 insertions(+), 1334 deletions(-) create mode 100644 assets/models/low_poly_spaceship/license.txt create mode 100644 assets/models/low_poly_spaceship/scene.bin create mode 100644 assets/models/low_poly_spaceship/scene.gltf create mode 100644 examples/split_screen.rs create mode 100644 src/bundles.rs create mode 100644 src/commands.rs create mode 100644 src/floating_origins.rs create mode 100644 src/plugin.rs delete mode 100644 src/propagation.rs create mode 100644 src/reference_frame/propagation.rs create mode 100644 src/tests.rs create mode 100644 src/validation.rs diff --git a/Cargo.toml b/Cargo.toml index e44d159..cc5732c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,13 +15,17 @@ bevy = { version = "0.13", default_features = false } [dev-dependencies] bevy = { version = "0.13", default-features = false, features = [ + "bevy_scene", + "bevy_gltf", "bevy_winit", "default_font", "bevy_ui", "bevy_pbr", "x11", "tonemapping_luts", + "multi-threaded", ] } +bevy-inspector-egui = "0.24" bevy_framepace = { version = "0.15", default-features = false } rand = "0.8.5" @@ -60,3 +64,9 @@ name = "planets" path = "examples/planets.rs" required-features = ["default"] doc-scrape-examples = true + +[[example]] +name = "split_screen" +path = "examples/split_screen.rs" +required-features = ["default"] +doc-scrape-examples = true diff --git a/README.md b/README.md index f1e2364..1ce0c23 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ https://user-images.githubusercontent.com/2632925/215318129-5bab3095-a7dd-455b-a Lots of space to play in. -This is a simple floating origin plugin, useful if you want to work with very, very large 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. +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 into the same reference frame. You can then rotate this reference frame with the planet, and orbit that planet around a star. +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 @@ -30,12 +30,12 @@ The plugin is generic over a few integer types, to trade off scale and precision - `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 -From the docs: https://docs.rs/big_space/latest/big_space/struct.GridCell.html +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. + +From the docs: https://docs.rs/big_space/latest/big_space/precision/trait.GridPrecision.html # Bevy Version Support -I intend to track the `main` branch of Bevy. PRs supporting this are welcome! - | bevy | big_space | | ---- | --------- | | 0.13 | 0.5, 0.6 | diff --git a/assets/models/low_poly_spaceship/license.txt b/assets/models/low_poly_spaceship/license.txt new file mode 100644 index 0000000..9124690 --- /dev/null +++ b/assets/models/low_poly_spaceship/license.txt @@ -0,0 +1,11 @@ +Model Information: +* title: Low Poly Spaceship +* source: https://sketchfab.com/3d-models/low-poly-spaceship-f854128cf78d4dafb28d16b3c15001ba +* author: FriendlyCreep (https://sketchfab.com/FriendlyCreep) + +Model License: +* license type: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/) +* requirements: Author must be credited. Commercial use is allowed. + +If you use this 3D model in your project be sure to copy paste this credit wherever you share it: +This work is based on "Low Poly Spaceship" (https://sketchfab.com/3d-models/low-poly-spaceship-f854128cf78d4dafb28d16b3c15001ba) by FriendlyCreep (https://sketchfab.com/FriendlyCreep) licensed under CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/) \ No newline at end of file diff --git a/assets/models/low_poly_spaceship/scene.bin b/assets/models/low_poly_spaceship/scene.bin new file mode 100644 index 0000000000000000000000000000000000000000..2ca8904fa7b02350cc827cb6440b30338e946bd3 GIT binary patch literal 149784 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
4qlE${cspWkwSavt;ZTrtnZdinlV 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 PUHPWT@XC_%O_Toz-Pqrl literal 0 HcmV?d00001 diff --git a/assets/models/low_poly_spaceship/scene.gltf b/assets/models/low_poly_spaceship/scene.gltf new file mode 100644 index 0000000..f637834 --- /dev/null +++ b/assets/models/low_poly_spaceship/scene.gltf @@ -0,0 +1,470 @@ +{ + "accessors": [ + { + "bufferView": 2, + "componentType": 5126, + "count": 712, + "max": [ + 4.986988067626953, + 0.5560435652732849, + 9.616311073303223 + ], + "min": [ + -4.986988067626953, + -1.969908356666565, + -4.9558634757995605 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 8544, + "componentType": 5126, + "count": 712, + "max": [ + 1.0, + 0.9917697906494141, + 0.9999937415122986 + ], + "min": [ + -1.0, + -0.9730851054191589, + -0.9999937415122986 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 712, + "max": [ + 0.7559658885002136, + 0.75 + ], + "min": [ + 0.1249999925494194, + 0.24999994039535522 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "componentType": 5125, + "count": 1164, + "type": "SCALAR" + }, + { + "bufferView": 2, + "byteOffset": 17088, + "componentType": 5126, + "count": 1768, + "max": [ + 5.272348403930664, + 0.6022237539291382, + 9.626778602600098 + ], + "min": [ + -5.272348403930664, + -2.1259989738464355, + -4.9558634757995605 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 38304, + "componentType": 5126, + "count": 1768, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 5696, + "componentType": 5126, + "count": 1768, + "max": [ + 0.875, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "byteOffset": 4656, + "componentType": 5125, + "count": 5070, + "type": "SCALAR" + }, + { + "bufferView": 2, + "byteOffset": 59520, + "componentType": 5126, + "count": 866, + "max": [ + 3.563509702682495, + 0.6022237539291382, + 9.626778602600098 + ], + "min": [ + -3.563509702682495, + -1.5118601322174072, + -4.9558634757995605 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 69912, + "componentType": 5126, + "count": 866, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 19840, + "componentType": 5126, + "count": 866, + "max": [ + 0.875, + 0.75 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "byteOffset": 24936, + "componentType": 5125, + "count": 1476, + "type": "SCALAR" + }, + { + "bufferView": 2, + "byteOffset": 80304, + "componentType": 5126, + "count": 296, + "max": [ + 4.863146781921387, + 0.5145567655563354, + 9.446455955505371 + ], + "min": [ + -4.863146781921387, + -1.8699951171875, + -4.738320827484131 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 83856, + "componentType": 5126, + "count": 296, + "max": [ + 1.0, + 1.0, + 0.9979816675186157 + ], + "min": [ + -0.8001577854156494, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 26768, + "componentType": 5126, + "count": 296, + "max": [ + 0.7559658885002136, + 0.735460638999939 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + }, + { + "bufferView": 0, + "byteOffset": 30840, + "componentType": 5125, + "count": 600, + "type": "SCALAR" + } + ], + "asset": { + "extras": { + "author": "FriendlyCreep (https://sketchfab.com/FriendlyCreep)", + "license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)", + "source": "https://sketchfab.com/3d-models/low-poly-spaceship-f854128cf78d4dafb28d16b3c15001ba", + "title": "Low Poly Spaceship" + }, + "generator": "Sketchfab-12.68.0", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 33240, + "name": "floatBufferViews", + "target": 34963 + }, + { + "buffer": 0, + "byteLength": 29136, + "byteOffset": 33240, + "byteStride": 8, + "name": "floatBufferViews", + "target": 34962 + }, + { + "buffer": 0, + "byteLength": 87408, + "byteOffset": 62376, + "byteStride": 12, + "name": "floatBufferViews", + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 149784, + "uri": "scene.bin" + } + ], + "materials": [ + { + "doubleSided": true, + "name": "Material.001", + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.0, + 0.0, + 0.0, + 1.0 + ], + "metallicFactor": 0.0, + "roughnessFactor": 0.5 + } + }, + { + "doubleSided": true, + "name": "Material.002", + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.226583, + 0.226583, + 0.226583, + 1.0 + ], + "metallicFactor": 0.0, + "roughnessFactor": 0.5 + } + }, + { + "doubleSided": true, + "name": "Material.003", + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.8, + 0.0113789, + 0.0, + 1.0 + ], + "metallicFactor": 0.0, + "roughnessFactor": 0.5 + } + }, + { + "doubleSided": true, + "emissiveFactor": [ + 0.0, + 0.161466, + 1.0 + ], + "name": "Material.004" + } + ], + "meshes": [ + { + "name": "Object_0", + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 0, + "TEXCOORD_0": 2 + }, + "indices": 3, + "material": 0, + "mode": 4 + } + ] + }, + { + "name": "Object_1", + "primitives": [ + { + "attributes": { + "NORMAL": 5, + "POSITION": 4, + "TEXCOORD_0": 6 + }, + "indices": 7, + "material": 1, + "mode": 4 + } + ] + }, + { + "name": "Object_2", + "primitives": [ + { + "attributes": { + "NORMAL": 9, + "POSITION": 8, + "TEXCOORD_0": 10 + }, + "indices": 11, + "material": 2, + "mode": 4 + } + ] + }, + { + "name": "Object_3", + "primitives": [ + { + "attributes": { + "NORMAL": 13, + "POSITION": 12, + "TEXCOORD_0": 14 + }, + "indices": 15, + "material": 3, + "mode": 4 + } + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 2.220446049250313e-16, + -1.0, + 0.0, + 0.0, + 1.0, + 2.220446049250313e-16, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ], + "name": "Sketchfab_model" + }, + { + "children": [ + 2 + ], + "name": "root" + }, + { + "children": [ + 3 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 2.220446049250313e-16, + 1.0, + 0.0, + 0.0, + -1.0, + 2.220446049250313e-16, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ], + "name": "GLTF_SceneRootNode" + }, + { + "children": [ + 4, + 5, + 6, + 7 + ], + "name": "Cube_0" + }, + { + "mesh": 0, + "name": "Object_4" + }, + { + "mesh": 1, + "name": "Object_5" + }, + { + "mesh": 2, + "name": "Object_6" + }, + { + "mesh": 3, + "name": "Object_7" + } + ], + "scene": 0, + "scenes": [ + { + "name": "Sketchfab_Scene", + "nodes": [ + 0 + ] + } + ] +} diff --git a/examples/debug.rs b/examples/debug.rs index 162b7d9..65a5aa9 100644 --- a/examples/debug.rs +++ b/examples/debug.rs @@ -1,13 +1,13 @@ #![allow(clippy::type_complexity)] use bevy::prelude::*; -use big_space::{reference_frame::ReferenceFrame, FloatingOrigin, GridCell}; +use big_space::{commands::BigSpaceCommands, reference_frame::ReferenceFrame, FloatingOrigin}; fn main() { App::new() .add_plugins(( DefaultPlugins.build().disable::(), - big_space::FloatingOriginPlugin::::new(0.5, 0.01), + big_space::BigSpacePlugin::::default(), big_space::debug::FloatingOriginDebugPlugin::::default(), )) .insert_resource(ClearColor(Color::BLACK)) @@ -65,69 +65,63 @@ fn setup( ..default() }); - commands.spawn(( - PbrBundle { - mesh: mesh_handle.clone(), - material: matl_handle.clone(), - transform: Transform::from_xyz(0.0, 0.0, 1.0), - ..default() - }, - GridCell::::default(), - Mover::<1>, - )); - commands.spawn(( - PbrBundle { - mesh: mesh_handle.clone(), - material: matl_handle.clone(), - transform: Transform::from_xyz(1.0, 0.0, 0.0), - ..default() - }, - GridCell::::default(), - Mover::<2>, - )); - commands - .spawn(( + commands.spawn_big_space(ReferenceFrame::::new(1.0, 0.01), |root| { + root.spawn_spatial(( PbrBundle { mesh: mesh_handle.clone(), material: matl_handle.clone(), - transform: Transform::from_xyz(0.0, 1.0, 0.0), + transform: Transform::from_xyz(0.0, 0.0, 1.0), ..default() }, - GridCell::::default(), - ReferenceFrame::::new(0.2, 0.01), - Rotator, - Mover::<3>, - )) - .with_children(|parent| { - parent.spawn(( + Mover::<1>, + )); + + root.spawn_spatial(( + PbrBundle { + mesh: mesh_handle.clone(), + material: matl_handle.clone(), + transform: Transform::from_xyz(1.0, 0.0, 0.0), + ..default() + }, + Mover::<2>, + )); + + root.with_frame(ReferenceFrame::new(0.2, 0.01), |new_frame| { + new_frame.insert(( + PbrBundle { + mesh: mesh_handle.clone(), + material: matl_handle.clone(), + transform: Transform::from_xyz(0.0, 1.0, 0.0), + ..default() + }, + Rotator, + Mover::<3>, + )); + new_frame.spawn_spatial(( PbrBundle { mesh: mesh_handle, material: matl_handle, transform: Transform::from_xyz(0.0, 0.5, 0.0), ..default() }, - GridCell::::default(), Mover::<4>, )); }); - // light - commands.spawn(( - PointLightBundle { + // light + root.spawn_spatial((PointLightBundle { transform: Transform::from_xyz(4.0, 8.0, 4.0), ..default() - }, - GridCell::::default(), - )); + },)); - // camera - commands.spawn(( - Camera3dBundle { - transform: Transform::from_xyz(0.0, 0.0, 8.0) - .looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y), - ..default() - }, - GridCell::::default(), - FloatingOrigin, - )); + // camera + root.spawn_spatial(( + Camera3dBundle { + transform: Transform::from_xyz(0.0, 0.0, 8.0) + .looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y), + ..default() + }, + FloatingOrigin, + )); + }); } diff --git a/examples/demo.rs b/examples/demo.rs index feb746b..37a4812 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -5,27 +5,27 @@ use bevy::{ }; use big_space::{ camera::{CameraController, CameraInput}, - propagation::IgnoreFloatingOrigin, - reference_frame::RootReferenceFrame, + commands::BigSpaceCommands, + reference_frame::{local_origin::ReferenceFrames, ReferenceFrame}, world_query::GridTransformReadOnly, - FloatingOrigin, GridCell, + FloatingOrigin, }; fn main() { App::new() .add_plugins(( DefaultPlugins.build().disable::(), - big_space::FloatingOriginPlugin::::default(), + big_space::BigSpacePlugin::::default(), big_space::debug::FloatingOriginDebugPlugin::::default(), big_space::camera::CameraControllerPlugin::::default(), bevy_framepace::FramepacePlugin, )) .insert_resource(ClearColor(Color::BLACK)) .add_systems(Startup, (setup, ui_setup)) - .add_systems(PreUpdate, cursor_grab_system) + .add_systems(PreUpdate, (cursor_grab_system, ui_text_system)) .add_systems( PostUpdate, - (highlight_nearest_sphere, ui_text_system).after(TransformSystem::TransformPropagate), + highlight_nearest_sphere.after(TransformSystem::TransformPropagate), ) .run() } @@ -35,57 +35,56 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - // camera - commands.spawn(( - Camera3dBundle { - transform: Transform::from_xyz(0.0, 0.0, 8.0) - .looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y), - projection: Projection::Perspective(PerspectiveProjection { - near: 1e-18, + commands.spawn_big_space(ReferenceFrame::::default(), |root| { + root.spawn_spatial(( + Camera3dBundle { + transform: Transform::from_xyz(0.0, 0.0, 8.0) + .looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y), + projection: Projection::Perspective(PerspectiveProjection { + near: 1e-18, + ..default() + }), ..default() - }), + }, + FloatingOrigin, // Important: marks the floating origin entity for rendering. + CameraController::default() // Built-in camera controller + .with_speed_bounds([10e-18, 10e35]) + .with_smoothness(0.9, 0.8) + .with_speed(1.0), + )); + + let mesh_handle = meshes.add(Sphere::new(0.5).mesh().ico(32).unwrap()); + let matl_handle = materials.add(StandardMaterial { + base_color: Color::BLUE, + perceptual_roughness: 0.8, + reflectance: 1.0, ..default() - }, - GridCell::::default(), // All spatial entities need this component - FloatingOrigin, // Important: marks the floating origin entity for rendering. - CameraController::default() // Built-in camera controller - .with_speed_bounds([10e-18, 10e35]) - .with_smoothness(0.9, 0.8) - .with_speed(1.0), - )); + }); - let mesh_handle = meshes.add(Sphere::new(0.5).mesh().ico(32).unwrap()); - let matl_handle = materials.add(StandardMaterial { - base_color: Color::BLUE, - perceptual_roughness: 0.8, - reflectance: 1.0, - ..default() - }); + let mut translation = Vec3::ZERO; + for i in -16..=27 { + let j = 10_f32.powf(i as f32); + let k = 10_f32.powf((i - 1) as f32); + translation.x += j / 2.0 + k; + translation.y = j / 2.0; - let mut translation = Vec3::ZERO; - for i in -16..=27 { - let j = 10_f32.powf(i as f32); - let k = 10_f32.powf((i - 1) as f32); - translation.x += j / 2.0 + k; - commands.spawn(( - PbrBundle { + root.spawn_spatial(PbrBundle { mesh: mesh_handle.clone(), material: matl_handle.clone(), transform: Transform::from_scale(Vec3::splat(j)).with_translation(translation), ..default() - }, - GridCell::::default(), - )); - } + }); + } - // light - commands.spawn((DirectionalLightBundle { - directional_light: DirectionalLight { - illuminance: 100_000.0, + // light + root.spawn_spatial(DirectionalLightBundle { + directional_light: DirectionalLight { + illuminance: 100_000.0, + ..default() + }, ..default() - }, - ..default() - },)); + }); + }); } #[derive(Component, Reflect)] @@ -112,7 +111,6 @@ fn ui_setup(mut commands: Commands) { ..default() }), BigSpaceDebugText, - IgnoreFloatingOrigin, )); commands.spawn(( @@ -133,7 +131,6 @@ fn ui_setup(mut commands: Commands) { }) .with_text_justify(JustifyText::Center), FunFactText, - IgnoreFloatingOrigin, )); } @@ -162,18 +159,18 @@ fn ui_text_system( (With, Without), >, mut fun_text: Query<&mut Text, (With, Without)>, + ref_frames: ReferenceFrames, time: Res