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

Bevy 0.13 update #1

Merged
merged 6 commits into from
Mar 19, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/[email protected]
- run: cargo check --workspace --no-default-features --all-targets
- run: cargo check --workspace --no-default-features

clippy:
runs-on: ubuntu-latest
Expand Down
50 changes: 38 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bevy_editor_cam"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
description = "A camera controller for editors and CAD."
license = "MIT OR Apache-2.0"
Expand All @@ -9,22 +9,48 @@ repository = "https://github.com/aevyrie/bevy_editor_cam"
documentation = "https://docs.rs/crate/bevy_editor_cam/latest"
exclude = ["assets/"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["extension_anchor_indicator", "extension_independent_skybox"]
extension_anchor_indicator = ["bevy_gizmos"]
extension_independent_skybox = ["bevy_asset", "bevy_core_pipeline"]

[dependencies]
bevy = { version = "0.12.1", default-features = false, features = [
"bevy_render",
"bevy_gizmos",
"bevy_asset",
"bevy_core_pipeline",
] }
bevy_picking_core = "0.17"
bevy_app = "0.13"
bevy_derive = "0.13"
bevy_ecs = "0.13"
bevy_input = "0.13"
bevy_log = "0.13"
bevy_math = "0.13"
bevy_reflect = "0.13"
bevy_render = "0.13"
bevy_time = "0.13"
bevy_transform = "0.13"
bevy_utils = "0.13"
bevy_window = "0.13"
# Optional
bevy_asset = { version = "0.13", optional = true }
bevy_core_pipeline = { version = "0.13", optional = true }
bevy_gizmos = { version = "0.13", optional = true }
# 3rd party
bevy_picking_core = "0.18"

[dev-dependencies]
bevy = { version = "0.12", features = ["jpeg"] }
bevy_mod_picking = { version = "0.17", default-features = false, features = [
bevy = { version = "0.13", default-features = false, features = [
"bevy_gizmos",
"bevy_gltf",
"bevy_scene",
"bevy_text",
"bevy_ui",
"bevy_winit",
"jpeg",
"ktx2",
"tonemapping_luts",
"x11",
"zstd",
] }
bevy_mod_picking = { version = "0.18", default-features = false, features = [
"backend_raycast",
] }

big_space = "0.4"
big_space = "0.5"
rand = "0.8"
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,11 @@ A production-ready camera controller for 2D/3D editors and CAD.

https://github.com/aevyrie/bevy_editor_cam/assets/2632925/50e342ac-9cb3-4ab5-8577-45b3955fe423

<details>
<summary><h2>Bevy Version Support</h2></summary>

| bevy | bevy_editor_cam |
| ---- | ---------------- |
| 0.13 | 0.2 |
| 0.12 | 0.1 |
</details>
67 changes: 40 additions & 27 deletions examples/cad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use std::time::Duration;

use bevy::{
core_pipeline::{
bloom::BloomSettings, experimental::taa::TemporalAntiAliasPlugin, tonemapping::Tonemapping,
bloom::BloomSettings,
experimental::taa::{TemporalAntiAliasBundle, TemporalAntiAliasPlugin},
tonemapping::Tonemapping,
},
pbr::ScreenSpaceAmbientOcclusionBundle,
prelude::*,
render::primitives::Aabb,
utils::Instant,
Expand All @@ -20,9 +23,9 @@ fn main() {
TemporalAntiAliasPlugin,
))
// The camera controller works with reactive rendering:
.insert_resource(bevy::winit::WinitSettings::desktop_app())
.insert_resource(Msaa::Sample4)
.insert_resource(ClearColor(Color::WHITE))
// .insert_resource(bevy::winit::WinitSettings::desktop_app())
.insert_resource(Msaa::Off)
.insert_resource(ClearColor(Color::NONE))
.insert_resource(AmbientLight {
brightness: 0.0,
..default()
Expand All @@ -42,33 +45,43 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
..Default::default()
});

commands.spawn((
Camera3dBundle {
transform: Transform::from_xyz(2.0, 2.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y),
tonemapping: Tonemapping::AcesFitted,
..default()
},
BloomSettings::default(),
EnvironmentMapLight {
diffuse_map: diffuse_map.clone(),
specular_map: specular_map.clone(),
},
EditorCam {
orbit_constraint: OrbitConstraint::Free,
last_anchor_depth: 2.0,
..Default::default()
},
bevy_editor_cam::extensions::independent_skybox::IndependentSkybox::new(diffuse_map),
));
commands
.spawn((
Camera3dBundle {
transform: Transform::from_xyz(2.0, 2.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y),
tonemapping: Tonemapping::AcesFitted,
..default()
},
BloomSettings::default(),
EnvironmentMapLight {
intensity: 1000.0,
diffuse_map: diffuse_map.clone(),
specular_map: specular_map.clone(),
},
EditorCam {
orbit_constraint: OrbitConstraint::Fixed {
up: Vec3::Y,
can_pass_tdc: false,
},
last_anchor_depth: 2.0,
..Default::default()
},
bevy_editor_cam::extensions::independent_skybox::IndependentSkybox::new(
diffuse_map,
500.0,
),
))
.insert(ScreenSpaceAmbientOcclusionBundle::default())
.insert(TemporalAntiAliasBundle::default());
}

fn toggle_projection(
keys: Res<Input<KeyCode>>,
keys: Res<ButtonInput<KeyCode>>,
mut dolly: EventWriter<DollyZoomTrigger>,
cam: Query<Entity, With<EditorCam>>,
mut toggled: Local<bool>,
) {
if keys.just_pressed(KeyCode::P) {
if keys.just_pressed(KeyCode::KeyP) {
*toggled = !*toggled;
let target_projection = if *toggled {
Projection::Orthographic(OrthographicProjection::default())
Expand All @@ -78,7 +91,7 @@ fn toggle_projection(
dolly.send(DollyZoomTrigger {
target_projection,
camera: cam.single(),
})
});
}
}

Expand Down Expand Up @@ -110,15 +123,15 @@ struct StartPos(f32);
#[allow(clippy::type_complexity)]
fn explode(
mut commands: Commands,
keys: Res<Input<KeyCode>>,
keys: Res<ButtonInput<KeyCode>>,
mut toggle: Local<Option<(bool, Instant, f32)>>,
mut explode_amount: Local<f32>,
mut redraw: EventWriter<RequestRedraw>,
mut parts: Query<(Entity, &mut Transform, &Aabb, Option<&StartPos>), With<Handle<Mesh>>>,
mut matls: ResMut<Assets<StandardMaterial>>,
) {
let animation = Duration::from_millis(2000);
if keys.just_pressed(KeyCode::E) {
if keys.just_pressed(KeyCode::KeyE) {
let new = if let Some((last, ..)) = *toggle {
!last
} else {
Expand Down
152 changes: 10 additions & 142 deletions examples/floating_origin.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,18 @@
//! This example demonstrates that the camera controller was designed to work with floating origin
//! systems for large worlds. Because the controller *never* relies on the `GlobalTransform` of the
//! camera, and instead only moves relative to the current position, it is compatible with arbitrary
//! transform systems.

use bevy::{prelude::*, transform::TransformSystem};
use bevy_editor_cam::prelude::*;
use big_space::{
camera::{CameraController, CameraInput},
FloatingOrigin, GridCell,
};
use bevy::prelude::*;
use bevy_editor_cam::{controller::component::EditorCam, DefaultEditorCamPlugins};
use big_space::{FloatingOrigin, GridCell};

fn main() {
App::new()
.add_plugins((
DefaultPlugins.build().disable::<TransformPlugin>(),
bevy_mod_picking::DefaultPickingPlugins,
DefaultEditorCamPlugins,
big_space::FloatingOriginPlugin::<i128>::default(),
big_space::debug::FloatingOriginDebugPlugin::<i128>::default(),
big_space::camera::CameraControllerPlugin::<i128>::default(),
bevy_mod_picking::DefaultPickingPlugins, // Prerequisite: Use picking plugin
DefaultEditorCamPlugins,
))
.insert_resource(CameraInput {
defaults_disabled: true,
..Default::default()
})
.insert_resource(ClearColor(Color::BLACK))
.add_systems(Startup, (setup, ui_setup))
.add_systems(Update, ui_text_system)
.add_systems(
PostUpdate,
highlight_nearest_sphere.after(TransformSystem::TransformPropagate),
)
.run()
}

Expand All @@ -50,20 +32,12 @@ fn setup(
}),
..default()
},
GridCell::<i128>::default(), // All spatial entities need this component
FloatingOrigin, // Important: marks the floating origin entity for rendering.
CameraController::default(),
GridCell::<i128>::default(),
FloatingOrigin,
EditorCam::default(),
));

let mesh_handle = meshes.add(
shape::Icosphere {
radius: 0.5,
subdivisions: 32,
}
.try_into()
.unwrap(),
);
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,
Expand Down Expand Up @@ -112,7 +86,7 @@ fn ui_setup(mut commands: Commands) {
..default()
},
)
.with_text_alignment(TextAlignment::Left)
.with_text_justify(JustifyText::Left)
.with_style(Style {
position_type: PositionType::Absolute,
top: Val::Px(10.0),
Expand All @@ -138,113 +112,7 @@ fn ui_setup(mut commands: Commands) {
left: Val::Px(10.0),
..default()
})
.with_text_alignment(TextAlignment::Center),
.with_text_justify(JustifyText::Center),
FunFactText,
));
}

