You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi, I modified the PanOrbitCamera in the cookbook to work with 0.12, this is the solution I found to make it work, basically replacing windows: Res in pan_orbit_camera with windows:Query<&Window>.
Some of the constants have different values, but otherwise the code is almost identical.
I had to specify a WindowPlugin when creating the App, below is the code, feel free to modify/post it as you see fit. Hope it helps.
use bevy::input::mouse::{MouseMotion, MouseWheel};
use bevy::prelude::*;
pub(crate) struct PanOrbitCameraPlugin;
impl Plugin for PanOrbitCameraPlugin {
fn build(&self, app: &mut App) {
app
.add_systems(Startup, spawn_camera)
.add_systems(Update, pan_orbit_camera);
}
}
#[derive(Component)]
struct PanOrbitCamera {
focus: Vec3,
radius: f32,
upside_down: bool
}
impl Default for PanOrbitCamera {
fn default() -> Self {
Self {
focus: Vec3::ZERO,
radius: 5.0,
upside_down: false
}
}
}
fn spawn_camera(mut commands: Commands) {
let translation = Vec3::new(10.0, 20.0, 50.0);
let radius = translation.length();
let transform = Transform::from_translation(translation)
.looking_at(Vec3::ZERO, Vec3::Y);
let camera = Camera3dBundle {
transform,
..default()
};
let pan_orbit = PanOrbitCamera {
radius,
..default()
};
commands.spawn((camera, pan_orbit));
}
fn pan_orbit_camera(
windows:Query<&Window>,
mut ev_motion: EventReader<MouseMotion>,
mut ev_scroll: EventReader<MouseWheel>,
input_mouse: Res<Input<MouseButton>>,
mut query: Query<(&mut PanOrbitCamera, &mut Transform, &Projection)>
) {
// change input mapping for orbit and panning here
let orbit_button = MouseButton::Right;
let pan_button = MouseButton::Middle;
let mut pan = Vec2::ZERO;
let mut rotation_move = Vec2::ZERO;
let mut scroll = 0.0;
let mut orbit_button_changed = false;
if input_mouse.pressed(orbit_button) {
for ev in ev_motion.read() {
rotation_move += ev.delta;
}
} else if input_mouse.pressed(pan_button) {
// Pan only if we're not rotating at the moment
for ev in ev_motion.read() {
pan += ev.delta;
}
}
for ev in ev_scroll.read() {
scroll += ev.y;
}
if input_mouse.just_released(orbit_button) || input_mouse.just_pressed(orbit_button) {
orbit_button_changed = true;
}
for (mut pan_orbit, mut transform, projection) in query.iter_mut() {
if orbit_button_changed {
// only check for upside down when orbiting started or ended this frame
// if the camera is "upside" down, panning horizontally would be inverted, so invert the input to make it correct
let up = transform.rotation * Vec3::Y;
pan_orbit.upside_down = up.y <= 0.0;
}
let mut any = false;
if rotation_move.length_squared() > 0.0 {
any = true;
let window = get_primary_window_size(&windows);
let delta_x = {
let delta = rotation_move.x / window.x * std::f32::consts::PI * 2.0;
if pan_orbit.upside_down { -delta } else { delta }
};
let delta_y = rotation_move.y / window.y * std::f32::consts::PI;
let yaw = Quat::from_rotation_y(-delta_x);
let pitch = Quat::from_rotation_x(-delta_y);
transform.rotation = yaw * transform.rotation; // rotate around global y axis
transform.rotation = transform.rotation * pitch; // rotate around local x axis
} else if pan.length_squared() > 0.0 {
any = true;
// make panning distance independent of resolution and FOV,
let window = get_primary_window_size(&windows);
if let Projection::Perspective(projection) = projection {
pan *= Vec2::new(projection.fov * projection.aspect_ratio, projection.fov) / window;
}
// translate by local axes
let right = transform.rotation * Vec3::X * -pan.x;
let up = transform.rotation * Vec3::Y * pan.y;
// make panning proportional to distance away from focus point
let translation = (right + up) * pan_orbit.radius;
pan_orbit.focus += translation;
} else if scroll.abs() > 0.0 {
any = true;
pan_orbit.radius -= scroll * pan_orbit.radius * 0.2;
// dont allow zoom to reach zero or you get stuck
pan_orbit.radius = f32::max(pan_orbit.radius, 0.05);
}
if any {
// emulating parent/child to make the yaw/y-axis rotation behave like a turntable
// parent = x and y rotation
// child = z-offset
let rot_matrix = Mat3::from_quat(transform.rotation);
transform.translation = pan_orbit.focus + rot_matrix.mul_vec3(Vec3::new(0.0, 0.0, pan_orbit.radius));
}
}
// consume any remaining events, so they don't pile up if we don't need them
// (and also to avoid Bevy warning us about not checking events every frame update)
ev_motion.clear();
}
fn get_primary_window_size(windows: &Query<&Window>) -> Vec2 {
let window = windows.single();
let window = Vec2::new(window.width() as f32, window.height() as f32);
window
}
The text was updated successfully, but these errors were encountered:
Hi, I modified the PanOrbitCamera in the cookbook to work with 0.12, this is the solution I found to make it work, basically replacing windows: Res in pan_orbit_camera with windows:Query<&Window>.
Some of the constants have different values, but otherwise the code is almost identical.
I had to specify a WindowPlugin when creating the App, below is the code, feel free to modify/post it as you see fit. Hope it helps.
main.rs
camera.rs
The text was updated successfully, but these errors were encountered: