From 7b5650fbdbcc35dd077285cec76565088d80ef18 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Tue, 3 Jan 2023 02:06:45 +0000 Subject: [PATCH] Add non-flat depth mode. --- src/computed.rs | 11 ++++++++--- src/draw.rs | 20 +++++++++++++++----- src/outline.wgsl | 13 ++++++++++--- src/pipeline.rs | 19 +++++++++++++++++-- src/uniforms.rs | 48 +++++++++++++++++++++++++++++++++--------------- 5 files changed, 83 insertions(+), 28 deletions(-) diff --git a/src/computed.rs b/src/computed.rs index 4a8c3b3..9655fd2 100644 --- a/src/computed.rs +++ b/src/computed.rs @@ -4,6 +4,7 @@ use bevy::prelude::*; #[derive(Clone, Component, Default)] pub struct ComputedOutlineDepth { pub(crate) origin: Vec3, + pub(crate) flat: bool, } /// A component which specifies how the outline depth should be computed. @@ -12,6 +13,8 @@ pub struct ComputedOutlineDepth { pub enum SetOutlineDepth { /// A flat plane facing the camera and intersecting the specified point in model-space. Flat { model_origin: Vec3 }, + /// Real model-space. + Real, } /// A component which specifies that this outline lies at the same depth as its parent. @@ -36,18 +39,20 @@ pub(crate) fn compute_outline_depth( for (mut computed, transform, changed_transform, set_depth, children) in root_query.iter_mut() { let mut changed = changed_transform; if changed { - let origin = if let Some((sd, sd_changed)) = set_depth { + let (origin, flat) = if let Some((sd, sd_changed)) = set_depth { changed |= sd_changed; match sd { SetOutlineDepth::Flat { model_origin: origin, - } => *origin, + } => (*origin, true), + SetOutlineDepth::Real => (Vec3::NAN, false), } } else { - Vec3::ZERO + (Vec3::ZERO, true) }; let matrix = transform.compute_matrix(); computed.origin = matrix.project_point3(origin); + computed.flat = flat; } if let Some((cs, changed_children)) = children { changed |= changed_children; diff --git a/src/draw.rs b/src/draw.rs index 39fe7cc..c0cac71 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -8,8 +8,8 @@ use bevy::render::view::ExtractedView; use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; use crate::pipeline::{OutlinePipeline, PassType, PipelineKey}; use crate::uniforms::{ - OutlineFragmentUniform, OutlineStencilUniform, OutlineVolumeUniform, - SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup, + OutlineFragmentUniform, OutlineStencilFlags, OutlineStencilUniform, OutlineVolumeFlags, + OutlineVolumeUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup, }; use crate::view_uniforms::SetOutlineViewBindGroup; @@ -30,7 +30,12 @@ pub(crate) fn queue_outline_stencil_mesh( mut pipelines: ResMut>, mut pipeline_cache: ResMut, render_meshes: Res>, - material_meshes: Query<(Entity, &Handle, &OutlineStencilUniform)>, + material_meshes: Query<( + Entity, + &Handle, + &OutlineStencilUniform, + &OutlineStencilFlags, + )>, mut views: Query<(&ExtractedView, &mut RenderPhase)>, ) { let draw_stencil = stencil_draw_functions @@ -44,10 +49,11 @@ pub(crate) fn queue_outline_stencil_mesh( for (view, mut stencil_phase) in views.iter_mut() { let rangefinder = view.rangefinder3d(); - for (entity, mesh_handle, stencil_uniform) in material_meshes.iter() { + for (entity, mesh_handle, stencil_uniform, stencil_flags) in material_meshes.iter() { if let Some(mesh) = render_meshes.get(mesh_handle) { let key = base_key .with_primitive_topology(mesh.primitive_topology) + .with_flat_depth(stencil_flags.flat_depth) .with_offset_zero(stencil_uniform.offset == 0.0); let pipeline = pipelines .specialize(&mut pipeline_cache, &stencil_pipeline, key, &mesh.layout) @@ -87,6 +93,7 @@ pub(crate) fn queue_outline_volume_mesh( Entity, &Handle, &OutlineVolumeUniform, + &OutlineVolumeFlags, &OutlineFragmentUniform, )>, mut views: Query<( @@ -108,7 +115,9 @@ pub(crate) fn queue_outline_volume_mesh( for (view, mut opaque_phase, mut transparent_phase) in views.iter_mut() { let rangefinder = view.rangefinder3d(); - for (entity, mesh_handle, volume_uniform, fragment_uniform) in material_meshes.iter() { + for (entity, mesh_handle, volume_uniform, volume_flags, fragment_uniform) in + material_meshes.iter() + { if let Some(mesh) = render_meshes.get(mesh_handle) { let transparent = fragment_uniform.colour[3] < 1.0; let key = base_key @@ -118,6 +127,7 @@ pub(crate) fn queue_outline_volume_mesh( } else { PassType::Opaque }) + .with_flat_depth(volume_flags.flat_depth) .with_offset_zero(volume_uniform.offset == 0.0); let pipeline = pipelines .specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout) diff --git a/src/outline.wgsl b/src/outline.wgsl index 29f8d61..a29e493 100644 --- a/src/outline.wgsl +++ b/src/outline.wgsl @@ -60,12 +60,19 @@ fn vertex(vertex: VertexInput) -> @builtin(position) vec4 { let model = mesh.model; #endif let clip_pos = view.view_proj * (model * vec4(vertex.position, 1.0)); +#ifdef FLAT_DEPTH let ndc_pos = clip_pos.xy / clip_pos.w; + let out_zw = vec2(model_origin_z(vstage.origin, view.view_proj), 1.0); +#else + let ndc_pos = clip_pos.xy; + let out_zw = clip_pos.zw; +#endif #ifdef OFFSET_ZERO - let ndc_delta = vec2(0.0, 0.0); + let out_xy = ndc_pos; #else let clip_norm = mat4to3(view.view_proj) * (mat4to3(model) * vertex.normal); - let ndc_delta = vstage.offset * normalize(clip_norm.xy) * view_uniform.scale; + let ndc_delta = vstage.offset * normalize(clip_norm.xy) * view_uniform.scale * out_zw.y; + let out_xy = ndc_pos + ndc_delta; #endif - return vec4(ndc_pos + ndc_delta, model_origin_z(vstage.origin, view.view_proj), 1.0); + return vec4(out_xy, out_zw); } diff --git a/src/pipeline.rs b/src/pipeline.rs index 9369df1..cb119b8 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -49,7 +49,8 @@ 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 flat_depth, set_flat_depth: 11; + pub offset_zero, set_offset_zero: 12; } pub(crate) fn new() -> Self { @@ -99,6 +100,11 @@ impl PipelineKey { self.set_offset_zero(offset_zero); self } + + pub(crate) fn with_flat_depth(mut self, flat_depth: bool) -> Self { + self.set_flat_depth(flat_depth); + self + } } #[derive(Resource)] @@ -207,6 +213,15 @@ impl SpecializedMeshPipeline for OutlinePipeline { }, ); bind_layouts.push(self.outline_view_bind_group_layout.clone()); + let cull_mode; + if key.flat_depth() { + vertex_defs.push("FLAT_DEPTH".to_string()); + cull_mode = Some(Face::Back); + } else if key.pass_type() == PassType::Stencil { + cull_mode = Some(Face::Back); + } else { + cull_mode = Some(Face::Front); + } if key.offset_zero() { vertex_defs.push("OFFSET_ZERO".to_string()); } else { @@ -255,7 +270,7 @@ impl SpecializedMeshPipeline for OutlinePipeline { layout: Some(bind_layouts), primitive: PrimitiveState { front_face: FrontFace::Ccw, - cull_mode: Some(Face::Back), + cull_mode, unclipped_depth: false, polygon_mode: PolygonMode::Fill, conservative: false, diff --git a/src/uniforms.rs b/src/uniforms.rs index 53b55b3..cf1efbb 100644 --- a/src/uniforms.rs +++ b/src/uniforms.rs @@ -15,19 +15,19 @@ use bevy::{ use crate::{pipeline::OutlinePipeline, ComputedOutlineDepth, OutlineStencil, OutlineVolume}; -macro_rules! outline_vertex_uniform { - ($x:ident) => { - #[derive(Clone, Component, ShaderType)] - pub(crate) struct $x { - #[align(16)] - pub origin: Vec3, - pub offset: f32, - } - }; +#[derive(Clone, Component, ShaderType)] +pub(crate) struct OutlineStencilUniform { + #[align(16)] + pub origin: Vec3, + pub offset: f32, } -outline_vertex_uniform!(OutlineStencilUniform); -outline_vertex_uniform!(OutlineVolumeUniform); +#[derive(Clone, Component, ShaderType)] +pub(crate) struct OutlineVolumeUniform { + #[align(16)] + pub origin: Vec3, + pub offset: f32, +} #[derive(Clone, Component, ShaderType)] pub(crate) struct OutlineFragmentUniform { @@ -35,6 +35,16 @@ pub(crate) struct OutlineFragmentUniform { pub colour: Vec4, } +#[derive(Component)] +pub(crate) struct OutlineStencilFlags { + pub flat_depth: bool, +} + +#[derive(Component)] +pub(crate) struct OutlineVolumeFlags { + pub flat_depth: bool, +} + #[derive(Resource)] pub(crate) struct OutlineStencilBindGroup { pub bind_group: BindGroup, @@ -50,10 +60,15 @@ pub(crate) fn extract_outline_stencil_uniforms( query: Extract>, ) { for (entity, stencil, computed) in query.iter() { - commands.get_or_spawn(entity).insert(OutlineStencilUniform { - origin: computed.origin, - offset: stencil.offset, - }); + commands + .get_or_spawn(entity) + .insert(OutlineStencilUniform { + origin: computed.origin, + offset: stencil.offset, + }) + .insert(OutlineStencilFlags { + flat_depth: computed.flat, + }); } } @@ -73,6 +88,9 @@ pub(crate) fn extract_outline_volume_uniforms( }) .insert(OutlineFragmentUniform { colour: outline.colour.as_linear_rgba_f32().into(), + }) + .insert(OutlineVolumeFlags { + flat_depth: computed.flat, }); } }