fn highlight_nearest_sphere(
cameras: Query<&CameraController>,
objects: Query<&GlobalTransform>,
mut gizmos: Gizmos,
) {
let Some((entity, _)) = cameras.single().nearest_object() else {
return;
};
let Ok(transform) = objects.get(entity) else {
return;
};
let (scale, rotation, translation) = transform.to_scale_rotation_translation();
gizmos
.sphere(translation, rotation, scale.x * 0.505, Color::RED)
.circle_segments(128);
}

fn ui_text_system(
mut debug_text: Query<&mut Text, (With<BigSpaceDebugText>, Without<FunFactText>)>,
mut fun_text: Query<&mut Text, (With<FunFactText>, Without<BigSpaceDebugText>)>,
time: Res<Time>,
origin: Query<(&GridCell<i128>, &Transform), With<FloatingOrigin>>,
camera: Query<&CameraController>,
objects: Query<&Transform, With<Handle<Mesh>>>,
) {
let (cell, transform) = origin.single();
let translation = transform.translation;

let grid_text = format!("GridCell: {}x, {}y, {}z", cell.x, cell.y, cell.z);

let translation_text = format!(
"Transform: {:>8.2}x, {:>8.2}y, {:>8.2}z",
translation.x, translation.y, translation.z
);

let velocity = camera.single().velocity();
let speed = velocity.0.length() / time.delta_seconds_f64();
let camera_text = if speed > 3.0e8 {
format!("Speed: {:.0e} * speed of light", speed / 3.0e8)
} else {
format!("Speed: {:.2e} m/s", speed)
};

let (nearest_text, fact_text) = if let Some(nearest) = camera.single().nearest_object() {
let dia = objects.get(nearest.0).unwrap().scale.max_element();
let (fact_dia, fact) = closest(dia);
let dist = nearest.1;
let multiple = dia / fact_dia;
(
format!(
"\nNearest sphere distance: {dist:.0e} m\nNearest sphere diameter: {dia:.0e} m",
),
format!("{multiple:.1}x {fact}"),
)
} else {
("".into(), "".into())
};

debug_text.single_mut().sections[0].value =
format!("{grid_text}\n{translation_text}\n{camera_text}\n{nearest_text}");

fun_text.single_mut().sections[0].value = fact_text
}

