render: multi-window cameras ready to go!

passes now bind camera buffers and cameras can now be assigned non-primary windows
This commit is contained in:
Carter Anderson 2020-06-25 23:04:08 -07:00
parent ca4726ea7d
commit 69925f0817
18 changed files with 239 additions and 160 deletions

View file

@ -29,12 +29,12 @@ impl Default for MeshComponents {
dynamic_bindings: vec![
// Transform
DynamicBinding {
bind_group: 1,
bind_group: 2,
binding: 0,
},
// StandardMaterial_albedo
DynamicBinding {
bind_group: 2,
bind_group: 3,
binding: 0,
},
],

View file

@ -18,18 +18,18 @@ layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 0, binding = 1) uniform Lights {
layout(set = 1, binding = 0) uniform Lights {
uvec4 NumLights;
Light SceneLights[MAX_LIGHTS];
};
layout(set = 2, binding = 0) uniform StandardMaterial_albedo {
layout(set = 3, binding = 0) uniform StandardMaterial_albedo {
vec4 Albedo;
};
# ifdef STANDARDMATERIAL_ALBEDO_TEXTURE
layout(set = 3, binding = 0) uniform texture2D StandardMaterial_albedo_texture;
layout(set = 3, binding = 1) uniform sampler StandardMaterial_albedo_texture_sampler;
layout(set = 3, binding = 1) uniform texture2D StandardMaterial_albedo_texture;
layout(set = 3, binding = 2) uniform sampler StandardMaterial_albedo_texture_sampler;
# endif
void main() {

View file

@ -12,7 +12,7 @@ layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
layout(set = 1, binding = 0) uniform Transform {
layout(set = 2, binding = 0) uniform Transform {
mat4 Model;
};

View file

@ -26,7 +26,7 @@ pub struct BaseRenderGraphConfig {
pub mod node {
pub const PRIMARY_SWAP_CHAIN: &str = "swapchain";
pub const CAMERA: &str = "camera";
pub const CAMERA3D: &str = "camera3d";
pub const CAMERA2D: &str = "camera2d";
pub const TEXTURE_COPY: &str = "texture_copy";
pub const MAIN_DEPTH_TEXTURE: &str = "main_pass_depth_texture";
@ -35,7 +35,7 @@ pub mod node {
}
pub mod camera {
pub const CAMERA: &str = "Camera";
pub const CAMERA3D: &str = "Camera3d";
pub const CAMERA2D: &str = "Camera2d";
}
@ -62,7 +62,7 @@ impl BaseRenderGraphBuilder for RenderGraph {
fn add_base_graph(&mut self, config: &BaseRenderGraphConfig) -> &mut Self {
self.add_node(node::TEXTURE_COPY, TextureCopyNode::default());
if config.add_3d_camera {
self.add_system_node(node::CAMERA, CameraNode::new(camera::CAMERA));
self.add_system_node(node::CAMERA3D, CameraNode::new(camera::CAMERA3D));
}
if config.add_2d_camera {
@ -117,7 +117,7 @@ impl BaseRenderGraphBuilder for RenderGraph {
main_pass_node.use_default_clear_color(0);
if config.add_3d_camera {
main_pass_node.add_camera(camera::CAMERA);
main_pass_node.add_camera(camera::CAMERA3D);
}
if config.add_2d_camera {
@ -135,7 +135,7 @@ impl BaseRenderGraphBuilder for RenderGraph {
.unwrap();
if config.add_3d_camera {
self.add_node_edge(node::CAMERA, node::MAIN_PASS).unwrap();
self.add_node_edge(node::CAMERA3D, node::MAIN_PASS).unwrap();
}
if config.add_2d_camera {

View file

@ -1,7 +1,7 @@
use crate::CameraProjection;
use bevy_app::{EventReader, Events};
use bevy_property::Properties;
use bevy_window::{WindowCreated, WindowResized, Windows};
use bevy_window::{WindowCreated, WindowReference, WindowResized, Windows};
use glam::Mat4;
use legion::{prelude::*, storage::Component};
@ -9,6 +9,8 @@ use legion::{prelude::*, storage::Component};
pub struct Camera {
pub projection_matrix: Mat4,
pub name: Option<String>,
#[property(ignore)]
pub window: WindowReference,
}
pub fn camera_system<T: CameraProjection + Component>() -> Box<dyn Schedulable> {
@ -19,27 +21,58 @@ pub fn camera_system<T: CameraProjection + Component>() -> Box<dyn Schedulable>
window_created_events: Res<Events<WindowCreated>>,
windows: Res<Windows>,
query: &mut Query<(Write<Camera>, Write<T>)>| {
let primary_window_resized_event = window_resized_event_reader
.find_latest(&window_resized_events, |event| event.is_primary);
for event in window_created_event_reader.iter(&window_created_events) {
if !event.is_primary {
let mut changed_window_ids = Vec::new();
let mut changed_primary_window_id = None;
// handle resize events. latest events are handled first because we only want to resize each window once
for event in window_resized_event_reader
.iter(&window_resized_events)
.rev()
{
if changed_window_ids.contains(&event.id) {
continue;
}
if let Some(window) = windows.get(event.id) {
for (mut camera, mut camera_projection) in query.iter_mut(world) {
camera_projection.update(window.width as usize, window.height as usize);
camera.projection_matrix = camera_projection.get_projection_matrix();
}
if event.is_primary {
changed_primary_window_id = Some(event.id);
} else {
changed_window_ids.push(event.id);
}
}
if let Some(primary_window_resized_event) = primary_window_resized_event {
for (mut camera, mut camera_projection) in query.iter_mut(world) {
camera_projection.update(
primary_window_resized_event.width,
primary_window_resized_event.height,
);
// handle resize events. latest events are handled first because we only want to resize each window once
for event in window_created_event_reader
.iter(&window_created_events)
.rev()
{
if changed_window_ids.contains(&event.id) {
continue;
}
if event.is_primary {
changed_primary_window_id = Some(event.id);
} else {
changed_window_ids.push(event.id);
}
}
for (mut camera, mut camera_projection) in query.iter_mut(world) {
if let Some(window) = match camera.window {
WindowReference::Id(id) => {
if changed_window_ids.contains(&id) {
windows.get(id)
} else {
None
}
}
WindowReference::Primary => {
if let Some(id) = changed_primary_window_id {
windows.get(id)
} else {
None
}
}
} {
camera_projection.update(window.width as usize, window.height as usize);
camera.projection_matrix = camera_projection.get_projection_matrix();
}
}

View file

@ -33,7 +33,7 @@ impl Default for PerspectiveCameraComponents {
fn default() -> Self {
PerspectiveCameraComponents {
camera: Camera {
name: Some(base_render_graph::camera::CAMERA.to_string()),
name: Some(base_render_graph::camera::CAMERA3D.to_string()),
..Default::default()
},
perspective_projection: Default::default(),

View file

@ -132,7 +132,7 @@ impl AppPlugin for RenderPlugin {
render_graph.add_base_graph(config);
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
if config.add_3d_camera {
active_cameras.add(base_render_graph::camera::CAMERA);
active_cameras.add(base_render_graph::camera::CAMERA3D);
}
if config.add_2d_camera {

View file

@ -40,7 +40,7 @@ impl BindType {
match self {
BindType::Uniform { properties, .. } => {
Some(properties.iter().fold(0, |total, property| {
total + property.property_type.get_size()
total + property.get_size()
}))
}
_ => None,

View file

@ -85,14 +85,7 @@ impl PipelineLayout {
}
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct UniformProperty {
pub name: String,
pub property_type: UniformPropertyType,
}
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum UniformPropertyType {
// TODO: Use VertexFormat here
pub enum UniformProperty {
UInt,
Int,
IVec2,
@ -104,27 +97,27 @@ pub enum UniformPropertyType {
Mat3,
Mat4,
Struct(Vec<UniformProperty>),
Array(Box<UniformPropertyType>, usize),
Array(Box<UniformProperty>, usize),
}
impl UniformPropertyType {
impl UniformProperty {
pub fn get_size(&self) -> u64 {
match self {
UniformPropertyType::UInt => 4,
UniformPropertyType::Int => 4,
UniformPropertyType::IVec2 => 4 * 2,
UniformPropertyType::Float => 4,
UniformPropertyType::UVec4 => 4 * 4,
UniformPropertyType::Vec2 => 4 * 2,
UniformPropertyType::Vec3 => 4 * 3,
UniformPropertyType::Vec4 => 4 * 4,
UniformPropertyType::Mat3 => 4 * 4 * 3,
UniformPropertyType::Mat4 => 4 * 4 * 4,
UniformPropertyType::Struct(properties) => properties
UniformProperty::UInt => 4,
UniformProperty::Int => 4,
UniformProperty::IVec2 => 4 * 2,
UniformProperty::Float => 4,
UniformProperty::UVec4 => 4 * 4,
UniformProperty::Vec2 => 4 * 2,
UniformProperty::Vec3 => 4 * 3,
UniformProperty::Vec4 => 4 * 4,
UniformProperty::Mat3 => 4 * 4 * 3,
UniformProperty::Mat4 => 4 * 4 * 4,
UniformProperty::Struct(properties) => properties
.iter()
.map(|p| p.property_type.get_size())
.map(|p| p.get_size())
.fold(0, |total, size| total + size),
UniformPropertyType::Array(property, length) => property.get_size() * *length as u64,
UniformProperty::Array(property, length) => property.get_size() * *length as u64,
}
}
}

View file

@ -1,21 +1,32 @@
use crate::{
draw::{Draw, RenderCommand},
pass::{PassDescriptor, TextureAttachment, ClearColor},
pipeline::PipelineDescriptor,
pass::{ClearColor, PassDescriptor, TextureAttachment},
pipeline::{
BindGroupDescriptor, BindType, BindingDescriptor, PipelineDescriptor, UniformProperty,
},
render_graph::{Node, ResourceSlotInfo, ResourceSlots},
render_resource::{BindGroupId, BufferId, RenderResourceBindings, RenderResourceType},
renderer::RenderContext, ActiveCameras, VisibleEntities,
render_resource::{
BindGroup, BindGroupId, BufferId, RenderResourceBindings, RenderResourceType,
},
renderer::RenderContext,
ActiveCameras, VisibleEntities,
};
use bevy_asset::{Assets, Handle};
use legion::prelude::*;
struct CameraInfo {
name: String,
bind_group_id: Option<BindGroupId>,
}
pub struct PassNode {
descriptor: PassDescriptor,
inputs: Vec<ResourceSlotInfo>,
cameras: Vec<String>,
cameras: Vec<CameraInfo>,
color_attachment_input_indices: Vec<Option<usize>>,
depth_stencil_attachment_input_index: Option<usize>,
default_clear_color_inputs: Vec<usize>,
camera_bind_group_descriptor: BindGroupDescriptor,
}
impl PassNode {
@ -45,6 +56,18 @@ impl PassNode {
}
}
let camera_bind_group_descriptor = BindGroupDescriptor::new(
0,
vec![BindingDescriptor {
name: "Camera".to_string(),
index: 0,
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![UniformProperty::Struct(vec![UniformProperty::Mat4])],
},
}],
);
PassNode {
descriptor,
inputs,
@ -52,11 +75,15 @@ impl PassNode {
color_attachment_input_indices,
depth_stencil_attachment_input_index,
default_clear_color_inputs: Vec::new(),
camera_bind_group_descriptor,
}
}
pub fn add_camera(&mut self, camera_name: &str) {
self.cameras.push(camera_name.to_string());
self.cameras.push(CameraInfo {
name: camera_name.to_string(),
bind_group_id: None,
});
}
pub fn use_default_clear_color(&mut self, color_attachment_index: usize) {
@ -79,12 +106,12 @@ impl Node for PassNode {
) {
let render_resource_bindings = resources.get::<RenderResourceBindings>().unwrap();
let pipelines = resources.get::<Assets<PipelineDescriptor>>().unwrap();
let active_cameras= resources.get::<ActiveCameras>().unwrap();
let active_cameras = resources.get::<ActiveCameras>().unwrap();
for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() {
if self.default_clear_color_inputs.contains(&i) {
if let Some(default_clear_color) = resources.get::<ClearColor>() {
color_attachment.clear_color = default_clear_color.color;
color_attachment.clear_color = default_clear_color.color;
}
}
if let Some(input_index) = self.color_attachment_input_indices[i] {
@ -101,18 +128,40 @@ impl Node for PassNode {
.attachment =
TextureAttachment::Id(input.get(input_index).unwrap().get_texture().unwrap());
}
for camera_info in self.cameras.iter_mut() {
let camera_binding =
if let Some(camera_binding) = render_resource_bindings.get(&camera_info.name) {
camera_binding.clone()
} else {
continue;
};
let camera_bind_group = BindGroup::build().add_binding(0, camera_binding).finish();
render_context
.resources()
.create_bind_group(self.camera_bind_group_descriptor.id, &camera_bind_group);
camera_info.bind_group_id = Some(camera_bind_group.id);
}
render_context.begin_pass(
&self.descriptor,
&render_resource_bindings,
&mut |render_pass| {
for camera_name in self.cameras.iter() {
let visible_entities = if let Some(camera_entity) = active_cameras.get(camera_name) {
for camera_info in self.cameras.iter() {
let camera_bind_group_id= if let Some(bind_group_id) = camera_info.bind_group_id {
bind_group_id
} else {
continue;
};
// get an ordered list of entities visible to the camera
let visible_entities = if let Some(camera_entity) = active_cameras.get(&camera_info.name) {
world.get_component::<VisibleEntities>(camera_entity).unwrap()
} else {
continue;
};
// attempt to draw each visible entity
let mut draw_state = DrawState::default();
for visible_entity in visible_entities.iter() {
let draw = if let Some(draw) = world.get_component::<Draw>(visible_entity.entity) {
@ -124,7 +173,8 @@ impl Node for PassNode {
if !draw.is_visible {
continue;
}
// each Draw component contains an ordered list of render commands. we turn those into actual render commands here
for render_command in draw.render_commands.iter() {
match render_command {
RenderCommand::SetPipeline { pipeline } => {
@ -132,6 +182,20 @@ impl Node for PassNode {
render_pass.set_pipeline(*pipeline);
let descriptor = pipelines.get(pipeline).unwrap();
draw_state.set_pipeline(*pipeline, descriptor);
// try to set current camera bind group
let layout = descriptor.get_layout().unwrap();
if let Some(descriptor) = layout.get_bind_group(0) {
if *descriptor == self.camera_bind_group_descriptor {
draw_state.set_bind_group(0, camera_bind_group_id);
render_pass.set_bind_group(
0,
descriptor.id,
camera_bind_group_id,
None
);
}
}
}
RenderCommand::DrawIndexed {
base_vertex,

View file

@ -261,7 +261,7 @@ impl Default for RenderResourceBindingsId {
#[cfg(test)]
mod tests {
use super::*;
use crate::pipeline::{BindType, BindingDescriptor, UniformProperty, UniformPropertyType};
use crate::pipeline::{BindType, BindingDescriptor, UniformProperty};
#[test]
fn test_bind_groups() {
@ -273,13 +273,7 @@ mod tests {
name: "a".to_string(),
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![UniformProperty {
name: "A".to_string(),
property_type: UniformPropertyType::Struct(vec![UniformProperty {
name: "".to_string(),
property_type: UniformPropertyType::Mat4,
}]),
}],
properties: vec![UniformProperty::Struct(vec![UniformProperty::Mat4])],
},
},
BindingDescriptor {
@ -287,10 +281,7 @@ mod tests {
name: "b".to_string(),
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![UniformProperty {
name: "B".to_string(),
property_type: UniformPropertyType::Float,
}],
properties: vec![UniformProperty::Float],
},
},
],

View file

@ -1,7 +1,7 @@
use crate::{
pipeline::{
BindGroupDescriptor, BindType, BindingDescriptor, InputStepMode, UniformProperty,
UniformPropertyType, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat,
},
texture::{TextureComponentType, TextureViewDimension},
};
@ -214,31 +214,26 @@ enum NumberType {
}
fn reflect_uniform(type_description: &ReflectTypeDescription) -> UniformProperty {
let uniform_property_type = if type_description
if type_description
.type_flags
.contains(ReflectTypeFlags::STRUCT)
{
reflect_uniform_struct(type_description)
} else {
reflect_uniform_numeric(type_description)
};
UniformProperty {
name: type_description.type_name.to_string(),
property_type: uniform_property_type,
}
}
fn reflect_uniform_struct(type_description: &ReflectTypeDescription) -> UniformPropertyType {
fn reflect_uniform_struct(type_description: &ReflectTypeDescription) -> UniformProperty {
let mut properties = Vec::new();
for member in type_description.members.iter() {
properties.push(reflect_uniform(member));
}
UniformPropertyType::Struct(properties)
UniformProperty::Struct(properties)
}
fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> UniformPropertyType {
fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> UniformProperty {
let traits = &type_description.traits;
let number_type = if type_description.type_flags.contains(ReflectTypeFlags::INT) {
match traits.numeric.scalar.signedness {
@ -266,8 +261,8 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
traits.numeric.matrix.column_count,
traits.numeric.matrix.row_count,
) {
(NumberType::Float, 3, 3) => UniformPropertyType::Mat3,
(NumberType::Float, 4, 4) => UniformPropertyType::Mat4,
(NumberType::Float, 3, 3) => UniformProperty::Mat3,
(NumberType::Float, 4, 4) => UniformProperty::Mat4,
(number_type, column_count, row_count) => panic!(
"unexpected uniform property matrix format {:?} {}x{}",
number_type, column_count, row_count
@ -275,14 +270,14 @@ fn reflect_uniform_numeric(type_description: &ReflectTypeDescription) -> Uniform
}
} else {
match (number_type, traits.numeric.vector.component_count) {
(NumberType::UInt, 0) => UniformPropertyType::UInt,
(NumberType::Int, 0) => UniformPropertyType::Int,
(NumberType::Int, 2) => UniformPropertyType::IVec2,
(NumberType::Float, 0) => UniformPropertyType::Float,
(NumberType::Float, 2) => UniformPropertyType::Vec2,
(NumberType::Float, 3) => UniformPropertyType::Vec3,
(NumberType::Float, 4) => UniformPropertyType::Vec4,
(NumberType::UInt, 4) => UniformPropertyType::UVec4,
(NumberType::UInt, 0) => UniformProperty::UInt,
(NumberType::Int, 0) => UniformProperty::Int,
(NumberType::Int, 2) => UniformProperty::IVec2,
(NumberType::Float, 0) => UniformProperty::Float,
(NumberType::Float, 2) => UniformProperty::Vec2,
(NumberType::Float, 3) => UniformProperty::Vec3,
(NumberType::Float, 4) => UniformProperty::Vec4,
(NumberType::UInt, 4) => UniformProperty::UVec4,
(number_type, component_count) => panic!(
"unexpected uniform property format {:?} {}",
number_type, component_count
@ -414,15 +409,9 @@ mod tests {
name: "Camera".into(),
bind_type: BindType::Uniform {
dynamic: false,
properties: vec![UniformProperty {
name: "Camera".into(),
property_type: UniformPropertyType::Struct(vec![
UniformProperty {
name: "".into(),
property_type: UniformPropertyType::Mat4,
}
]),
}],
properties: vec![UniformProperty::Struct(vec![
UniformProperty::Mat4
])],
},
}]
),

View file

@ -6,7 +6,7 @@ layout(location = 2) in vec2 Vertex_Uv;
layout(location = 0) out vec2 v_Uv;
layout(set = 0, binding = 0) uniform Camera2d {
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};

View file

@ -7,16 +7,9 @@ layout(location = 2) in vec2 Vertex_Uv;
layout(location = 0) out vec2 v_Uv;
layout(location = 1) out vec4 v_Color;
// TODO: remove UI shader def and replace with generic "Camera" when its easier to manually bind global RenderResourceBindings
#ifdef UI_CAMERA
layout(set = 0, binding = 0) uniform UiCamera {
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};
# else
layout(set = 0, binding = 0) uniform Camera2d {
mat4 ViewProj;
};
#endif
// TODO: merge dimensions into "sprites" buffer when that is supported in the Uniforms derive abstraction
layout(set = 1, binding = 0) uniform TextureAtlas_size {

View file

@ -4,7 +4,7 @@ use bevy_asset::Assets;
use bevy_render::{
draw::{Draw, DrawContext, DrawError, Drawable},
mesh,
pipeline::{PipelineSpecialization, ShaderSpecialization},
pipeline::PipelineSpecialization,
render_resource::{
AssetRenderResourceBindings, BindGroup, BufferUsage, RenderResourceBindings,
RenderResourceId,
@ -13,7 +13,6 @@ use bevy_render::{
};
use bevy_sprite::{TextureAtlas, TextureAtlasSprite};
use glam::{Mat4, Vec3};
use std::collections::HashSet;
pub struct TextStyle {
pub font_size: f32,
@ -57,16 +56,11 @@ impl<'a> DrawableText<'a> {
impl<'a> Drawable for DrawableText<'a> {
fn draw(&mut self, draw: &mut Draw, context: &mut DrawContext) -> Result<(), DrawError> {
let mut shader_defs = HashSet::new();
shader_defs.insert("UI_CAMERA".to_string());
context.set_pipeline(
draw,
bevy_sprite::SPRITE_SHEET_PIPELINE_HANDLE,
// TODO: remove this shader def specialization when its easier to manually bind global render resources to specific bind groups
&PipelineSpecialization {
shader_specialization: ShaderSpecialization { shader_defs },
..Default::default()
},
&PipelineSpecialization::default(),
)?;
let render_resource_context = &**context.render_resource_context;
@ -151,10 +145,10 @@ impl<'a> Drawable for DrawableText<'a> {
.shared_buffers
.get_buffer(&sprite, BufferUsage::UNIFORM)
.unwrap();
let sprite_bind_group =
BindGroup::build()
.add_binding(0, transform_buffer)
.add_binding(1, sprite_buffer).finish();
let sprite_bind_group = BindGroup::build()
.add_binding(0, transform_buffer)
.add_binding(1, sprite_buffer)
.finish();
context.create_bind_group_resource(2, &sprite_bind_group)?;
draw.set_bind_group(2, &sprite_bind_group);
draw.draw_indexed(indices.clone(), 0, 0..1);

View file

@ -6,7 +6,7 @@ layout(location = 2) in vec2 Vertex_Uv;
layout(location = 0) out vec2 v_Uv;
layout(set = 0, binding = 0) uniform UiCamera {
layout(set = 0, binding = 0) uniform Camera {
mat4 ViewProj;
};

View file

@ -1,10 +1,18 @@
use uuid::Uuid;
#[derive(Debug)]
pub enum WindowReference {
Primary,
Id(WindowId),
}
impl Default for WindowReference {
fn default() -> Self {
WindowReference::Primary
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct WindowId(Uuid);

View file

@ -1,18 +1,30 @@
use bevy::{prelude::*, window::CreateWindow};
use bevy_render::{pass::{StoreOp, LoadOp, TextureAttachment, RenderPassColorAttachmentDescriptor, PassDescriptor, RenderPassDepthStencilAttachmentDescriptor}, texture::{TextureDescriptor, TextureFormat, TextureUsage}};
use bevy_window::{WindowId, WindowReference};
use bevy::{
prelude::*,
render::{
pass::{
LoadOp, PassDescriptor, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, StoreOp, TextureAttachment,
},
texture::{TextureDescriptor, TextureFormat, TextureUsage},
ActiveCameras,
},
window::{CreateWindow, WindowId, WindowReference},
};
fn main() {
App::build()
.add_default_plugins()
.add_startup_system(create_second_window_system.system())
.add_startup_system(setup_scene.system())
.add_startup_system(setup.system())
.run();
}
fn create_second_window_system(
fn setup(
command_buffer: &mut CommandBuffer,
mut create_window_events: ResMut<Events<CreateWindow>>,
mut active_cameras: ResMut<ActiveCameras>,
mut render_graph: ResMut<RenderGraph>,
mut materials: ResMut<Assets<StandardMaterial>>,
asset_server: Res<AssetServer>,
) {
let window_id = WindowId::new();
@ -48,6 +60,10 @@ fn create_second_window_system(
),
);
// add a new depth texture node for our new window
render_graph.add_system_node("secondary_camera", CameraNode::new("Secondary"));
// add a new render pass for our new camera
let mut second_window_pass = PassNode::new(PassDescriptor {
color_attachments: vec![RenderPassColorAttachmentDescriptor {
attachment: TextureAttachment::Input("color".to_string()),
@ -70,13 +86,10 @@ fn create_second_window_system(
sample_count: 1,
});
// TODO: use different camera here
second_window_pass.add_camera(bevy::render::base_render_graph::camera::CAMERA);
second_window_pass.add_camera("Secondary");
active_cameras.add("Secondary");
render_graph.add_node(
"second_window_pass",
second_window_pass,
);
render_graph.add_node("second_window_pass", second_window_pass);
render_graph
.add_slot_edge(
@ -95,13 +108,13 @@ fn create_second_window_system(
"depth",
)
.unwrap();
}
fn setup_scene(
command_buffer: &mut CommandBuffer,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
render_graph
.add_node_edge("secondary_camera", "second_window_pass")
.unwrap();
// SETUP SCENE
// load the mesh
let mesh_handle = asset_server
.load("assets/models/monkey/Monkey.gltf")
@ -135,18 +148,19 @@ fn setup_scene(
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
})
// second window camera
.entity_with(PerspectiveCameraComponents {
camera: Camera {
name: Some("Secondary".to_string()),
window: WindowReference::Id(window_id),
..Default::default()
},
transform: Transform::new_sync_disabled(Mat4::face_toward(
Vec3::new(6.0, 0.0, 0.0),
Vec3::new(0.0, 0.0, 0.0),
Vec3::new(0.0, 1.0, 0.0),
)),
..Default::default()
});
// // second window camera
// .entity_with(PerspectiveCameraComponents {
// camera: Camera {
// name: Some("Secondary".to_string()),
// ..Default::default()
// },
// transform: Transform::new_sync_disabled(Mat4::face_toward(
// Vec3::new(0.0, 0.0, 6.0),
// Vec3::new(0.0, 0.0, 0.0),
// Vec3::new(0.0, 1.0, 0.0),
// )),
// ..Default::default()
// });
}