 bbb9849506
			
		
	
	
		bbb9849506
		
	
	
	
	
		
			
			it's a followup of #1550 I think calling explicit methods/values instead of default makes the code easier to read: "what is `Quat::default()`" vs "Oh, it's `Quat::IDENTITY`" `Transform::identity()` and `GlobalTransform::identity()` can also be consts and I replaced the calls to their `default()` impl with `identity()`
		
			
				
	
	
		
			207 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| 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()
 | |
|         .insert_resource(Msaa { samples: 4 })
 | |
|         .insert_resource(State::new(AppState::CreateWindow))
 | |
|         .add_plugins(DefaultPlugins)
 | |
|         .add_stage_after(CoreStage::Update, Stage, StateStage::<AppState>::default())
 | |
|         .on_state_update(Stage, AppState::CreateWindow, setup_window.system())
 | |
|         .on_state_enter(Stage, AppState::Setup, setup_pipeline.system())
 | |
|         .run();
 | |
| }
 | |
| 
 | |
| #[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)]
 | |
| pub struct Stage;
 | |
| 
 | |
| // NOTE: this "state based" approach to multiple windows is a short term workaround.
 | |
| // Future Bevy releases shouldn't require such a strict order of operations.
 | |
| #[derive(Clone)]
 | |
| enum AppState {
 | |
|     CreateWindow,
 | |
|     Setup,
 | |
| }
 | |
| 
 | |
| fn setup_window(
 | |
|     mut app_state: ResMut<State<AppState>>,
 | |
|     mut create_window_events: EventWriter<CreateWindow>,
 | |
| ) {
 | |
|     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()
 | |
|         },
 | |
|     });
 | |
| 
 | |
|     app_state.set_next(AppState::Setup).unwrap();
 | |
| }
 | |
| 
 | |
| fn setup_pipeline(
 | |
|     mut commands: Commands,
 | |
|     windows: Res<Windows>,
 | |
|     mut active_cameras: ResMut<ActiveCameras>,
 | |
|     mut render_graph: ResMut<RenderGraph>,
 | |
|     asset_server: Res<AssetServer>,
 | |
|     msaa: Res<Msaa>,
 | |
| ) {
 | |
|     // get the non-default window id
 | |
|     let window_id = windows
 | |
|         .iter()
 | |
|         .find(|w| w.id() != WindowId::default())
 | |
|         .map(|w| w.id())
 | |
|         .unwrap();
 | |
| 
 | |
|     // 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#Scene0"))
 | |
|         // light
 | |
|         .spawn(LightBundle {
 | |
|             transform: Transform::from_xyz(4.0, 5.0, 4.0),
 | |
|             ..Default::default()
 | |
|         })
 | |
|         // main camera
 | |
|         .spawn(PerspectiveCameraBundle {
 | |
|             transform: Transform::from_xyz(0.0, 0.0, 6.0).looking_at(Vec3::ZERO, Vec3::Y),
 | |
|             ..Default::default()
 | |
|         })
 | |
|         // second window camera
 | |
|         .spawn(PerspectiveCameraBundle {
 | |
|             camera: Camera {
 | |
|                 name: Some("Secondary".to_string()),
 | |
|                 window: window_id,
 | |
|                 ..Default::default()
 | |
|             },
 | |
|             transform: Transform::from_xyz(6.0, 0.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y),
 | |
|             ..Default::default()
 | |
|         });
 | |
| }
 |