Skip to content

Commit

Permalink
Flexible camera bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
cart committed Mar 19, 2021
1 parent 0a875f6 commit 4f9a6fc
Show file tree
Hide file tree
Showing 15 changed files with 270 additions and 235 deletions.
2 changes: 1 addition & 1 deletion assets/shaders/hot.vert
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ 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;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ 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;
};

Expand Down
25 changes: 17 additions & 8 deletions crates/bevy_render/src/camera/active_cameras.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
use crate::renderer::RenderResourceBindings;

use super::Camera;
use bevy_ecs::{
entity::Entity,
system::{Query, ResMut},
};
use bevy_utils::HashMap;

#[derive(Debug, Default)]
pub struct ActiveCamera {
pub entity: Option<Entity>,
pub bindings: RenderResourceBindings,
}

#[derive(Debug, Default)]
pub struct ActiveCameras {
pub cameras: HashMap<String, Option<Entity>>,
cameras: HashMap<String, ActiveCamera>,
}

impl ActiveCameras {
pub fn add(&mut self, name: &str) {
self.cameras.insert(name.to_string(), None);
self.cameras
.insert(name.to_string(), ActiveCamera::default());
}

pub fn set(&mut self, name: &str, entity: Entity) {
self.cameras.insert(name.to_string(), Some(entity));
pub fn get(&self, name: &str) -> Option<&ActiveCamera> {
self.cameras.get(name)
}

pub fn get(&self, name: &str) -> Option<Entity> {
self.cameras.get(name).and_then(|e| *e)
pub fn get_mut(&mut self, name: &str) -> Option<&mut ActiveCamera> {
self.cameras.get_mut(name)
}
}

Expand All @@ -29,11 +38,11 @@ pub fn active_cameras_system(
query: Query<(Entity, &Camera)>,
) {
for (name, active_camera) in active_cameras.cameras.iter_mut() {
if active_camera.is_none() {
if active_camera.entity.is_none() {
for (camera_entity, camera) in query.iter() {
if let Some(ref current_name) = camera.name {
if current_name == name {
*active_camera = Some(camera_entity);
active_camera.entity = Some(camera_entity);
}
}
}
Expand Down
130 changes: 84 additions & 46 deletions crates/bevy_render/src/render_graph/nodes/camera_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
renderer::{
BufferId, BufferInfo, BufferMapMode, BufferUsage, RenderContext, RenderResourceBinding,
RenderResourceBindings, RenderResourceContext,
RenderResourceContext,
},
};
use bevy_core::AsBytes;
Expand Down Expand Up @@ -50,88 +50,126 @@ 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,
})
});
Box::new(system)
}
}

const CAMERA_VIEW_PROJ: &str = "CameraViewProj";
const CAMERA_VIEW: &str = "CameraView";

#[derive(Debug, Default)]
pub struct CameraNodeState {
command_queue: CommandQueue,
camera_name: Cow<'static, str>,
camera_buffer: Option<BufferId>,
staging_buffer: Option<BufferId>,
}

const MATRIX_SIZE: usize = std::mem::size_of::<[[f32; 4]; 4]>();

pub fn camera_node_system(
mut state: Local<CameraNodeState>,
active_cameras: Res<ActiveCameras>,
mut active_cameras: ResMut<ActiveCameras>,
render_resource_context: Res<Box<dyn RenderResourceContext>>,
// PERF: this write on RenderResourceAssignments will prevent this system from running in
// parallel with other systems that do the same
mut render_resource_bindings: ResMut<RenderResourceBindings>,
query: Query<(&Camera, &GlobalTransform)>,
mut query: Query<(&Camera, &GlobalTransform)>,
) {
let render_resource_context = &**render_resource_context;

let (camera, global_transform) = if let Some(entity) = active_cameras.get(&state.camera_name) {
query.get(entity).unwrap()
} else {
return;
};
let ((camera, global_transform), bindings) =
if let Some(active_camera) = active_cameras.get_mut(&state.camera_name) {
if let Some(entity) = active_camera.entity {
(query.get_mut(entity).unwrap(), &mut active_camera.bindings)
} else {
return;
}
} 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 staging_buffer = render_resource_context.create_buffer(BufferInfo {
size: MATRIX_SIZE * 2,
buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
mapped_at_creation: true,
});

state.staging_buffer = Some(staging_buffer);
staging_buffer
};

if bindings.get(CAMERA_VIEW_PROJ).is_none() {
let buffer = render_resource_context.create_buffer(BufferInfo {
size,
size: MATRIX_SIZE,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
..Default::default()
});
render_resource_bindings.set(
&state.camera_name,
bindings.set(
CAMERA_VIEW_PROJ,
RenderResourceBinding::Buffer {
buffer,
range: 0..size as u64,
range: 0..MATRIX_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,
if bindings.get(CAMERA_VIEW).is_none() {
let buffer = render_resource_context.create_buffer(BufferInfo {
size: MATRIX_SIZE,
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
..Default::default()
});
bindings.set(
CAMERA_VIEW,
RenderResourceBinding::Buffer {
buffer,
range: 0..MATRIX_SIZE as u64,
dynamic_index: None,
},
);
}

state.staging_buffer = Some(staging_buffer);
staging_buffer
};
let view = global_transform.compute_matrix();

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_context.write_mapped_buffer(
staging_buffer,
0..matrix_size as u64,
&mut |data, _renderer| {
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
},
);
render_resource_context.unmap_buffer(staging_buffer);
if let Some(RenderResourceBinding::Buffer { buffer, .. }) = bindings.get(CAMERA_VIEW) {
render_resource_context.write_mapped_buffer(
staging_buffer,
0..MATRIX_SIZE as u64,
&mut |data, _renderer| {
data[0..MATRIX_SIZE].copy_from_slice(view.to_cols_array_2d().as_bytes());
},
);
state.command_queue.copy_buffer_to_buffer(
staging_buffer,
0,
*buffer,
0,
MATRIX_SIZE as u64,
);
}

if let Some(RenderResourceBinding::Buffer { buffer, .. }) = bindings.get(CAMERA_VIEW_PROJ) {
let view_proj = camera.projection_matrix * view.inverse();
render_resource_context.write_mapped_buffer(
staging_buffer,
MATRIX_SIZE as u64..(2 * MATRIX_SIZE) as u64,
&mut |data, _renderer| {
data[0..MATRIX_SIZE].copy_from_slice(view_proj.to_cols_array_2d().as_bytes());
},
);
state.command_queue.copy_buffer_to_buffer(
staging_buffer,
MATRIX_SIZE as u64,
*buffer,
0,
MATRIX_SIZE as u64,
);
}

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);
}
Loading

0 comments on commit 4f9a6fc

Please sign in to comment.