diff --git a/examples/pieces.rs b/examples/pieces.rs index ebeca88..aaa48b2 100644 --- a/examples/pieces.rs +++ b/examples/pieces.rs @@ -53,6 +53,7 @@ fn setup( colour: Color::WHITE, width: 10.0, }, + stencil: OutlineStencil { offset: 5.0 }, ..default() }) .insert(Rotates) @@ -81,6 +82,7 @@ fn setup( colour: Color::WHITE, width: 10.0, }, + stencil: OutlineStencil { offset: 5.0 }, ..default() }) .insert(InheritOutlineDepth); @@ -106,6 +108,7 @@ fn setup( colour: Color::WHITE, width: 10.0, }, + stencil: OutlineStencil { offset: 5.0 }, ..default() }) .insert(InheritOutlineDepth); diff --git a/src/draw.rs b/src/draw.rs index 325ad0f..af0a59d 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -8,10 +8,10 @@ use bevy::render::view::ExtractedView; use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; use crate::pipeline::{OutlinePipeline, PassType, PipelineKey}; use crate::uniforms::{ - OutlineFragmentUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup, + OutlineFragmentUniform, OutlineStencilUniform, OutlineVolumeUniform, + SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup, }; use crate::view_uniforms::SetOutlineViewBindGroup; -use crate::OutlineStencil; pub type DrawStencil = ( SetItemPipeline, @@ -30,7 +30,7 @@ pub fn queue_outline_stencil_mesh( mut pipelines: ResMut>, mut pipeline_cache: ResMut, render_meshes: Res>, - material_meshes: Query<(Entity, &MeshUniform, &Handle), With>, + material_meshes: Query<(Entity, &MeshUniform, &Handle, &OutlineStencilUniform)>, mut views: Query<(&ExtractedView, &mut RenderPhase)>, ) { let draw_stencil = stencil_draw_functions @@ -44,9 +44,11 @@ pub fn queue_outline_stencil_mesh( for (view, mut stencil_phase) in views.iter_mut() { let rangefinder = view.rangefinder3d(); - for (entity, mesh_uniform, mesh_handle) in material_meshes.iter() { + for (entity, mesh_uniform, mesh_handle, stencil_uniform) in material_meshes.iter() { if let Some(mesh) = render_meshes.get(mesh_handle) { - let key = base_key.with_primitive_topology(mesh.primitive_topology); + let key = base_key + .with_primitive_topology(mesh.primitive_topology) + .with_offset_zero(stencil_uniform.offset == 0.0); let pipeline = pipelines .specialize(&mut pipeline_cache, &stencil_pipeline, key, &mesh.layout) .unwrap(); @@ -80,7 +82,13 @@ pub fn queue_outline_volume_mesh( mut pipelines: ResMut>, mut pipeline_cache: ResMut, render_meshes: Res>, - material_meshes: Query<(Entity, &MeshUniform, &Handle, &OutlineFragmentUniform)>, + material_meshes: Query<( + Entity, + &MeshUniform, + &Handle, + &OutlineVolumeUniform, + &OutlineFragmentUniform, + )>, mut views: Query<( &ExtractedView, &mut RenderPhase, @@ -100,16 +108,19 @@ pub fn queue_outline_volume_mesh( for (view, mut opaque_phase, mut transparent_phase) in views.iter_mut() { let rangefinder = view.rangefinder3d(); - for (entity, mesh_uniform, mesh_handle, outline_fragment) in material_meshes.iter() { + for (entity, mesh_uniform, mesh_handle, volume_uniform, fragment_uniform) in + material_meshes.iter() + { if let Some(mesh) = render_meshes.get(mesh_handle) { - let transparent = outline_fragment.colour[3] < 1.0; + let transparent = fragment_uniform.colour[3] < 1.0; let key = base_key .with_primitive_topology(mesh.primitive_topology) .with_pass_type(if transparent { PassType::Transparent } else { PassType::Opaque - }); + }) + .with_offset_zero(volume_uniform.offset == 0.0); let pipeline = pipelines .specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout) .unwrap(); diff --git a/src/lib.rs b/src/lib.rs index bd8f08d..e3c3ee2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,14 +67,17 @@ pub const OUTLINE_PASS_NODE_NAME: &str = "bevy_mod_outline_node"; /// A component for stenciling meshes during outline rendering. #[derive(Clone, Component, Default)] -pub struct OutlineStencil; +pub struct OutlineStencil { + /// Offset of the stencil in logical pixels + pub offset: f32, +} impl ExtractComponent for OutlineStencil { - type Query = (); - type Filter = With; + type Query = &'static OutlineStencil; + type Filter = (); - fn extract_component(_item: QueryItem) -> Self { - OutlineStencil + fn extract_component(item: QueryItem) -> Self { + item.clone() } } diff --git a/src/pipeline.rs b/src/pipeline.rs index b8f157c..63c88f9 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -49,6 +49,7 @@ impl PipelineKey { msaa_samples_minus_one, set_msaa_samples_minus_one: 5, 0; primitive_topology_int, set_primitive_topology_int: 8, 6; pass_type_int, set_pass_type_int: 10, 9; + pub offset_zero, set_offset_zero: 11; } pub fn new() -> Self { @@ -93,6 +94,11 @@ impl PipelineKey { x => panic!("Invalid value for PassType: {}", x), } } + + pub fn with_offset_zero(mut self, offset_zero: bool) -> Self { + self.set_offset_zero(offset_zero); + self + } } pub struct OutlinePipeline { @@ -200,9 +206,20 @@ impl SpecializedMeshPipeline for OutlinePipeline { }, ); bind_layouts.push(self.outline_view_bind_group_layout.clone()); + if key.offset_zero() { + vertex_defs.push("OFFSET_ZERO".to_string()); + } else { + buffer_attrs.push( + if mesh_layout.contains(ATTRIBUTE_OUTLINE_NORMAL) { + ATTRIBUTE_OUTLINE_NORMAL + } else { + Mesh::ATTRIBUTE_NORMAL + } + .at_shader_location(1), + ); + } match key.pass_type() { PassType::Stencil => { - vertex_defs.push("OFFSET_ZERO".to_string()); bind_layouts.push(self.outline_stencil_bind_group_layout.clone()); } PassType::Opaque | PassType::Transparent => { @@ -218,14 +235,6 @@ impl SpecializedMeshPipeline for OutlinePipeline { })); bind_layouts.push(self.outline_volume_bind_group_layout.clone()); - buffer_attrs.push( - if mesh_layout.contains(ATTRIBUTE_OUTLINE_NORMAL) { - ATTRIBUTE_OUTLINE_NORMAL - } else { - Mesh::ATTRIBUTE_NORMAL - } - .at_shader_location(1), - ); } } let buffers = vec![mesh_layout.get_layout(&buffer_attrs)?]; diff --git a/src/uniforms.rs b/src/uniforms.rs index b86fe01..6d931cb 100644 --- a/src/uniforms.rs +++ b/src/uniforms.rs @@ -45,12 +45,12 @@ pub struct OutlineVolumeBindGroup { pub fn extract_outline_stencil_uniforms( mut commands: Commands, - query: Extract>>, + query: Extract>, ) { - for (entity, computed) in query.iter() { + for (entity, stencil, computed) in query.iter() { commands.get_or_spawn(entity).insert(OutlineStencilUniform { origin: computed.origin, - offset: 0.0, + offset: stencil.offset, }); } }