render: ActiveCameras resource and system

This commit is contained in:
Carter Anderson 2020-06-23 15:58:06 -07:00
parent b6dbbf04db
commit ca8625c407
7 changed files with 106 additions and 40 deletions

View file

@ -34,7 +34,7 @@ pub mod node {
pub const SHARED_BUFFERS: &str = "shared_buffers";
}
pub mod uniform {
pub mod camera {
pub const CAMERA: &str = "Camera";
pub const CAMERA2D: &str = "Camera2d";
}
@ -62,11 +62,11 @@ 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(uniform::CAMERA));
self.add_system_node(node::CAMERA, CameraNode::new(camera::CAMERA));
}
if config.add_2d_camera {
self.add_system_node(node::CAMERA2D, CameraNode::new(uniform::CAMERA2D));
self.add_system_node(node::CAMERA2D, CameraNode::new(camera::CAMERA2D));
}
self.add_node(node::SHARED_BUFFERS, SharedBuffersNode::default());

View file

@ -0,0 +1,44 @@
use crate::Camera;
use legion::{
entity::Entity,
prelude::Read,
systems::{Query, ResMut, SubWorld},
};
use std::collections::HashMap;
#[derive(Default)]
pub struct ActiveCameras {
pub cameras: HashMap<String, Option<Entity>>,
}
impl ActiveCameras {
pub fn add(&mut self, name: &str) {
self.cameras.insert(name.to_string(), None);
}
pub fn set(&mut self, name: &str, entity: Entity) {
self.cameras.insert(name.to_string(), Some(entity));
}
pub fn get(&self, name: &str) -> Option<Entity> {
self.cameras.get(name).and_then(|e| e.clone())
}
}
pub fn active_cameras_system(
world: &mut SubWorld,
mut active_cameras: ResMut<ActiveCameras>,
query: &mut Query<Read<Camera>>,
) {
for (name, active_camera) in active_cameras.cameras.iter_mut() {
if let None = active_camera {
for (camera_entity, camera) in query.iter_entities(world) {
if let Some(ref current_name) = camera.name {
if current_name == name {
*active_camera = Some(camera_entity);
}
}
}
}
}
}

View file

@ -1,7 +1,9 @@
mod active_cameras;
mod camera;
mod projection;
mod visible_entities;
pub use active_cameras::*;
pub use camera::*;
pub use projection::*;
pub use visible_entities::*;

View file

