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![ dynamic_bindings: vec![
// Transform // Transform
DynamicBinding { DynamicBinding {
bind_group: 1, bind_group: 2,
binding: 0, binding: 0,
}, },
// StandardMaterial_albedo // StandardMaterial_albedo
DynamicBinding { DynamicBinding {
bind_group: 2, bind_group: 3,
binding: 0, binding: 0,
}, },
], ],

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -132,7 +132,7 @@ impl AppPlugin for RenderPlugin {
render_graph.add_base_graph(config); render_graph.add_base_graph(config);
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap(); let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
if config.add_3d_camera { 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 { if config.add_2d_camera {

View File

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

View File

@ -85,14 +85,7 @@ impl PipelineLayout {
} }
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] #[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct UniformProperty { pub enum UniformProperty {
pub name: String,
pub property_type: UniformPropertyType,
}
#[derive(Hash, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum UniformPropertyType {
// TODO: Use VertexFormat here
UInt, UInt,
Int, Int,
IVec2, IVec2,
@ -104,27 +97,27 @@ pub enum UniformPropertyType {
Mat3, Mat3,
Mat4, Mat4,
Struct(Vec<UniformProperty>), Struct(Vec<UniformProperty>),
Array(Box<UniformPropertyType>, usize), Array(Box<UniformProperty>, usize),
} }
impl UniformPropertyType { impl UniformProperty {
pub fn get_size(&self) -> u64 { pub fn get_size(&self) -> u64 {
match self { match self {
UniformPropertyType::UInt => 4, UniformProperty::UInt => 4,
UniformPropertyType::Int => 4, UniformProperty::Int => 4,
UniformPropertyType::IVec2 => 4 * 2, UniformProperty::IVec2 => 4 * 2,
UniformPropertyType::Float => 4, UniformProperty::Float => 4,
UniformPropertyType::UVec4 => 4 * 4, UniformProperty::UVec4 => 4 * 4,
UniformPropertyType::Vec2 => 4 * 2, UniformProperty::Vec2 => 4 * 2,
UniformPropertyType::Vec3 => 4 * 3, UniformProperty::Vec3 => 4 * 3,
UniformPropertyType::Vec4 => 4 * 4, UniformProperty::Vec4 => 4 * 4,
UniformPropertyType::Mat3 => 4 * 4 * 3, UniformProperty::Mat3 => 4 * 4 * 3,
UniformPropertyType::Mat4 => 4 * 4 * 4, UniformProperty::Mat4 => 4 * 4 * 4,
UniformPropertyType::Struct(properties) => properties UniformProperty::Struct(properties) => properties
.iter() .iter()
.map(|p| p.property_type.get_size()) .map(|p| p.get_size())
.fold(0, |total, size| total + 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::{ use crate::{
draw::{Draw, RenderCommand}, draw::{Draw, RenderCommand},
pass::{PassDescriptor, TextureAttachment, ClearColor}, pass::{ClearColor, PassDescriptor, TextureAttachment},
pipeline::PipelineDescriptor, pipeline::{
BindGroupDescriptor, BindType, BindingDescriptor, PipelineDescriptor, UniformProperty,
},
render_graph::{Node, ResourceSlotInfo, ResourceSlots}, render_graph::{Node, ResourceSlotInfo, ResourceSlots},
render_resource::{BindGroupId, BufferId, RenderResourceBindings, RenderResourceType}, render_resource::{
renderer::RenderContext, ActiveCameras, VisibleEntities, BindGroup, BindGroupId, BufferId, RenderResourceBindings, RenderResourceType,
},
renderer::RenderContext,
ActiveCameras, VisibleEntities,
}; };
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use legion::prelude::*; use legion::prelude::*;
struct CameraInfo {
name: String,
bind_group_id: Option<BindGroupId>,
}
pub struct PassNode { pub struct PassNode {
descriptor: PassDescriptor, descriptor: PassDescriptor,
inputs: Vec<ResourceSlotInfo>, inputs: Vec<ResourceSlotInfo>,
cameras: Vec<String>, cameras: Vec<CameraInfo>,
color_attachment_input_indices: Vec<Option<usize>>, color_attachment_input_indices: Vec<Option<usize>>,
depth_stencil_attachment_input_index: Option<usize>, depth_stencil_attachment_input_index: Option<usize>,
default_clear_color_inputs: Vec<usize>, default_clear_color_inputs: Vec<usize>,
camera_bind_group_descriptor: BindGroupDescriptor,
} }
impl PassNode { 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 { PassNode {
descriptor, descriptor,
inputs, inputs,
@ -52,11 +75,15 @@ impl PassNode {
color_attachment_input_indices, color_attachment_input_indices,
depth_stencil_attachment_input_index, depth_stencil_attachment_input_index,
default_clear_color_inputs: Vec::new(), default_clear_color_inputs: Vec::new(),
camera_bind_group_descriptor,
} }
} }
pub fn add_camera(&mut self, camera_name: &str) { 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) { 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 render_resource_bindings = resources.get::<RenderResourceBindings>().unwrap();
let pipelines = resources.get::<Assets<PipelineDescriptor>>().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() { for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() {
if self.default_clear_color_inputs.contains(&i) { if self.default_clear_color_inputs.contains(&i) {
if let Some(default_clear_color) = resources.get::<ClearColor>() { 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] { if let Some(input_index) = self.color_attachment_input_indices[i] {
@ -101,18 +128,40 @@ impl Node for PassNode {
.attachment = .attachment =
TextureAttachment::Id(input.get(input_index).unwrap().get_texture().unwrap()); 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( render_context.begin_pass(
&self.descriptor, &self.descriptor,
&render_resource_bindings, &render_resource_bindings,
&mut |render_pass| { &mut |render_pass| {
for camera_name in self.cameras.iter() { for camera_info in self.cameras.iter() {
let visible_entities = if let Some(camera_entity) = active_cameras.get(camera_name) { 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() world.get_component::<VisibleEntities>(camera_entity).unwrap()
} else { } else {
continue; continue;
}; };
// attempt to draw each visible entity
let mut draw_state = DrawState::default(); let mut draw_state = DrawState::default();
for visible_entity in visible_entities.iter() { for visible_entity in visible_entities.iter() {
let draw = if let Some(draw) = world.get_component::<Draw>(visible_entity.entity) { 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 { if !draw.is_visible {
continue; 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() { for render_command in draw.render_commands.iter() {
match render_command { match render_command {
RenderCommand::SetPipeline { pipeline } => { RenderCommand::SetPipeline { pipeline } => {
@ -132,6 +182,20 @@ impl Node for PassNode {
render_pass.set_pipeline(*pipeline); render_pass.set_pipeline(*pipeline);
let descriptor = pipelines.get(pipeline).unwrap(); let descriptor = pipelines.get(pipeline).unwrap();
draw_state.set_pipeline(*pipeline, descriptor); 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 { RenderCommand::DrawIndexed {
base_vertex, base_vertex,

View File

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

View File

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

View File

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

View File

@ -7,16 +7,9 @@ layout(location = 2) in vec2 Vertex_Uv;
layout(location = 0) out vec2 v_Uv; layout(location = 0) out vec2 v_Uv;
layout(location = 1) out vec4 v_Color; 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 layout(set = 0, binding = 0) uniform Camera {
#ifdef UI_CAMERA
layout(set = 0, binding = 0) uniform UiCamera {
mat4 ViewProj; 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 // TODO: merge dimensions into "sprites" buffer when that is supported in the Uniforms derive abstraction
layout(set = 1, binding = 0) uniform TextureAtlas_size { layout(set = 1, binding = 0) uniform TextureAtlas_size {

View File

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

View File

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

View File

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