1use bevy::{
10 camera::{ScalingMode, SubCameraView, Viewport},
11 prelude::*,
12};
13
14fn main() {
15 App::new()
16 .add_plugins(DefaultPlugins)
17 .add_systems(Startup, setup)
18 .add_systems(Update, (move_camera_view, resize_viewports))
19 .run();
20}
21
22#[derive(Debug, Component)]
23struct MovingCameraMarker;
24
25fn setup(
27 mut commands: Commands,
28 mut meshes: ResMut<Assets<Mesh>>,
29 mut materials: ResMut<Assets<StandardMaterial>>,
30) {
31 let transform = Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y);
32
33 commands.spawn((
35 Mesh3d(meshes.add(Plane3d::default().mesh().size(5.0, 5.0))),
36 MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))),
37 ));
38
39 commands.spawn((
41 Mesh3d(meshes.add(Cuboid::default())),
42 MeshMaterial3d(materials.add(Color::srgb(0.8, 0.7, 0.6))),
43 Transform::from_xyz(0.0, 0.5, 0.0),
44 ));
45
46 commands.spawn((
48 PointLight {
49 shadow_maps_enabled: true,
50 ..default()
51 },
52 Transform::from_xyz(4.0, 8.0, 4.0),
53 ));
54
55 commands.spawn((
59 Camera3d::default(),
60 Camera::default(),
61 ExampleViewports::PerspectiveMain,
62 transform,
63 ));
64
65 commands.spawn((
74 Camera3d::default(),
75 Camera {
76 sub_camera_view: Some(SubCameraView {
77 full_size: UVec2::new(10, 10),
81 offset: Vec2::new(5.0, 0.0),
84 size: UVec2::new(5, 10),
85 }),
86 order: 1,
87 ..default()
88 },
89 ExampleViewports::PerspectiveStretched,
90 transform,
91 ));
92
93 commands.spawn((
101 Camera3d::default(),
102 Camera {
103 sub_camera_view: Some(SubCameraView {
104 full_size: UVec2::new(500, 500),
105 offset: Vec2::ZERO,
106 size: UVec2::new(100, 100),
107 }),
108 order: 2,
109 ..default()
110 },
111 transform,
112 ExampleViewports::PerspectiveMoving,
113 MovingCameraMarker,
114 ));
115
116 commands.spawn((
124 Camera3d::default(),
125 Camera {
126 sub_camera_view: Some(SubCameraView {
127 full_size: UVec2::new(800, 800),
128 offset: Vec2::ZERO,
129 size: UVec2::new(800, 400),
130 }),
131 order: 3,
132 ..default()
133 },
134 ExampleViewports::PerspectiveControl,
135 transform,
136 ));
137
138 commands.spawn((
142 Camera3d::default(),
143 Projection::from(OrthographicProjection {
144 scaling_mode: ScalingMode::FixedVertical {
145 viewport_height: 6.0,
146 },
147 ..OrthographicProjection::default_3d()
148 }),
149 Camera {
150 order: 4,
151 ..default()
152 },
153 ExampleViewports::OrthographicMain,
154 transform,
155 ));
156
157 commands.spawn((
164 Camera3d::default(),
165 Projection::from(OrthographicProjection {
166 scaling_mode: ScalingMode::FixedVertical {
167 viewport_height: 6.0,
168 },
169 ..OrthographicProjection::default_3d()
170 }),
171 Camera {
172 sub_camera_view: Some(SubCameraView {
173 full_size: UVec2::new(2, 2),
174 offset: Vec2::ZERO,
175 size: UVec2::new(1, 2),
176 }),
177 order: 5,
178 ..default()
179 },
180 ExampleViewports::OrthographicStretched,
181 transform,
182 ));
183
184 commands.spawn((
192 Camera3d::default(),
193 Projection::from(OrthographicProjection {
194 scaling_mode: ScalingMode::FixedVertical {
195 viewport_height: 6.0,
196 },
197 ..OrthographicProjection::default_3d()
198 }),
199 Camera {
200 sub_camera_view: Some(SubCameraView {
201 full_size: UVec2::new(500, 500),
202 offset: Vec2::ZERO,
203 size: UVec2::new(100, 100),
204 }),
205 order: 6,
206 ..default()
207 },
208 transform,
209 ExampleViewports::OrthographicMoving,
210 MovingCameraMarker,
211 ));
212
213 commands.spawn((
221 Camera3d::default(),
222 Projection::from(OrthographicProjection {
223 scaling_mode: ScalingMode::FixedVertical {
224 viewport_height: 6.0,
225 },
226 ..OrthographicProjection::default_3d()
227 }),
228 Camera {
229 sub_camera_view: Some(SubCameraView {
230 full_size: UVec2::new(200, 200),
231 offset: Vec2::ZERO,
232 size: UVec2::new(200, 100),
233 }),
234 order: 7,
235 ..default()
236 },
237 ExampleViewports::OrthographicControl,
238 transform,
239 ));
240}
241
242fn move_camera_view(
243 mut movable_camera_query: Query<&mut Camera, With<MovingCameraMarker>>,
244 time: Res<Time>,
245) {
246 for mut camera in movable_camera_query.iter_mut() {
247 if let Some(sub_view) = &mut camera.sub_camera_view {
248 sub_view.offset.x = (time.elapsed_secs() * 150.) % 450.0 - 50.0;
249 sub_view.offset.y = sub_view.offset.x;
250 }
251 }
252}
253
254fn resize_viewports(
256 window: Single<&Window, With<bevy::window::PrimaryWindow>>,
257 mut viewports: Query<(&mut Camera, &ExampleViewports)>,
258) {
259 let window_size = window.physical_size();
260
261 let small_height = window_size.y / 5;
262 let small_width = window_size.x / 8;
263
264 let large_height = small_height * 4;
265 let large_width = small_width * 4;
266
267 let large_size = UVec2::new(large_width, large_height);
268
269 let small_dim = small_height.min(small_width);
272 let small_size = UVec2::new(small_dim, small_dim);
273
274 let small_wide_size = UVec2::new(small_dim * 2, small_dim);
275
276 for (mut camera, example_viewport) in viewports.iter_mut() {
277 if camera.viewport.is_none() {
278 camera.viewport = Some(Viewport::default());
279 };
280
281 let Some(viewport) = &mut camera.viewport else {
282 continue;
283 };
284
285 let (size, position) = match example_viewport {
286 ExampleViewports::PerspectiveMain => (large_size, UVec2::new(0, small_height)),
287 ExampleViewports::PerspectiveStretched => (small_size, UVec2::ZERO),
288 ExampleViewports::PerspectiveMoving => (small_size, UVec2::new(small_width, 0)),
289 ExampleViewports::PerspectiveControl => {
290 (small_wide_size, UVec2::new(small_width * 2, 0))
291 }
292 ExampleViewports::OrthographicMain => {
293 (large_size, UVec2::new(large_width, small_height))
294 }
295 ExampleViewports::OrthographicStretched => (small_size, UVec2::new(small_width * 4, 0)),
296 ExampleViewports::OrthographicMoving => (small_size, UVec2::new(small_width * 5, 0)),
297 ExampleViewports::OrthographicControl => {
298 (small_wide_size, UVec2::new(small_width * 6, 0))
299 }
300 };
301
302 viewport.physical_size = size;
303 viewport.physical_position = position;
304 }
305}
306
307#[derive(Component)]
308enum ExampleViewports {
309 PerspectiveMain,
310 PerspectiveStretched,
311 PerspectiveMoving,
312 PerspectiveControl,
313 OrthographicMain,
314 OrthographicStretched,
315 OrthographicMoving,
316 OrthographicControl,
317}