mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 22:20:20 +00:00
70b0eacc3b
# Objective - Custom render passes, or future passes in the engine (such as https://github.com/bevyengine/bevy/pull/10164) need a better way to know and indicate to the core passes whether the view color/depth/prepass attachments have been cleared or not yet this frame, to know if they should clear it themselves or load it. ## Solution - For all render targets (depth textures, shadow textures, prepass textures, main textures) use an atomic bool to track whether or not each texture has been cleared this frame. Abstracted away in the new ColorAttachment and DepthAttachment wrappers. --- ## Changelog - Changed `ViewTarget::get_color_attachment()`, removed arguments. - Changed `ViewTarget::get_unsampled_color_attachment()`, removed arguments. - Removed `Camera3d::clear_color`. - Removed `Camera2d::clear_color`. - Added `Camera::clear_color`. - Added `ExtractedCamera::clear_color`. - Added `ColorAttachment` and `DepthAttachment` wrappers. - Moved `ClearColor` and `ClearColorConfig` from `bevy::core_pipeline::clear_color` to `bevy::render::camera`. - Core render passes now track when a texture is first bound as an attachment in order to decide whether to clear or load it. ## Migration Guide - Remove arguments to `ViewTarget::get_color_attachment()` and `ViewTarget::get_unsampled_color_attachment()`. - Configure clear color on `Camera` instead of on `Camera3d` and `Camera2d`. - Moved `ClearColor` and `ClearColorConfig` from `bevy::core_pipeline::clear_color` to `bevy::render::camera`. - `ViewDepthTexture` must now be created via the `new()` method --------- Co-authored-by: vero <email@atlasdostal.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
116 lines
3.6 KiB
Rust
116 lines
3.6 KiB
Rust
//! Renders two cameras to the same window to accomplish "split screen".
|
|
|
|
use std::f32::consts::PI;
|
|
|
|
use bevy::{
|
|
pbr::CascadeShadowConfigBuilder, prelude::*, render::camera::Viewport, window::WindowResized,
|
|
};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.add_systems(Startup, setup)
|
|
.add_systems(Update, set_camera_viewports)
|
|
.run();
|
|
}
|
|
|
|
/// set up a simple 3D scene
|
|
fn setup(
|
|
mut commands: Commands,
|
|
asset_server: Res<AssetServer>,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
) {
|
|
// plane
|
|
commands.spawn(PbrBundle {
|
|
mesh: meshes.add(shape::Plane::from_size(100.0).into()),
|
|
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
|
..default()
|
|
});
|
|
|
|
commands.spawn(SceneBundle {
|
|
scene: asset_server.load("models/animated/Fox.glb#Scene0"),
|
|
..default()
|
|
});
|
|
|
|
// Light
|
|
commands.spawn(DirectionalLightBundle {
|
|
transform: Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)),
|
|
directional_light: DirectionalLight {
|
|
shadows_enabled: true,
|
|
..default()
|
|
},
|
|
cascade_shadow_config: CascadeShadowConfigBuilder {
|
|
num_cascades: 2,
|
|
first_cascade_far_bound: 200.0,
|
|
maximum_distance: 280.0,
|
|
..default()
|
|
}
|
|
.into(),
|
|
..default()
|
|
});
|
|
|
|
// Left Camera
|
|
commands.spawn((
|
|
Camera3dBundle {
|
|
transform: Transform::from_xyz(0.0, 200.0, -100.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
..default()
|
|
},
|
|
LeftCamera,
|
|
));
|
|
|
|
// Right Camera
|
|
commands.spawn((
|
|
Camera3dBundle {
|
|
transform: Transform::from_xyz(100.0, 100., 150.0).looking_at(Vec3::ZERO, Vec3::Y),
|
|
camera: Camera {
|
|
// Renders the right camera after the left camera, which has a default priority of 0
|
|
order: 1,
|
|
// Don't clear on the second camera because the first camera already cleared the window
|
|
clear_color: ClearColorConfig::None,
|
|
..default()
|
|
},
|
|
..default()
|
|
},
|
|
RightCamera,
|
|
));
|
|
}
|
|
|
|
#[derive(Component)]
|
|
struct LeftCamera;
|
|
|
|
#[derive(Component)]
|
|
struct RightCamera;
|
|
|
|
fn set_camera_viewports(
|
|
windows: Query<&Window>,
|
|
mut resize_events: EventReader<WindowResized>,
|
|
mut left_camera: Query<&mut Camera, (With<LeftCamera>, Without<RightCamera>)>,
|
|
mut right_camera: Query<&mut Camera, With<RightCamera>>,
|
|
) {
|
|
// We need to dynamically resize the camera's viewports whenever the window size changes
|
|
// so then each camera always takes up half the screen.
|
|
// A resize_event is sent when the window is first created, allowing us to reuse this system for initial setup.
|
|
for resize_event in resize_events.read() {
|
|
let window = windows.get(resize_event.window).unwrap();
|
|
let mut left_camera = left_camera.single_mut();
|
|
left_camera.viewport = Some(Viewport {
|
|
physical_position: UVec2::new(0, 0),
|
|
physical_size: UVec2::new(
|
|
window.resolution.physical_width() / 2,
|
|
window.resolution.physical_height(),
|
|
),
|
|
..default()
|
|
});
|
|
|
|
let mut right_camera = right_camera.single_mut();
|
|
right_camera.viewport = Some(Viewport {
|
|
physical_position: UVec2::new(window.resolution.physical_width() / 2, 0),
|
|
physical_size: UVec2::new(
|
|
window.resolution.physical_width() / 2,
|
|
window.resolution.physical_height(),
|
|
),
|
|
..default()
|
|
});
|
|
}
|
|
}
|