@ -33,7 +33,7 @@ impl Default for PerspectiveCameraEntity {
fn default() -> Self {
PerspectiveCameraEntity {
camera: Camera {
name: Some(base_render_graph::uniform::CAMERA.to_string()),
name: Some(base_render_graph::camera::CAMERA.to_string()),
..Default::default()
},
perspective_projection: Default::default(),
@ -81,7 +81,7 @@ impl Default for OrthographicCameraEntity {
fn default() -> Self {
OrthographicCameraEntity {
camera: Camera {
name: Some(base_render_graph::uniform::CAMERA2D.to_string()),
name: Some(base_render_graph::camera::CAMERA2D.to_string()),
..Default::default()
},
orthographic_projection: Default::default(),

View file

@ -94,7 +94,12 @@ impl AppPlugin for RenderPlugin {
.init_resource::<VertexBufferDescriptors>()
.init_resource::<TextureResourceSystemState>()
.init_resource::<AssetRenderResourceBindings>()
.init_resource::<ActiveCameras>()
.add_system_to_stage(bevy_app::stage::PRE_UPDATE, clear_draw_system.system())
.add_system_to_stage(
bevy_app::stage::POST_UPDATE,
camera::active_cameras_system.system(),
)
.add_system_to_stage(
bevy_app::stage::POST_UPDATE,
camera::camera_system::<OrthographicProjection>(),
@ -125,6 +130,14 @@ impl AppPlugin for RenderPlugin {
let resources = app.resources();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
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);
}
if config.add_2d_camera {
active_cameras.add(base_render_graph::camera::CAMERA2D);
}
}
}
}

View file

@ -2,7 +2,7 @@ use crate::{
render_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
render_resource::{BufferInfo, BufferUsage, RenderResourceBinding, RenderResourceBindings},
renderer::{RenderContext, RenderResourceContext},
Camera,
ActiveCameras, Camera,
};
use bevy_core::bytes::AsBytes;
@ -12,17 +12,17 @@ use std::borrow::Cow;
pub struct CameraNode {
command_queue: CommandQueue,
uniform_name: Cow<'static, str>,
camera_name: Cow<'static, str>,
}
impl CameraNode {
pub fn new<T>(uniform_name: T) -> Self
pub fn new<T>(camera_name: T) -> Self
where
T: Into<Cow<'static, str>>,
{
CameraNode {
command_queue: Default::default(),
uniform_name: uniform_name.into(),
camera_name: camera_name.into(),
}
}
}
@ -44,13 +44,14 @@ impl SystemNode for CameraNode {
fn get_system(&self) -> Box<dyn Schedulable> {
let mut camera_buffer = None;
let mut command_queue = self.command_queue.clone();
let uniform_name = self.uniform_name.clone();
let camera_name = self.camera_name.clone();
(move |world: &mut SubWorld,
active_cameras: Res<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: &mut Query<(Read<Camera>, Read<Transform>)>| {
_query: &mut Query<(Read<Camera>, Read<Transform>)>| {
let render_resource_context = &**render_resource_context;
if camera_buffer.is_none() {
let size = std::mem::size_of::<[[f32; 4]; 4]>();
@ -60,7 +61,7 @@ impl SystemNode for CameraNode {
..Default::default()
});
render_resource_bindings.set(
&uniform_name,
&camera_name,
RenderResourceBinding::Buffer {
buffer,
range: 0..size as u64,
@ -69,34 +70,38 @@ impl SystemNode for CameraNode {
);
camera_buffer = Some(buffer);
}
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
if let Some((camera, transform)) = query
.iter(world)
.find(|(camera, _)| camera.name.as_ref().map(|n| n.as_str()) == Some(&uniform_name))
let (camera, transform) = if let Some(camera_entity) = active_cameras.get(&camera_name)
{
let camera_matrix: [f32; 16] =
(camera.view_matrix * transform.value).to_cols_array();
(
world.get_component::<Camera>(camera_entity).unwrap(),
world.get_component::<Transform>(camera_entity).unwrap(),
)
} else {
return;
};
let tmp_buffer = render_resource_context.create_buffer_mapped(
BufferInfo {
size: matrix_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| {
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
},
);
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
let camera_matrix: [f32; 16] = (camera.view_matrix * transform.value).to_cols_array();
command_queue.copy_buffer_to_buffer(
tmp_buffer,
0,
camera_buffer.unwrap(),
0,
matrix_size as u64,
);
command_queue.free_buffer(tmp_buffer);
}
let tmp_buffer = render_resource_context.create_buffer_mapped(
BufferInfo {
size: matrix_size,
buffer_usage: BufferUsage::COPY_SRC,
..Default::default()
},
&mut |data, _renderer| {
data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes());
},
);
command_queue.copy_buffer_to_buffer(
tmp_buffer,
0,
camera_buffer.unwrap(),
0,
matrix_size as u64,
);
command_queue.free_buffer(tmp_buffer);
})
.system()
}

View file

@ -4,7 +4,7 @@ use bevy_render::{
pipeline::{state_descriptors::*, PipelineDescriptor},
render_graph::{nodes::CameraNode, RenderGraph},
shader::{Shader, ShaderStage, ShaderStages},
texture::TextureFormat,
texture::TextureFormat, ActiveCameras,
};
use legion::prelude::Resources;
@ -60,7 +60,7 @@ pub mod node {
pub const UI_CAMERA: &'static str = "ui_camera";
}
pub mod uniform {
pub mod camera {
pub const UI_CAMERA: &'static str = "UiCamera";
}
@ -70,12 +70,14 @@ pub trait UiRenderGraphBuilder {
impl UiRenderGraphBuilder for RenderGraph {
fn add_ui_graph(&mut self, resources: &Resources) -> &mut Self {
self.add_system_node(node::UI_CAMERA, CameraNode::new(uniform::UI_CAMERA));
self.add_system_node(node::UI_CAMERA, CameraNode::new(camera::UI_CAMERA));
self.add_node_edge(node::UI_CAMERA, base_render_graph::node::MAIN_PASS)
.unwrap();
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders));
let mut active_cameras = resources.get_mut::<ActiveCameras>().unwrap();
active_cameras.add(camera::UI_CAMERA);
self
}
}