diff --git a/assets/shaders/hot.vert b/assets/shaders/hot.vert index 71a610e6e8463..1809b220dfd90 100644 --- a/assets/shaders/hot.vert +++ b/assets/shaders/hot.vert @@ -2,7 +2,7 @@ layout(location = 0) in vec3 Vertex_Position; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; }; diff --git a/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.frag b/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.frag index fc043c0db59c9..36e95ac27a0d8 100644 --- a/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.frag +++ b/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.frag @@ -14,9 +14,12 @@ layout(location = 2) in vec2 v_Uv; layout(location = 0) out vec4 o_Target; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; }; +layout(set = 0, binding = 1) uniform CameraView { + mat4 View; +}; layout(set = 1, binding = 0) uniform Lights { vec3 AmbientColor; diff --git a/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.vert b/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.vert index 028a86389c012..50e60c4d410f9 100644 --- a/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.vert +++ b/crates/bevy_pbr/src/render_graph/forward_pipeline/forward.vert @@ -8,9 +8,12 @@ layout(location = 0) out vec3 v_Position; layout(location = 1) out vec3 v_Normal; layout(location = 2) out vec2 v_Uv; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; }; +layout(set = 0, binding = 1) uniform CameraView { + mat4 View; +}; layout(set = 2, binding = 0) uniform Transform { mat4 Model; diff --git a/crates/bevy_render/src/render_graph/nodes/camera_node.rs b/crates/bevy_render/src/render_graph/nodes/camera_node.rs index ed62fdd395197..d882dad85cc78 100644 --- a/crates/bevy_render/src/render_graph/nodes/camera_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/camera_node.rs @@ -6,12 +6,14 @@ use crate::{ RenderResourceBindings, RenderResourceContext, }, }; -use bevy_core::AsBytes; +use bevy_core::{AsBytes, Byteable, Bytes}; use bevy_ecs::{ system::{BoxedSystem, IntoSystem, Local, Query, Res, ResMut}, world::World, }; + use bevy_transform::prelude::*; +use bevy_utils::HashMap; use std::borrow::Cow; #[derive(Debug)] @@ -50,9 +52,8 @@ impl SystemNode for CameraNode { config.0 = Some(CameraNodeState { camera_name: self.camera_name.clone(), command_queue: self.command_queue.clone(), - camera_buffer: None, - staging_buffer: None, - }) + buffers: HashMap::default(), + }); }); Box::new(system) } @@ -62,8 +63,8 @@ impl SystemNode for CameraNode { pub struct CameraNodeState { command_queue: CommandQueue, camera_name: Cow<'static, str>, - camera_buffer: Option, - staging_buffer: Option, + /// This mas from `binding_name` -> `(staging_buffer_id, buffer_id)` + buffers: HashMap, } pub fn camera_node_system( @@ -75,63 +76,85 @@ pub fn camera_node_system( mut render_resource_bindings: ResMut, query: Query<(&Camera, &GlobalTransform)>, ) { - let render_resource_context = &**render_resource_context; + let camera_name = state.camera_name.clone(); - let (camera, global_transform) = if let Some(entity) = active_cameras.get(&state.camera_name) { + let (camera, global_transform) = if let Some(entity) = active_cameras.get(&camera_name) { query.get(entity).unwrap() } else { return; }; - let staging_buffer = if let Some(staging_buffer) = state.staging_buffer { - render_resource_context.map_buffer(staging_buffer, BufferMapMode::Write); - staging_buffer - } else { - let size = std::mem::size_of::<[[f32; 4]; 4]>(); - let buffer = render_resource_context.create_buffer(BufferInfo { - size, - buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, - ..Default::default() - }); - render_resource_bindings.set( - &state.camera_name, - RenderResourceBinding::Buffer { - buffer, - range: 0..size as u64, - dynamic_index: None, - }, - ); - state.camera_buffer = Some(buffer); - - let staging_buffer = render_resource_context.create_buffer(BufferInfo { - size, - buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE, - mapped_at_creation: true, - }); + let view_matrix = global_transform.compute_matrix().inverse(); + let view_proj_matrix = camera.projection_matrix * view_matrix; - state.staging_buffer = Some(staging_buffer); - staging_buffer - }; + make_binding( + &mut *state, + &**render_resource_context, + &mut *render_resource_bindings, + &format!("{}ViewProj", camera_name), + view_proj_matrix.to_cols_array(), + ); + + make_binding( + &mut *state, + &**render_resource_context, + &mut *render_resource_bindings, + &format!("{}View", camera_name), + view_matrix.to_cols_array(), + ); +} + +fn make_binding( + state: &mut CameraNodeState, + render_resource_context: &dyn RenderResourceContext, + render_resource_bindings: &mut RenderResourceBindings, + binding_name: &str, + bytes: B, +) where + B: Bytes + Byteable, +{ + let buffer_size = bytes.byte_len(); + + let buffers_entry = state.buffers.entry(binding_name.to_owned()); + + let (staging_buffer, buffer) = buffers_entry + .and_modify(|(staging_buffer, _)| { + render_resource_context.map_buffer(*staging_buffer, BufferMapMode::Write); + }) + .or_insert_with(|| { + let buffer = render_resource_context.create_buffer(BufferInfo { + size: buffer_size, + buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM, + ..Default::default() + }); - let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>(); - let camera_matrix: [f32; 16] = - (camera.projection_matrix * global_transform.compute_matrix().inverse()).to_cols_array(); + render_resource_bindings.set( + &binding_name, + RenderResourceBinding::Buffer { + buffer, + range: 0..buffer_size as u64, + dynamic_index: None, + }, + ); + + let staging_buffer = render_resource_context.create_buffer(BufferInfo { + size: buffer_size, + buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE, + mapped_at_creation: true, + }); + (staging_buffer, buffer) + }); render_resource_context.write_mapped_buffer( - staging_buffer, - 0..matrix_size as u64, + *staging_buffer, + 0..buffer_size as u64, &mut |data, _renderer| { - data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); + data[0..buffer_size].copy_from_slice(bytes.as_bytes()); }, ); - render_resource_context.unmap_buffer(staging_buffer); - - let camera_buffer = state.camera_buffer.unwrap(); - state.command_queue.copy_buffer_to_buffer( - staging_buffer, - 0, - camera_buffer, - 0, - matrix_size as u64, - ); + render_resource_context.unmap_buffer(*staging_buffer); + + state + .command_queue + .copy_buffer_to_buffer(*staging_buffer, 0, *buffer, 0, buffer_size as u64); } diff --git a/crates/bevy_render/src/render_graph/nodes/pass_node.rs b/crates/bevy_render/src/render_graph/nodes/pass_node.rs index e105f9bc900b5..b5cf71cb6ce71 100644 --- a/crates/bevy_render/src/render_graph/nodes/pass_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/pass_node.rs @@ -108,15 +108,30 @@ impl PassNode { let camera_bind_group_descriptor = BindGroupDescriptor::new( 0, - vec![BindingDescriptor { - name: "Camera".to_string(), - index: 0, - bind_type: BindType::Uniform { - has_dynamic_offset: false, - property: UniformProperty::Struct(vec![UniformProperty::Mat4]), + vec![ + BindingDescriptor { + name: "CameraViewProj".to_string(), + index: 0, + bind_type: BindType::Uniform { + has_dynamic_offset: false, + property: UniformProperty::Struct(vec![ + UniformProperty::Mat4, // View Projection + ]), + }, + shader_stage: BindingShaderStage::VERTEX | BindingShaderStage::FRAGMENT, }, - shader_stage: BindingShaderStage::VERTEX | BindingShaderStage::FRAGMENT, - }], + BindingDescriptor { + name: "CameraView".to_string(), + index: 1, + bind_type: BindType::Uniform { + has_dynamic_offset: false, + property: UniformProperty::Struct(vec![ + UniformProperty::Mat4, // View + ]), + }, + shader_stage: BindingShaderStage::VERTEX | BindingShaderStage::FRAGMENT, + }, + ], ); PassNode { @@ -192,18 +207,37 @@ where .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; - }; + + 'outer: for camera_info in self.cameras.iter_mut() { + let camera_name = &camera_info.name; + if render_context .resources() .bind_group_descriptor_exists(self.camera_bind_group_descriptor.id) { - let camera_bind_group = BindGroup::build().add_binding(0, camera_binding).finish(); + let mut camera_bind_group_builder = BindGroup::build(); + + for (index, binding_name) in self + .camera_bind_group_descriptor + .bindings + .iter() + .map(|binding| &binding.name) + .enumerate() + { + let camera_binding = if let Some(camera_binding) = render_resource_bindings.get( + &format!("{}{}", &camera_name, binding_name.replace("Camera", "")), + ) { + camera_binding.clone() + } else { + continue 'outer; + }; + + camera_bind_group_builder = + camera_bind_group_builder.add_binding(index as u32, camera_binding); + } + + let camera_bind_group = camera_bind_group_builder.finish(); + render_context .resources() .create_bind_group(self.camera_bind_group_descriptor.id, &camera_bind_group); diff --git a/crates/bevy_render/src/shader/shader_reflect.rs b/crates/bevy_render/src/shader/shader_reflect.rs index fe1ff7167ff76..47d9ac0299275 100644 --- a/crates/bevy_render/src/shader/shader_reflect.rs +++ b/crates/bevy_render/src/shader/shader_reflect.rs @@ -162,7 +162,7 @@ fn reflect_binding( let name = name.to_string(); - if name == "Camera" { + if let Some(0usize) = name.find("Camera") { shader_stage = BindingShaderStage::VERTEX | BindingShaderStage::FRAGMENT; } @@ -325,7 +325,7 @@ mod tests { layout(location = 2) in uvec4 I_TestInstancing_Property; layout(location = 0) out vec4 v_Position; - layout(set = 0, binding = 0) uniform Camera { + layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; }; layout(set = 1, binding = 0) uniform texture2D Texture; @@ -381,7 +381,7 @@ mod tests { 0, vec![BindingDescriptor { index: 0, - name: "Camera".into(), + name: "CameraViewProj".into(), bind_type: BindType::Uniform { has_dynamic_offset: false, property: UniformProperty::Struct(vec![UniformProperty::Mat4]), diff --git a/crates/bevy_render/src/wireframe/wireframe.vert b/crates/bevy_render/src/wireframe/wireframe.vert index 47828402121a0..87b32a667a1cc 100644 --- a/crates/bevy_render/src/wireframe/wireframe.vert +++ b/crates/bevy_render/src/wireframe/wireframe.vert @@ -2,7 +2,7 @@ layout(location = 0) in vec3 Vertex_Position; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; }; diff --git a/crates/bevy_sprite/src/render/sprite.vert b/crates/bevy_sprite/src/render/sprite.vert index 23c77d38c7d72..f1fdd9283a744 100644 --- a/crates/bevy_sprite/src/render/sprite.vert +++ b/crates/bevy_sprite/src/render/sprite.vert @@ -6,8 +6,9 @@ layout(location = 2) in vec2 Vertex_Uv; layout(location = 0) out vec2 v_Uv; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; + mat4 View; }; layout(set = 2, binding = 0) uniform Transform { @@ -25,7 +26,7 @@ void main() { uint x_flip_bit = 1; // The X flip bit uint y_flip_bit = 2; // The Y flip bit - + // Note: Here we subtract f32::EPSILON from the flipped UV coord. This is due to reasons unknown // to me (@zicklag ) that causes the uv's to be slightly offset and causes over/under running of // the sprite UV sampling which is visible when resizing the screen. @@ -41,4 +42,4 @@ void main() { vec3 position = Vertex_Position * vec3(size, 1.0); gl_Position = ViewProj * Model * vec4(position, 1.0); -} \ No newline at end of file +} diff --git a/crates/bevy_sprite/src/render/sprite_sheet.vert b/crates/bevy_sprite/src/render/sprite_sheet.vert index d4ddabad7df5e..4a22ee01c5c72 100644 --- a/crates/bevy_sprite/src/render/sprite_sheet.vert +++ b/crates/bevy_sprite/src/render/sprite_sheet.vert @@ -7,8 +7,9 @@ layout(location = 2) in vec2 Vertex_Uv; layout(location = 0) out vec2 v_Uv; layout(location = 1) out vec4 v_Color; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; + mat4 View; }; // TODO: merge dimensions into "sprites" buffer when that is supported in the Uniforms derive abstraction @@ -25,7 +26,6 @@ layout(set = 1, binding = 1) buffer TextureAtlas_textures { Rect[] Textures; }; - layout(set = 2, binding = 0) uniform Transform { mat4 SpriteTransform; }; @@ -75,11 +75,10 @@ void main() { bottom_left, top_left, top_right, - bottom_right - ); + bottom_right); v_Uv = (atlas_positions[gl_VertexIndex]) / AtlasSize; v_Color = color; gl_Position = ViewProj * SpriteTransform * vec4(vertex_position, 1.0); -} \ No newline at end of file +} diff --git a/crates/bevy_ui/src/render/ui.vert b/crates/bevy_ui/src/render/ui.vert index 2268af642b305..3cf3971e97965 100644 --- a/crates/bevy_ui/src/render/ui.vert +++ b/crates/bevy_ui/src/render/ui.vert @@ -6,8 +6,9 @@ layout(location = 2) in vec2 Vertex_Uv; layout(location = 0) out vec2 v_Uv; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; + mat4 View; }; layout(set = 1, binding = 0) uniform Transform { @@ -21,4 +22,4 @@ void main() { v_Uv = Vertex_Uv; vec3 position = Vertex_Position * vec3(NodeSize, 0.0); gl_Position = ViewProj * Object * vec4(position, 1.0); -} \ No newline at end of file +} diff --git a/examples/shader/array_texture.rs b/examples/shader/array_texture.rs index 3dbbe9ed81a41..f788e842edcfc 100644 --- a/examples/shader/array_texture.rs +++ b/examples/shader/array_texture.rs @@ -32,8 +32,9 @@ const VERTEX_SHADER: &str = r#" layout(location = 0) in vec3 Vertex_Position; layout(location = 0) out vec4 v_Position; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; + mat4 View; }; layout(set = 1, binding = 0) uniform Transform { mat4 Model; diff --git a/examples/shader/mesh_custom_attribute.rs b/examples/shader/mesh_custom_attribute.rs index 42bac14cf63fd..a1366e72a6d14 100644 --- a/examples/shader/mesh_custom_attribute.rs +++ b/examples/shader/mesh_custom_attribute.rs @@ -29,8 +29,9 @@ layout(location = 0) in vec3 Vertex_Position; layout(location = 1) in vec3 Vertex_Color; layout(location = 0) out vec3 v_color; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; + mat4 View; }; layout(set = 1, binding = 0) uniform Transform { mat4 Model; diff --git a/examples/shader/shader_custom_material.rs b/examples/shader/shader_custom_material.rs index b5d2323c90da6..4a6f037b359fd 100644 --- a/examples/shader/shader_custom_material.rs +++ b/examples/shader/shader_custom_material.rs @@ -28,8 +28,9 @@ struct MyMaterial { const VERTEX_SHADER: &str = r#" #version 450 layout(location = 0) in vec3 Vertex_Position; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; + mat4 View; }; layout(set = 1, binding = 0) uniform Transform { mat4 Model; diff --git a/examples/shader/shader_defs.rs b/examples/shader/shader_defs.rs index f14241f3c4264..b99cf6b1c450d 100644 --- a/examples/shader/shader_defs.rs +++ b/examples/shader/shader_defs.rs @@ -36,8 +36,9 @@ struct MyMaterial { const VERTEX_SHADER: &str = r#" #version 450 layout(location = 0) in vec3 Vertex_Position; -layout(set = 0, binding = 0) uniform Camera { +layout(set = 0, binding = 0) uniform CameraViewProj { mat4 ViewProj; + mat4 View; }; layout(set = 1, binding = 0) uniform Transform { mat4 Model;