fn closest<'a>(diameter: f32) -> (f32, &'a str) {
let items = vec![
(8.8e26, "diameter of the observable universe"),
(9e25, "length of the Hercules-Corona Borealis Great Wall"),
(1e24, "diameter of the Local Supercluster"),
(9e22, "diameter of the Local Group"),
(1e21, "diameter of the Milky Way galaxy"),
(5e16, "length of the Pillars of Creation"),
(1.8e14, "diameter of Messier 87"),
(7e12, "diameter of Pluto's orbit"),
(24e9, "diameter of Sagittarius A"),
(1.4e9, "diameter of the Sun"),
(1.4e8, "diameter of Jupiter"),
(12e6, "diameter of Earth"),
(3e6, "diameter of the Moon"),
(9e3, "height of Mt. Everest"),
(3.8e2, "height of the Empire State Building"),
(2.5e1, "length of a train car"),
(1.8, "height of a human"),
(1e-1, "size of a cat"),
(1e-2, "size of a mouse"),
(1e-3, "size of an insect"),
(1e-4, "diameter of a eukaryotic cell"),
(1e-5, "width of a human hair"),
(1e-6, "diameter of a bacteria"),
(5e-8, "size of a phage"),
(5e-9, "size of a transistor"),
(1e-10, "diameter of a carbon atom"),
(4e-11, "diameter of a hydrogen atom"),
(4e-12, "diameter of an electron"),
(1.9e-15, "diameter of a proton"),
];

let mut min = items[0];
for item in items.iter() {
if (item.0 - diameter).abs() < (min.0 - diameter).abs() {
min = item.to_owned();
}
}
min
}
Loading
Loading