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 const SHARED_BUFFERS: &str = "shared_buffers";
} }
pub mod uniform { pub mod camera {
pub const CAMERA: &str = "Camera"; pub const CAMERA: &str = "Camera";
pub const CAMERA2D: &str = "Camera2d"; pub const CAMERA2D: &str = "Camera2d";
} }
@ -62,11 +62,11 @@ 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(uniform::CAMERA)); self.add_system_node(node::CAMERA, CameraNode::new(camera::CAMERA));
} }
if config.add_2d_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()); 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 camera;
mod projection; mod projection;
mod visible_entities; mod visible_entities;
pub use active_cameras::*;
pub use camera::*; pub use camera::*;
pub use projection::*; pub use projection::*;
pub use visible_entities::*; pub use visible_entities::*;

View File

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

View File

@ -94,7 +94,12 @@ impl AppPlugin for RenderPlugin {
.init_resource::<VertexBufferDescriptors>() .init_resource::<VertexBufferDescriptors>()
.init_resource::<TextureResourceSystemState>() .init_resource::<TextureResourceSystemState>()
.init_resource::<AssetRenderResourceBindings>() .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::PRE_UPDATE, clear_draw_system.system())
.add_system_to_stage(
bevy_app::stage::POST_UPDATE,
camera::active_cameras_system.system(),
)
.add_system_to_stage( .add_system_to_stage(
bevy_app::stage::POST_UPDATE, bevy_app::stage::POST_UPDATE,
camera::camera_system::<OrthographicProjection>(), camera::camera_system::<OrthographicProjection>(),
@ -125,6 +130,14 @@ impl AppPlugin for RenderPlugin {
let resources = app.resources(); let resources = app.resources();
let mut render_graph = resources.get_mut::<RenderGraph>().unwrap(); let mut render_graph = resources.get_mut::<RenderGraph>().unwrap();
render_graph.add_base_graph(config); 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_graph::{CommandQueue, Node, ResourceSlots, SystemNode},
render_resource::{BufferInfo, BufferUsage, RenderResourceBinding, RenderResourceBindings}, render_resource::{BufferInfo, BufferUsage, RenderResourceBinding, RenderResourceBindings},
renderer::{RenderContext, RenderResourceContext}, renderer::{RenderContext, RenderResourceContext},
Camera, ActiveCameras, Camera,
}; };
use bevy_core::bytes::AsBytes; use bevy_core::bytes::AsBytes;
@ -12,17 +12,17 @@ use std::borrow::Cow;
pub struct CameraNode { pub struct CameraNode {
command_queue: CommandQueue, command_queue: CommandQueue,
uniform_name: Cow<'static, str>, camera_name: Cow<'static, str>,
} }
impl CameraNode { impl CameraNode {
pub fn new<T>(uniform_name: T) -> Self pub fn new<T>(camera_name: T) -> Self
where where
T: Into<Cow<'static, str>>, T: Into<Cow<'static, str>>,
{ {
CameraNode { CameraNode {
command_queue: Default::default(), 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> { fn get_system(&self) -> Box<dyn Schedulable> {
let mut camera_buffer = None; let mut camera_buffer = None;
let mut command_queue = self.command_queue.clone(); 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, (move |world: &mut SubWorld,
active_cameras: Res<ActiveCameras>,
render_resource_context: Res<Box<dyn RenderResourceContext>>, render_resource_context: Res<Box<dyn RenderResourceContext>>,
// PERF: this write on RenderResourceAssignments will prevent this system from running in parallel // PERF: this write on RenderResourceAssignments will prevent this system from running in parallel
// with other systems that do the same // with other systems that do the same
mut render_resource_bindings: ResMut<RenderResourceBindings>, 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; let render_resource_context = &**render_resource_context;
if camera_buffer.is_none() { if camera_buffer.is_none() {
let size = std::mem::size_of::<[[f32; 4]; 4]>(); let size = std::mem::size_of::<[[f32; 4]; 4]>();
@ -60,7 +61,7 @@ impl SystemNode for CameraNode {
..Default::default() ..Default::default()
}); });
render_resource_bindings.set( render_resource_bindings.set(
&uniform_name, &camera_name,
RenderResourceBinding::Buffer { RenderResourceBinding::Buffer {
buffer, buffer,
range: 0..size as u64, range: 0..size as u64,
@ -69,34 +70,38 @@ impl SystemNode for CameraNode {
); );
camera_buffer = Some(buffer); camera_buffer = Some(buffer);
} }
let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>(); let (camera, transform) = if let Some(camera_entity) = active_cameras.get(&camera_name)
if let Some((camera, transform)) = query
.iter(world)
.find(|(camera, _)| camera.name.as_ref().map(|n| n.as_str()) == Some(&uniform_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( let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>();
BufferInfo { let camera_matrix: [f32; 16] = (camera.view_matrix * transform.value).to_cols_array();
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( let tmp_buffer = render_resource_context.create_buffer_mapped(
tmp_buffer, BufferInfo {
0, size: matrix_size,
camera_buffer.unwrap(), buffer_usage: BufferUsage::COPY_SRC,
0, ..Default::default()
matrix_size as u64, },
); &mut |data, _renderer| {
command_queue.free_buffer(tmp_buffer); 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() .system()
} }

View File

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