diff --git a/src/draw.rs b/src/draw.rs index 7d9b5e3..abd5184 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -1,4 +1,7 @@ -use bevy::pbr::{DrawMesh, SetMeshBindGroup}; +use bevy::core_pipeline::prepass::{ + DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass, +}; +use bevy::pbr::{DrawMesh, MeshPipelineViewLayoutKey, SetMeshBindGroup, SetMeshViewBindGroup}; use bevy::prelude::*; use bevy::render::render_asset::RenderAssets; use bevy::render::render_phase::{DrawFunctions, RenderPhase, SetItemPipeline}; @@ -16,12 +19,47 @@ use crate::OutlineRenderLayers; pub(crate) type DrawStencil = ( SetItemPipeline, - SetOutlineViewBindGroup<0>, + SetMeshViewBindGroup<0>, SetMeshBindGroup<1>, - SetOutlineStencilBindGroup<2>, + SetOutlineViewBindGroup<2>, + SetOutlineStencilBindGroup<3>, DrawMesh, ); +fn build_mesh_pipeline_view_layout_key( + msaa: Msaa, + (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass): ( + bool, + bool, + bool, + bool, + ), +) -> MeshPipelineViewLayoutKey { + let mut view_key = MeshPipelineViewLayoutKey::empty(); + + if msaa != Msaa::Off { + view_key |= MeshPipelineViewLayoutKey::MULTISAMPLED; + } + + if normal_prepass { + view_key |= MeshPipelineViewLayoutKey::NORMAL_PREPASS; + } + + if depth_prepass { + view_key |= MeshPipelineViewLayoutKey::DEPTH_PREPASS; + } + + if motion_vector_prepass { + view_key |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS; + } + + if deferred_prepass { + view_key |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS; + } + + view_key +} + #[allow(clippy::too_many_arguments, clippy::type_complexity)] pub(crate) fn queue_outline_stencil_mesh( stencil_draw_functions: Res>, @@ -40,6 +78,12 @@ pub(crate) fn queue_outline_stencil_mesh( &ExtractedView, &mut RenderPhase, Option<&RenderLayers>, + ( + Has, + Has, + Has, + Has, + ), )>, ) { let draw_stencil = stencil_draw_functions @@ -51,7 +95,7 @@ pub(crate) fn queue_outline_stencil_mesh( .with_msaa(*msaa) .with_pass_type(PassType::Stencil); - for (view, mut stencil_phase, view_mask) in views.iter_mut() { + for (view, mut stencil_phase, view_mask, prepasses) in views.iter_mut() { let rangefinder = view.rangefinder3d(); let view_mask = view_mask.copied().unwrap_or_default(); for (entity, stencil_uniform, outline, outline_mask) in material_meshes.iter() { @@ -65,7 +109,8 @@ pub(crate) fn queue_outline_stencil_mesh( .with_primitive_topology(mesh.primitive_topology) .with_depth_mode(outline.depth_mode) .with_offset_zero(stencil_uniform.offset == 0.0) - .with_morph_targets(mesh.morph_targets.is_some()); + .with_morph_targets(mesh.morph_targets.is_some()) + .with_view_key(build_mesh_pipeline_view_layout_key(*msaa, prepasses)); let Ok(pipeline) = pipelines.specialize(&pipeline_cache, &stencil_pipeline, key, &mesh.layout) else { @@ -86,9 +131,10 @@ pub(crate) fn queue_outline_stencil_mesh( pub(crate) type DrawOutline = ( SetItemPipeline, - SetOutlineViewBindGroup<0>, + SetMeshViewBindGroup<0>, SetMeshBindGroup<1>, - SetOutlineVolumeBindGroup<2>, + SetOutlineViewBindGroup<2>, + SetOutlineVolumeBindGroup<3>, DrawMesh, ); @@ -113,6 +159,12 @@ pub(crate) fn queue_outline_volume_mesh( &mut RenderPhase, &mut RenderPhase, Option<&RenderLayers>, + ( + Has, + Has, + Has, + Has, + ), )>, ) { let draw_opaque_outline = opaque_draw_functions @@ -126,7 +178,7 @@ pub(crate) fn queue_outline_volume_mesh( let base_key = PipelineKey::new().with_msaa(*msaa); - for (view, mut opaque_phase, mut transparent_phase, view_mask) in views.iter_mut() { + for (view, mut opaque_phase, mut transparent_phase, view_mask, prepasses) in views.iter_mut() { let view_mask = view_mask.copied().unwrap_or_default(); let rangefinder = view.rangefinder3d(); for (entity, volume_uniform, outline, fragment_uniform, outline_mask) in @@ -149,7 +201,8 @@ pub(crate) fn queue_outline_volume_mesh( .with_depth_mode(outline.depth_mode) .with_offset_zero(volume_uniform.offset == 0.0) .with_hdr_format(view.hdr) - .with_morph_targets(mesh.morph_targets.is_some()); + .with_morph_targets(mesh.morph_targets.is_some()) + .with_view_key(build_mesh_pipeline_view_layout_key(*msaa, prepasses)); let Ok(pipeline) = pipelines.specialize(&pipeline_cache, &outline_pipeline, key, &mesh.layout) else { diff --git a/src/fragment.wgsl b/src/fragment.wgsl index 1e31003..dd1d197 100644 --- a/src/fragment.wgsl +++ b/src/fragment.wgsl @@ -11,7 +11,7 @@ struct OutlineFragmentUniform { }; #ifdef VOLUME -@group(2) @binding(1) +@group(3) @binding(1) var fstage: OutlineFragmentUniform; #endif diff --git a/src/outline.wgsl b/src/outline.wgsl index 069e1f0..a47fb00 100644 --- a/src/outline.wgsl +++ b/src/outline.wgsl @@ -42,14 +42,14 @@ struct OutlineVertexUniform { @group(0) @binding(0) var view: View; -@group(0) @binding(1) -var view_uniform: OutlineViewUniform; - #import bevy_pbr::mesh_bindings #import bevy_pbr::skinning #import bevy_pbr::morph @group(2) @binding(0) +var view_uniform: OutlineViewUniform; + +@group(3) @binding(0) var vstage: OutlineVertexUniform; #ifdef MORPH_TARGETS diff --git a/src/pipeline.rs b/src/pipeline.rs index 12dad97..3ebaed1 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -3,7 +3,8 @@ use std::borrow::Cow; use bevy::ecs::system::lifetimeless::SQuery; use bevy::ecs::system::SystemParamItem; use bevy::pbr::{ - setup_morph_and_skinning_defs, MeshFlags, MeshPipelineKey, MeshTransforms, MeshUniform, + setup_morph_and_skinning_defs, MeshFlags, MeshPipelineKey, MeshPipelineViewLayoutKey, + MeshTransforms, MeshUniform, }; use bevy::prelude::*; use bevy::render::batching::GetBatchData; @@ -16,7 +17,7 @@ use bevy::render::render_resource::{ use bevy::render::renderer::RenderDevice; use bevy::render::settings::WgpuSettings; use bevy::render::texture::BevyDefault; -use bevy::render::view::{ViewTarget, ViewUniform}; +use bevy::render::view::ViewTarget; use bevy::{ pbr::MeshPipeline, render::{ @@ -63,6 +64,7 @@ impl PipelineKey { pub offset_zero, set_offset_zero: 13; pub hdr_format, set_hdr_format: 14; pub morph_targets, set_morph_targets: 15; + view_key_int, set_view_key_int: 23, 16; } pub(crate) fn new() -> Self { @@ -141,6 +143,15 @@ impl PipelineKey { self.set_morph_targets(morph_targets); self } + + pub(crate) fn with_view_key(mut self, view_key: MeshPipelineViewLayoutKey) -> Self { + self.set_view_key_int(view_key.bits()); + self + } + + pub(crate) fn view_key(&self) -> MeshPipelineViewLayoutKey { + MeshPipelineViewLayoutKey::from_bits(self.view_key_int()).unwrap() + } } impl From for MeshPipelineKey { @@ -168,28 +179,16 @@ impl FromWorld for OutlinePipeline { let render_device = world.get_resource::().unwrap(); let outline_view_bind_group_layout = render_device.create_bind_group_layout( "outline_view_bind_group_layout", - &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, + &[BindGroupLayoutEntry { + binding: 0, + visibility: ShaderStages::VERTEX, + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: true, + min_binding_size: Some(OutlineViewUniform::min_size()), }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(OutlineViewUniform::min_size()), - }, - count: None, - }, - ], + count: None, + }], ); let outline_volume_bind_group_layout = render_device.create_bind_group_layout( "outline_volume_bind_group_layout", @@ -258,16 +257,18 @@ impl SpecializedMeshPipeline for OutlinePipeline { buffer_attrs.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0)); } - let mut bind_layouts = vec![self.outline_view_bind_group_layout.clone()]; - - bind_layouts.push(setup_morph_and_skinning_defs( - &self.mesh_pipeline.mesh_layouts, - layout, - 5, - &key.into(), - &mut vertex_defs, - &mut buffer_attrs, - )); + let mut bind_layouts = vec![ + self.mesh_pipeline.get_view_layout(key.view_key()).clone(), + setup_morph_and_skinning_defs( + &self.mesh_pipeline.mesh_layouts, + layout, + 5, + &key.into(), + &mut vertex_defs, + &mut buffer_attrs, + ), + self.outline_view_bind_group_layout.clone(), + ]; let cull_mode; if key.depth_mode() == DepthMode::Flat { diff --git a/src/view_uniforms.rs b/src/view_uniforms.rs index 4d8eb76..aebe7c0 100644 --- a/src/view_uniforms.rs +++ b/src/view_uniforms.rs @@ -9,7 +9,7 @@ use bevy::render::render_phase::{ use bevy::render::render_resource::ShaderType; use bevy::render::render_resource::{BindGroup, BindGroupEntry}; use bevy::render::renderer::RenderDevice; -use bevy::render::view::{RenderLayers, ViewUniformOffset, ViewUniforms}; +use bevy::render::view::RenderLayers; use bevy::render::Extract; use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; @@ -54,26 +54,16 @@ pub(crate) fn prepare_outline_view_bind_group( mut commands: Commands, render_device: Res, outline_pipeline: Res, - core_view_uniforms: Res, - outline_view_uniforms: Res>, + view_uniforms: Res>, ) { - if let (Some(core_view_binding), Some(outline_view_binding)) = ( - core_view_uniforms.uniforms.binding(), - outline_view_uniforms.binding(), - ) { + if let Some(view_binding) = view_uniforms.binding() { let bind_group = render_device.create_bind_group( "outline_view_bind_group", &outline_pipeline.outline_view_bind_group_layout, - &[ - BindGroupEntry { - binding: 0, - resource: core_view_binding.clone(), - }, - BindGroupEntry { - binding: 1, - resource: outline_view_binding.clone(), - }, - ], + &[BindGroupEntry { + binding: 0, + resource: view_binding.clone(), + }], ); commands.insert_resource(OutlineViewBindGroup { bind_group }); } @@ -82,24 +72,17 @@ pub(crate) fn prepare_outline_view_bind_group( pub(crate) struct SetOutlineViewBindGroup(); impl RenderCommand

for SetOutlineViewBindGroup { - type ViewQuery = ( - Read, - Read>, - ); + type ViewQuery = Read>; type ItemQuery = (); type Param = SRes; fn render<'w>( _item: &P, - (core_view_data, outline_view_data): ROQueryItem<'w, Self::ViewQuery>, + view_data: ROQueryItem<'w, Self::ViewQuery>, _entity_data: Option<()>, bind_group: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { - pass.set_bind_group( - I, - &bind_group.into_inner().bind_group, - &[core_view_data.offset, outline_view_data.index()], - ); + pass.set_bind_group(I, &bind_group.into_inner().bind_group, &[view_data.index()]); RenderCommandResult::Success } }