Skip to content

Commit 4e20ec0

Browse files
committed
Add viewport example.
1 parent 34a378b commit 4e20ec0

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,10 @@ path = "examples/window/multiple_windows.rs"
373373
name = "scale_factor_override"
374374
path = "examples/window/scale_factor_override.rs"
375375

376+
[[example]]
377+
name = "viewports"
378+
path = "examples/window/viewports.rs"
379+
376380
[[example]]
377381
name = "window_settings"
378382
path = "examples/window/window_settings.rs"

examples/window/viewports.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
use bevy::{
2+
math::clamp,
3+
prelude::*,
4+
render::{
5+
camera::{ActiveCameras, Camera, Viewport, ViewportSideLocation},
6+
render_graph::{base::MainPass, CameraNode, PassNode, RenderGraph},
7+
},
8+
};
9+
10+
/// This example creates a second window and draws a mesh from two different cameras.
11+
fn main() {
12+
App::build()
13+
.insert_resource(Msaa { samples: 4 })
14+
.init_resource::<ViewportLayout>()
15+
.add_plugins(DefaultPlugins)
16+
.add_startup_system(setup.system())
17+
.add_system(viewport_layout_system.system())
18+
.run();
19+
}
20+
21+
fn setup(
22+
commands: &mut Commands,
23+
mut active_cameras: ResMut<ActiveCameras>,
24+
mut render_graph: ResMut<RenderGraph>,
25+
asset_server: Res<AssetServer>,
26+
) {
27+
// add new camera nodes for the secondary viewports
28+
render_graph.add_system_node("top_right_camera", CameraNode::new("TopRight"));
29+
render_graph.add_system_node("bottom_right_camera", CameraNode::new("BottomRight"));
30+
active_cameras.add("TopRight");
31+
active_cameras.add("BottomRight");
32+
33+
// add the cameras to the main pass
34+
{
35+
let main_pass: &mut PassNode<&MainPass> = render_graph.get_node_mut("main_pass").unwrap();
36+
main_pass.add_camera("TopRight");
37+
main_pass.add_camera("BottomRight");
38+
}
39+
render_graph
40+
.add_node_edge("top_right_camera", "main_pass")
41+
.unwrap();
42+
render_graph
43+
.add_node_edge("bottom_right_camera", "main_pass")
44+
.unwrap();
45+
46+
// SETUP SCENE
47+
48+
// add entities to the world
49+
commands
50+
//.spawn_scene(asset_server.load("models/monkey/Monkey.gltf#Scene0"))
51+
.spawn_scene(asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"))
52+
// light
53+
.spawn(LightBundle {
54+
transform: Transform::from_xyz(4.0, 5.0, 4.0),
55+
..Default::default()
56+
})
57+
// main camera
58+
.spawn(PerspectiveCameraBundle {
59+
// the following is an example of how to setup static viewports
60+
// and isn't really necessary in this case, as it will be
61+
// immediately overwritten by the viewport_layout_system
62+
viewport: Viewport {
63+
sides: Rect {
64+
// occupy the left 50% of the available horizontal space
65+
left: ViewportSideLocation::Relative(0.0),
66+
right: ViewportSideLocation::Relative(0.5),
67+
// occupy the left 100% of the available vertical space
68+
top: ViewportSideLocation::Relative(0.0),
69+
bottom: ViewportSideLocation::Relative(1.0),
70+
},
71+
..Default::default()
72+
},
73+
transform: Transform::from_xyz(-1.0, 1.0, 1.0)
74+
.looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::unit_y()),
75+
..Default::default()
76+
})
77+
// top right camera
78+
.spawn(PerspectiveCameraBundle {
79+
camera: Camera {
80+
name: Some("TopRight".to_string()),
81+
..Default::default()
82+
},
83+
transform: Transform::from_xyz(0.0, 0.3, 1.3)
84+
.looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::unit_y()),
85+
..Default::default()
86+
})
87+
// bottom right camera
88+
.spawn(PerspectiveCameraBundle {
89+
camera: Camera {
90+
name: Some("BottomRight".to_string()),
91+
..Default::default()
92+
},
93+
transform: Transform::from_xyz(-1.3, 0.3, 0.0)
94+
.looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::unit_y()),
95+
..Default::default()
96+
});
97+
98+
// ui
99+
let instructions_text = "use the arrow keys to resize the viewports";
100+
commands
101+
.spawn(UiCameraBundle {
102+
// viewports occupy the entire surface by default, and can overlap each other
103+
..Default::default()
104+
})
105+
.spawn(TextBundle {
106+
style: Style {
107+
align_self: AlignSelf::FlexEnd,
108+
..Default::default()
109+
},
110+
text: Text::with_section(
111+
instructions_text,
112+
TextStyle {
113+
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
114+
font_size: 30.0,
115+
color: Color::WHITE,
116+
},
117+
Default::default(),
118+
),
119+
..Default::default()
120+
});
121+
}
122+
123+
struct ViewportLayout {
124+
divide_x: f32,
125+
divide_y: f32,
126+
}
127+
128+
impl Default for ViewportLayout {
129+
fn default() -> Self {
130+
Self {
131+
divide_x: 0.5,
132+
divide_y: 0.5,
133+
}
134+
}
135+
}
136+
137+
fn viewport_layout_system(
138+
keyboard_input: Res<Input<KeyCode>>,
139+
mut layout: ResMut<ViewportLayout>,
140+
mut query: Query<(&Camera, &mut Viewport)>,
141+
) {
142+
// update the layout state
143+
if keyboard_input.just_pressed(KeyCode::Left) {
144+
layout.divide_x -= 0.05;
145+
}
146+
if keyboard_input.just_pressed(KeyCode::Right) {
147+
layout.divide_x += 0.05;
148+
}
149+
if keyboard_input.just_pressed(KeyCode::Up) {
150+
layout.divide_y -= 0.05;
151+
}
152+
if keyboard_input.just_pressed(KeyCode::Down) {
153+
layout.divide_y += 0.05;
154+
}
155+
layout.divide_x = clamp(layout.divide_x, 0.05, 0.95);
156+
layout.divide_y = clamp(layout.divide_y, 0.05, 0.95);
157+
158+
// resize the viewports
159+
for (camera, mut viewport) in query.iter_mut() {
160+
match camera.name.as_deref() {
161+
// default camera
162+
Some("Camera3d") => {
163+
viewport.sides.right = ViewportSideLocation::Relative(layout.divide_x);
164+
}
165+
Some("TopRight") => {
166+
viewport.sides.left = ViewportSideLocation::Relative(layout.divide_x);
167+
viewport.sides.bottom = ViewportSideLocation::Relative(layout.divide_y);
168+
}
169+
Some("BottomRight") => {
170+
viewport.sides.left = ViewportSideLocation::Relative(layout.divide_x);
171+
viewport.sides.top = ViewportSideLocation::Relative(layout.divide_y);
172+
}
173+
_ => {}
174+
}
175+
}
176+
}

0 commit comments

Comments
 (0)