//! This example demonstrates what floating point error in rendering looks like. You can press //! spacebar to smoothly switch between enabling and disabling the floating origin. //! //! Instead of disabling the plugin outright, this example simply moves the floating origin //! independently from the camera, which is equivalent to what would happen when moving far from the //! origin when not using this plugin. use bevy::prelude::*; use big_space::{ commands::BigSpaceCommands, reference_frame::{local_origin::ReferenceFrames, ReferenceFrame}, FloatingOrigin, GridCell, }; fn main() { App::new() .add_plugins(( DefaultPlugins.build().disable::(), big_space::BigSpacePlugin::::default(), )) .add_systems(Startup, (setup_scene, setup_ui)) .add_systems(Update, (rotator_system, toggle_plugin)) .run(); } /// You can put things really, really far away from the origin. The distance we use here is actually /// quite small, because we want the mesh to still be visible when the floating origin is far from /// the camera. If you go much further than this, the mesh will simply disappear in a *POOF* of /// floating point error when we disable this plugin. /// /// This plugin can function much further from the origin without any issues. Try setting this to: /// 10_000_000_000_000_000_000_000_000_000_000_000_000 const DISTANCE: i128 = 2_000_000; /// Move the floating origin back to the "true" origin when the user presses the spacebar to emulate /// disabling the plugin. Normally you would make your active camera the floating origin to avoid /// this issue. fn toggle_plugin( input: Res>, ref_frames: ReferenceFrames, mut text: Query<&mut Text>, mut disabled: Local, mut floating_origin: Query<(Entity, &mut GridCell), With>, ) { if input.just_pressed(KeyCode::Space) { *disabled = !*disabled; } let this_frame = ref_frames.parent_frame(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 increment = index_max / 100; let msg = if *disabled { if origin_cell.x > 0 { origin_cell.x = 0.max(origin_cell.x - increment); origin_cell.y = 0.max(origin_cell.y - increment); origin_cell.z = 0.max(origin_cell.z - increment); "Disabling..." } else { "Floating Origin Disabled" } } else if origin_cell.x < index_max { origin_cell.x = index_max.min(origin_cell.x.saturating_add(increment)); origin_cell.y = index_max.min(origin_cell.y.saturating_add(increment)); origin_cell.z = index_max.min(origin_cell.z.saturating_add(increment)); "Enabling..." } else { "Floating Origin Enabled" }; let dist = index_max.saturating_sub(origin_cell.x) * this_frame.cell_edge_length() as i128; let thousands = |num: i128| { num.to_string() .as_bytes() .rchunks(3) .rev() .map(std::str::from_utf8) .collect::, _>>() .unwrap() .join(",") // separator }; text.single_mut().sections[0].value = format!("Press Spacebar to toggle: {msg}\nCamera distance to floating origin: {}\nMesh distance from origin: {}", thousands(dist), thousands(DISTANCE)) } #[derive(Component)] struct Rotator; fn rotator_system(time: Res