From 41dc8a596793dce340025514b34fcb7d2e2b2885 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Tue, 23 Jun 2020 16:52:50 -0700 Subject: [PATCH] render: add front-to-back drawing MainPassNodes now have assigned cameras and draw using those camera's VisibleEntities --- .../bevy_render/src/base_render_graph/mod.rs | 52 +++--- .../src/camera/visible_entities.rs | 24 ++- .../src/render_graph/nodes/main_pass_node.rs | 149 ++++++++++-------- crates/bevy_ui/src/render/mod.rs | 12 +- examples/3d/z_sort_debug.rs | 4 +- 5 files changed, 146 insertions(+), 95 deletions(-) diff --git a/crates/bevy_render/src/base_render_graph/mod.rs b/crates/bevy_render/src/base_render_graph/mod.rs index 8d7d4dac00..a7fb0fe94e 100644 --- a/crates/bevy_render/src/base_render_graph/mod.rs +++ b/crates/bevy_render/src/base_render_graph/mod.rs @@ -92,29 +92,39 @@ impl BaseRenderGraphBuilder for RenderGraph { } if config.add_main_pass { + let mut main_pass_node = MainPassNode::new(PassDescriptor { + color_attachments: vec![RenderPassColorAttachmentDescriptor { + attachment: TextureAttachment::Input("color".to_string()), + resolve_target: None, + load_op: LoadOp::Clear, + store_op: StoreOp::Store, + clear_color: Color::rgb(0.1, 0.1, 0.1), + }], + depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor { + attachment: TextureAttachment::Input("depth".to_string()), + depth_load_op: LoadOp::Clear, + depth_store_op: StoreOp::Store, + stencil_load_op: LoadOp::Clear, + stencil_store_op: StoreOp::Store, + stencil_read_only: false, + depth_read_only: false, + clear_depth: 1.0, + clear_stencil: 0, + }), + sample_count: 1, + }); + + if config.add_3d_camera { + main_pass_node.add_camera(camera::CAMERA); + } + + if config.add_2d_camera { + main_pass_node.add_camera(camera::CAMERA2D); + } + self.add_node( node::MAIN_PASS, - MainPassNode::new(PassDescriptor { - color_attachments: vec![RenderPassColorAttachmentDescriptor { - attachment: TextureAttachment::Input("color".to_string()), - resolve_target: None, - load_op: LoadOp::Clear, - store_op: StoreOp::Store, - clear_color: Color::rgb(0.1, 0.1, 0.1), - }], - depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor { - attachment: TextureAttachment::Input("depth".to_string()), - depth_load_op: LoadOp::Clear, - depth_store_op: StoreOp::Store, - stencil_load_op: LoadOp::Clear, - stencil_store_op: StoreOp::Store, - stencil_read_only: false, - depth_read_only: false, - clear_depth: 1.0, - clear_stencil: 0, - }), - sample_count: 1, - }), + main_pass_node ); self.add_node_edge(node::TEXTURE_COPY, node::MAIN_PASS) diff --git a/crates/bevy_render/src/camera/visible_entities.rs b/crates/bevy_render/src/camera/visible_entities.rs index a53a369c0f..7f6fd56093 100644 --- a/crates/bevy_render/src/camera/visible_entities.rs +++ b/crates/bevy_render/src/camera/visible_entities.rs @@ -17,24 +17,40 @@ pub struct VisibleEntities { pub value: Vec, } +impl VisibleEntities { + pub fn iter(&self) -> impl DoubleEndedIterator { + self.value.iter() + } +} + pub fn visible_entities_system( world: &mut SubWorld, camera_query: &mut Query<(Read, Read, Write)>, - entities_query: &mut Query<(Read, Read)>, + entities_query: &mut Query>, + _transform_entities_query: &mut Query<(Read, Read)>, // ensures we can optionally access Transforms ) { for (_camera, camera_transform, mut visible_entities) in camera_query.iter_mut(world) { visible_entities.value.clear(); let camera_position = camera_transform.value.w_axis().truncate(); - for (entity, (draw, transform)) in entities_query.iter_entities(world) { + let mut no_transform_order = 0.0; + for (entity, draw) in entities_query.iter_entities(world) { if !draw.is_visible { continue; } - let position = transform.value.w_axis().truncate(); + let order = if let Some(transform) = world.get_component::(entity) { + let position = transform.value.w_axis().truncate(); + // smaller distances are sorted to lower indices by using the negative distance from the camera + FloatOrd(-(camera_position - position).length()) + } else { + let order = FloatOrd(no_transform_order); + no_transform_order += 0.1; + order + }; visible_entities.value.push(VisibleEntity { entity, - order: FloatOrd((camera_position - position).length()), + order, }) } diff --git a/crates/bevy_render/src/render_graph/nodes/main_pass_node.rs b/crates/bevy_render/src/render_graph/nodes/main_pass_node.rs index 355552bb67..e6fdb5d461 100644 --- a/crates/bevy_render/src/render_graph/nodes/main_pass_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/main_pass_node.rs @@ -4,7 +4,7 @@ use crate::{ pipeline::PipelineDescriptor, render_graph::{Node, ResourceSlotInfo, ResourceSlots}, render_resource::{BindGroupId, BufferId, RenderResourceBindings, RenderResourceType}, - renderer::RenderContext, + renderer::RenderContext, ActiveCameras, VisibleEntities, }; use bevy_asset::{Assets, Handle}; use legion::prelude::*; @@ -12,6 +12,7 @@ use legion::prelude::*; pub struct MainPassNode { descriptor: PassDescriptor, inputs: Vec, + cameras: Vec, color_attachment_input_indices: Vec>, depth_stencil_attachment_input_index: Option, } @@ -46,10 +47,15 @@ impl MainPassNode { MainPassNode { descriptor, inputs, + cameras: Vec::new(), color_attachment_input_indices, depth_stencil_attachment_input_index, } } + + pub fn add_camera(&mut self, camera_name: &str) { + self.cameras.push(camera_name.to_string()); + } } impl Node for MainPassNode { @@ -67,6 +73,7 @@ impl Node for MainPassNode { ) { let render_resource_bindings = resources.get::().unwrap(); let pipelines = resources.get::>().unwrap(); + let active_cameras= resources.get::().unwrap(); for (i, color_attachment) in self.descriptor.color_attachments.iter_mut().enumerate() { if let Some(input_index) = self.color_attachment_input_indices[i] { @@ -84,74 +91,88 @@ impl Node for MainPassNode { TextureAttachment::Id(input.get(input_index).unwrap().get_texture().unwrap()); } - render_context.begin_pass( - &self.descriptor, - &render_resource_bindings, - &mut |render_pass| { - let mut draw_state = DrawState::default(); - for draw in >::query().iter(&world) { - if !draw.is_visible { - continue; - } + for camera_name in self.cameras.iter() { + let visible_entities = if let Some(camera_entity) = active_cameras.get(camera_name) { + world.get_component::(camera_entity).unwrap() + } else { + continue; + }; - for render_command in draw.render_commands.iter() { - match render_command { - RenderCommand::SetPipeline { pipeline } => { - // TODO: Filter pipelines - render_pass.set_pipeline(*pipeline); - let descriptor = pipelines.get(pipeline).unwrap(); - draw_state.set_pipeline(*pipeline, descriptor); - } - RenderCommand::DrawIndexed { - base_vertex, - indices, - instances, - } => { - if draw_state.can_draw_indexed() { - render_pass.draw_indexed( - indices.clone(), - *base_vertex, - instances.clone(), - ); - } else { - log::info!("Could not draw indexed because the pipeline layout wasn't fully set for pipeline: {:?}", draw_state.pipeline); + render_context.begin_pass( + &self.descriptor, + &render_resource_bindings, + &mut |render_pass| { + let mut draw_state = DrawState::default(); + for visible_entity in visible_entities.iter() { + let draw = if let Some(draw) = world.get_component::(visible_entity.entity) { + draw + } else { + continue; + }; + + if !draw.is_visible { + continue; + } + + for render_command in draw.render_commands.iter() { + match render_command { + RenderCommand::SetPipeline { pipeline } => { + // TODO: Filter pipelines + render_pass.set_pipeline(*pipeline); + let descriptor = pipelines.get(pipeline).unwrap(); + draw_state.set_pipeline(*pipeline, descriptor); + } + RenderCommand::DrawIndexed { + base_vertex, + indices, + instances, + } => { + if draw_state.can_draw_indexed() { + render_pass.draw_indexed( + indices.clone(), + *base_vertex, + instances.clone(), + ); + } else { + log::info!("Could not draw indexed because the pipeline layout wasn't fully set for pipeline: {:?}", draw_state.pipeline); + } + } + RenderCommand::SetVertexBuffer { + buffer, + offset, + slot, + } => { + render_pass.set_vertex_buffer(*slot, *buffer, *offset); + draw_state.set_vertex_buffer(*slot, *buffer); + } + RenderCommand::SetIndexBuffer { buffer, offset } => { + render_pass.set_index_buffer(*buffer, *offset); + draw_state.set_index_buffer(*buffer) + } + RenderCommand::SetBindGroup { + index, + bind_group, + dynamic_uniform_indices, + } => { + let pipeline = pipelines.get(&draw_state.pipeline.unwrap()).unwrap(); + let layout = pipeline.get_layout().unwrap(); + let bind_group_descriptor = layout.get_bind_group(*index).unwrap(); + render_pass.set_bind_group( + *index, + bind_group_descriptor.id, + *bind_group, + dynamic_uniform_indices + .as_ref() + .map(|indices| indices.as_slice()), + ); + draw_state.set_bind_group(*index, *bind_group); } - } - RenderCommand::SetVertexBuffer { - buffer, - offset, - slot, - } => { - render_pass.set_vertex_buffer(*slot, *buffer, *offset); - draw_state.set_vertex_buffer(*slot, *buffer); - } - RenderCommand::SetIndexBuffer { buffer, offset } => { - render_pass.set_index_buffer(*buffer, *offset); - draw_state.set_index_buffer(*buffer) - } - RenderCommand::SetBindGroup { - index, - bind_group, - dynamic_uniform_indices, - } => { - let pipeline = pipelines.get(&draw_state.pipeline.unwrap()).unwrap(); - let layout = pipeline.get_layout().unwrap(); - let bind_group_descriptor = layout.get_bind_group(*index).unwrap(); - render_pass.set_bind_group( - *index, - bind_group_descriptor.id, - *bind_group, - dynamic_uniform_indices - .as_ref() - .map(|indices| indices.as_slice()), - ); - draw_state.set_bind_group(*index, *bind_group); } } } - } - }, - ); + }, + ); + } } } diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index a8cc20d50a..e2e32d9acf 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -2,7 +2,7 @@ use bevy_asset::{Assets, Handle}; use bevy_render::{ base_render_graph, pipeline::{state_descriptors::*, PipelineDescriptor}, - render_graph::{nodes::CameraNode, RenderGraph}, + render_graph::{nodes::{MainPassNode, CameraNode}, RenderGraph}, shader::{Shader, ShaderStage, ShaderStages}, texture::TextureFormat, ActiveCameras, }; @@ -70,13 +70,17 @@ 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(camera::UI_CAMERA)); - self.add_node_edge(node::UI_CAMERA, base_render_graph::node::MAIN_PASS) - .unwrap(); let mut pipelines = resources.get_mut::>().unwrap(); let mut shaders = resources.get_mut::>().unwrap(); pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders)); + + // setup 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 active_cameras = resources.get_mut::().unwrap(); + let main_pass_node: &mut MainPassNode = self.get_node_mut(base_render_graph::node::MAIN_PASS).unwrap(); + main_pass_node.add_camera(camera::UI_CAMERA); active_cameras.add(camera::UI_CAMERA); self } diff --git a/examples/3d/z_sort_debug.rs b/examples/3d/z_sort_debug.rs index 541f6283c0..015991849e 100644 --- a/examples/3d/z_sort_debug.rs +++ b/examples/3d/z_sort_debug.rs @@ -23,10 +23,10 @@ fn camera_order_color_system( _material_query: &mut Query>>, ) { for (_camera, visible_entities) in camera_query.iter(world) { - for visible_entity in visible_entities.value.iter() { + for visible_entity in visible_entities.iter() { if let Some(material_handle) = world.get_component::>(visible_entity.entity) { let material = materials.get_mut(&material_handle).unwrap(); - let value = 1.0 - (20.0 - visible_entity.order.0) / 7.0; + let value = 1.0 - (20.0 + visible_entity.order.0) / 7.0; material.albedo = Color::rgb(value, value, value); } }