render: add front-to-back drawing

MainPassNodes now have assigned cameras and draw using those camera's VisibleEntities
This commit is contained in:
Carter Anderson 2020-06-23 16:52:50 -07:00
parent ca8625c407
commit 41dc8a5967
5 changed files with 146 additions and 95 deletions

View File

@ -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)

View File

@ -17,24 +17,40 @@ pub struct VisibleEntities {
pub value: Vec<VisibleEntity>,
}
impl VisibleEntities {
pub fn iter(&self) -> impl DoubleEndedIterator<Item=&VisibleEntity> {
self.value.iter()
}
}
pub fn visible_entities_system(
world: &mut SubWorld,
camera_query: &mut Query<(Read<Camera>, Read<Transform>, Write<VisibleEntities>)>,
entities_query: &mut Query<(Read<Draw>, Read<Transform>)>,
entities_query: &mut Query<Read<Draw>>,
_transform_entities_query: &mut Query<(Read<Draw>, Read<Transform>)>, // 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::<Transform>(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,
})
}

View File

@ -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<ResourceSlotInfo>,
cameras: Vec<String>,
color_attachment_input_indices: Vec<Option<usize>>,
depth_stencil_attachment_input_index: Option<usize>,
}
@ -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::<RenderResourceBindings>().unwrap();
let pipelines = resources.get::<Assets<PipelineDescriptor>>().unwrap();
let active_cameras= resources.get::<ActiveCameras>().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 <Read<Draw>>::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::<VisibleEntities>(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::<Draw>(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);
}
}
}
}
},
);
},
);
}
}
}

View File

@ -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::<Assets<PipelineDescriptor>>().unwrap();
let mut shaders = resources.get_mut::<Assets<Shader>>().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::<ActiveCameras>().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
}

View File

@ -23,10 +23,10 @@ fn camera_order_color_system(
_material_query: &mut Query<Read<Handle<StandardMaterial>>>,
) {
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::<Handle<StandardMaterial>>(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);
}
}