Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/camera/camera_orbit.rs
6592 views
1
//! Shows how to orbit camera around a static scene using pitch, yaw, and roll.
2
//!
3
//! See also: `first_person_view_model` example, which does something similar but as a first-person
4
//! camera view.
5
6
use std::{f32::consts::FRAC_PI_2, ops::Range};
7
8
use bevy::{input::mouse::AccumulatedMouseMotion, prelude::*};
9
10
#[derive(Debug, Resource)]
11
struct CameraSettings {
12
pub orbit_distance: f32,
13
pub pitch_speed: f32,
14
// Clamp pitch to this range
15
pub pitch_range: Range<f32>,
16
pub roll_speed: f32,
17
pub yaw_speed: f32,
18
}
19
20
impl Default for CameraSettings {
21
fn default() -> Self {
22
// Limiting pitch stops some unexpected rotation past 90° up or down.
23
let pitch_limit = FRAC_PI_2 - 0.01;
24
Self {
25
// These values are completely arbitrary, chosen because they seem to produce
26
// "sensible" results for this example. Adjust as required.
27
orbit_distance: 20.0,
28
pitch_speed: 0.003,
29
pitch_range: -pitch_limit..pitch_limit,
30
roll_speed: 1.0,
31
yaw_speed: 0.004,
32
}
33
}
34
}
35
36
fn main() {
37
App::new()
38
.add_plugins(DefaultPlugins)
39
.init_resource::<CameraSettings>()
40
.add_systems(Startup, (setup, instructions))
41
.add_systems(Update, orbit)
42
.run();
43
}
44
45
/// Set up a simple 3D scene
46
fn setup(
47
mut commands: Commands,
48
mut meshes: ResMut<Assets<Mesh>>,
49
mut materials: ResMut<Assets<StandardMaterial>>,
50
) {
51
commands.spawn((
52
Name::new("Camera"),
53
Camera3d::default(),
54
Transform::from_xyz(5.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
55
));
56
57
commands.spawn((
58
Name::new("Plane"),
59
Mesh3d(meshes.add(Plane3d::default().mesh().size(5.0, 5.0))),
60
MeshMaterial3d(materials.add(StandardMaterial {
61
base_color: Color::srgb(0.3, 0.5, 0.3),
62
// Turning off culling keeps the plane visible when viewed from beneath.
63
cull_mode: None,
64
..default()
65
})),
66
));
67
68
commands.spawn((
69
Name::new("Cube"),
70
Mesh3d(meshes.add(Cuboid::default())),
71
MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))),
72
Transform::from_xyz(1.5, 0.51, 1.5),
73
));
74
75
commands.spawn((
76
Name::new("Light"),
77
PointLight::default(),
78
Transform::from_xyz(3.0, 8.0, 5.0),
79
));
80
}
81
82
fn instructions(mut commands: Commands) {
83
commands.spawn((
84
Name::new("Instructions"),
85
Text::new(
86
"Mouse up or down: pitch\n\
87
Mouse left or right: yaw\n\
88
Mouse buttons: roll",
89
),
90
Node {
91
position_type: PositionType::Absolute,
92
top: px(12),
93
left: px(12),
94
..default()
95
},
96
));
97
}
98
99
fn orbit(
100
mut camera: Single<&mut Transform, With<Camera>>,
101
camera_settings: Res<CameraSettings>,
102
mouse_buttons: Res<ButtonInput<MouseButton>>,
103
mouse_motion: Res<AccumulatedMouseMotion>,
104
time: Res<Time>,
105
) {
106
let delta = mouse_motion.delta;
107
let mut delta_roll = 0.0;
108
109
if mouse_buttons.pressed(MouseButton::Left) {
110
delta_roll -= 1.0;
111
}
112
if mouse_buttons.pressed(MouseButton::Right) {
113
delta_roll += 1.0;
114
}
115
116
// Mouse motion is one of the few inputs that should not be multiplied by delta time,
117
// as we are already receiving the full movement since the last frame was rendered. Multiplying
118
// by delta time here would make the movement slower that it should be.
119
let delta_pitch = delta.y * camera_settings.pitch_speed;
120
let delta_yaw = delta.x * camera_settings.yaw_speed;
121
122
// Conversely, we DO need to factor in delta time for mouse button inputs.
123
delta_roll *= camera_settings.roll_speed * time.delta_secs();
124
125
// Obtain the existing pitch, yaw, and roll values from the transform.
126
let (yaw, pitch, roll) = camera.rotation.to_euler(EulerRot::YXZ);
127
128
// Establish the new yaw and pitch, preventing the pitch value from exceeding our limits.
129
let pitch = (pitch + delta_pitch).clamp(
130
camera_settings.pitch_range.start,
131
camera_settings.pitch_range.end,
132
);
133
let roll = roll + delta_roll;
134
let yaw = yaw + delta_yaw;
135
camera.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
136
137
// Adjust the translation to maintain the correct orientation toward the orbit target.
138
// In our example it's a static target, but this could easily be customized.
139
let target = Vec3::ZERO;
140
camera.translation = target - camera.forward() * camera_settings.orbit_distance;
141
}
142
143