use bevy::{ prelude::*, render::{ camera::{ActiveCameras, Camera}, pass::*, render_graph::{ base::MainPass, CameraNode, PassNode, RenderGraph, WindowSwapChainNode, WindowTextureNode, }, texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage}, }, window::{CreateWindow, WindowDescriptor, WindowId}, }; /// This example creates a second window and draws a mesh from two different cameras. fn main() { App::build() .add_resource(Msaa { samples: 4 }) .add_default_plugins() .add_startup_system(setup.system()) .run(); } fn setup( mut commands: Commands, mut create_window_events: ResMut>, mut active_cameras: ResMut, mut render_graph: ResMut, asset_server: Res, msaa: Res, ) { let window_id = WindowId::new(); // sends out a "CreateWindow" event, which will be received by the windowing backend create_window_events.send(CreateWindow { id: window_id, descriptor: WindowDescriptor { width: 800, height: 600, vsync: false, title: "second window".to_string(), ..Default::default() }, }); // here we setup our render graph to draw our second camera to the new window's swap chain // add a swapchain node for our new window render_graph.add_node( "second_window_swap_chain", WindowSwapChainNode::new(window_id), ); // add a new depth texture node for our new window render_graph.add_node( "second_window_depth_texture", WindowTextureNode::new( window_id, TextureDescriptor { format: TextureFormat::Depth32Float, usage: TextureUsage::OUTPUT_ATTACHMENT, sample_count: msaa.samples, ..Default::default() }, ), ); // add a new camera node for our new window render_graph.add_system_node("secondary_camera", CameraNode::new("Secondary")); // add a new render pass for our new window / camera let mut second_window_pass = PassNode::<&MainPass>::new(PassDescriptor { color_attachments: vec![msaa.color_attachment_descriptor( TextureAttachment::Input("color_attachment".to_string()), TextureAttachment::Input("color_resolve_target".to_string()), Operations { load: LoadOp::Clear(Color::rgb(0.5, 0.5, 0.8)), store: true, }, )], depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor { attachment: TextureAttachment::Input("depth".to_string()), depth_ops: Some(Operations { load: LoadOp::Clear(1.0), store: true, }), stencil_ops: None, }), sample_count: msaa.samples, }); second_window_pass.add_camera("Secondary"); active_cameras.add("Secondary"); render_graph.add_node("second_window_pass", second_window_pass); render_graph .add_slot_edge( "second_window_swap_chain", WindowSwapChainNode::OUT_TEXTURE, "second_window_pass", if msaa.samples > 1 { "color_resolve_target" } else { "color_attachment" }, ) .unwrap(); render_graph .add_slot_edge( "second_window_depth_texture", WindowTextureNode::OUT_TEXTURE, "second_window_pass", "depth", ) .unwrap(); render_graph .add_node_edge("secondary_camera", "second_window_pass") .unwrap(); if msaa.samples > 1 { render_graph.add_node( "second_multi_sampled_color_attachment", WindowTextureNode::new( window_id, TextureDescriptor { size: Extent3d { depth: 1, width: 1, height: 1, }, mip_level_count: 1, sample_count: msaa.samples, dimension: TextureDimension::D2, format: TextureFormat::default(), usage: TextureUsage::OUTPUT_ATTACHMENT, }, ), ); render_graph .add_slot_edge( "second_multi_sampled_color_attachment", WindowSwapChainNode::OUT_TEXTURE, "second_window_pass", "color_attachment", ) .unwrap(); } // SETUP SCENE // add entities to the world commands .spawn_scene(asset_server.load("models/monkey/Monkey.gltf")) // light .spawn(LightComponents { transform: Transform::from_translation(Vec3::new(4.0, 5.0, 4.0)), ..Default::default() }) // main camera .spawn(Camera3dComponents { transform: Transform::from_translation(Vec3::new(0.0, 0.0, 6.0)) .looking_at(Vec3::default(), Vec3::unit_y()), ..Default::default() }) // second window camera .spawn(Camera3dComponents { camera: Camera { name: Some("Secondary".to_string()), window: window_id, ..Default::default() }, transform: Transform::from_translation(Vec3::new(6.0, 0.0, 0.0)) .looking_at(Vec3::default(), Vec3::unit_y()), ..Default::default() }); }