Add non-flat depth mode.

This commit is contained in:
Robin KAY 2023-01-03 02:06:45 +00:00
parent 10f2d985d3
commit 7b5650fbdb
5 changed files with 83 additions and 28 deletions

View File

@ -4,6 +4,7 @@ use bevy::prelude::*;
#[derive(Clone, Component, Default)] #[derive(Clone, Component, Default)]
pub struct ComputedOutlineDepth { pub struct ComputedOutlineDepth {
pub(crate) origin: Vec3, pub(crate) origin: Vec3,
pub(crate) flat: bool,
} }
/// A component which specifies how the outline depth should be computed. /// A component which specifies how the outline depth should be computed.
@ -12,6 +13,8 @@ pub struct ComputedOutlineDepth {
pub enum SetOutlineDepth { pub enum SetOutlineDepth {
/// A flat plane facing the camera and intersecting the specified point in model-space. /// A flat plane facing the camera and intersecting the specified point in model-space.
Flat { model_origin: Vec3 }, Flat { model_origin: Vec3 },
/// Real model-space.
Real,
} }
/// A component which specifies that this outline lies at the same depth as its parent. /// 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() { for (mut computed, transform, changed_transform, set_depth, children) in root_query.iter_mut() {
let mut changed = changed_transform; let mut changed = changed_transform;
if changed { 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; changed |= sd_changed;
match sd { match sd {
SetOutlineDepth::Flat { SetOutlineDepth::Flat {
model_origin: origin, model_origin: origin,
} => *origin, } => (*origin, true),
SetOutlineDepth::Real => (Vec3::NAN, false),
} }
} else { } else {
Vec3::ZERO (Vec3::ZERO, true)
}; };
let matrix = transform.compute_matrix(); let matrix = transform.compute_matrix();
computed.origin = matrix.project_point3(origin); computed.origin = matrix.project_point3(origin);
computed.flat = flat;
} }
if let Some((cs, changed_children)) = children { if let Some((cs, changed_children)) = children {
changed |= changed_children; changed |= changed_children;

View File

@ -8,8 +8,8 @@ use bevy::render::view::ExtractedView;
use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline};
use crate::pipeline::{OutlinePipeline, PassType, PipelineKey}; use crate::pipeline::{OutlinePipeline, PassType, PipelineKey};
use crate::uniforms::{ use crate::uniforms::{
OutlineFragmentUniform, OutlineStencilUniform, OutlineVolumeUniform, OutlineFragmentUniform, OutlineStencilFlags, OutlineStencilUniform, OutlineVolumeFlags,
SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup, OutlineVolumeUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup,
}; };
use crate::view_uniforms::SetOutlineViewBindGroup; use crate::view_uniforms::SetOutlineViewBindGroup;
@ -30,7 +30,12 @@ pub(crate) fn queue_outline_stencil_mesh(
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>, mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
mut pipeline_cache: ResMut<PipelineCache>, mut pipeline_cache: ResMut<PipelineCache>,
render_meshes: Res<RenderAssets<Mesh>>, render_meshes: Res<RenderAssets<Mesh>>,
material_meshes: Query<(Entity, &Handle<Mesh>, &OutlineStencilUniform)>, material_meshes: Query<(
Entity,
&Handle<Mesh>,
&OutlineStencilUniform,
&OutlineStencilFlags,
)>,
mut views: Query<(&ExtractedView, &mut RenderPhase<StencilOutline>)>, mut views: Query<(&ExtractedView, &mut RenderPhase<StencilOutline>)>,
) { ) {
let draw_stencil = stencil_draw_functions 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() { for (view, mut stencil_phase) in views.iter_mut() {
let rangefinder = view.rangefinder3d(); 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) { if let Some(mesh) = render_meshes.get(mesh_handle) {
let key = base_key let key = base_key
.with_primitive_topology(mesh.primitive_topology) .with_primitive_topology(mesh.primitive_topology)
.with_flat_depth(stencil_flags.flat_depth)
.with_offset_zero(stencil_uniform.offset == 0.0); .with_offset_zero(stencil_uniform.offset == 0.0);
let pipeline = pipelines let pipeline = pipelines
.specialize(&mut pipeline_cache, &stencil_pipeline, key, &mesh.layout) .specialize(&mut pipeline_cache, &stencil_pipeline, key, &mesh.layout)
@ -87,6 +93,7 @@ pub(crate) fn queue_outline_volume_mesh(
Entity, Entity,
&Handle<Mesh>, &Handle<Mesh>,
&OutlineVolumeUniform, &OutlineVolumeUniform,
&OutlineVolumeFlags,
&OutlineFragmentUniform, &OutlineFragmentUniform,
)>, )>,
mut views: Query<( 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() { for (view, mut opaque_phase, mut transparent_phase) in views.iter_mut() {
let rangefinder = view.rangefinder3d(); 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) { if let Some(mesh) = render_meshes.get(mesh_handle) {
let transparent = fragment_uniform.colour[3] < 1.0; let transparent = fragment_uniform.colour[3] < 1.0;
let key = base_key let key = base_key
@ -118,6 +127,7 @@ pub(crate) fn queue_outline_volume_mesh(
} else { } else {
PassType::Opaque PassType::Opaque
}) })
.with_flat_depth(volume_flags.flat_depth)
.with_offset_zero(volume_uniform.offset == 0.0); .with_offset_zero(volume_uniform.offset == 0.0);
let pipeline = pipelines let pipeline = pipelines
.specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout) .specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout)

View File

@ -60,12 +60,19 @@ fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> {
let model = mesh.model; let model = mesh.model;
#endif #endif
let clip_pos = view.view_proj * (model * vec4<f32>(vertex.position, 1.0)); let clip_pos = view.view_proj * (model * vec4<f32>(vertex.position, 1.0));
#ifdef FLAT_DEPTH
let ndc_pos = clip_pos.xy / clip_pos.w; let ndc_pos = clip_pos.xy / clip_pos.w;
let out_zw = vec2<f32>(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 #ifdef OFFSET_ZERO
let ndc_delta = vec2<f32>(0.0, 0.0); let out_xy = ndc_pos;
#else #else
let clip_norm = mat4to3(view.view_proj) * (mat4to3(model) * vertex.normal); 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 #endif
return vec4<f32>(ndc_pos + ndc_delta, model_origin_z(vstage.origin, view.view_proj), 1.0); return vec4<f32>(out_xy, out_zw);
} }

View File

@ -49,7 +49,8 @@ impl PipelineKey {
msaa_samples_minus_one, set_msaa_samples_minus_one: 5, 0; msaa_samples_minus_one, set_msaa_samples_minus_one: 5, 0;
primitive_topology_int, set_primitive_topology_int: 8, 6; primitive_topology_int, set_primitive_topology_int: 8, 6;
pass_type_int, set_pass_type_int: 10, 9; 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 { pub(crate) fn new() -> Self {
@ -99,6 +100,11 @@ impl PipelineKey {
self.set_offset_zero(offset_zero); self.set_offset_zero(offset_zero);
self self
} }
pub(crate) fn with_flat_depth(mut self, flat_depth: bool) -> Self {
self.set_flat_depth(flat_depth);
self
}
} }
#[derive(Resource)] #[derive(Resource)]
@ -207,6 +213,15 @@ impl SpecializedMeshPipeline for OutlinePipeline {
}, },
); );
bind_layouts.push(self.outline_view_bind_group_layout.clone()); 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() { if key.offset_zero() {
vertex_defs.push("OFFSET_ZERO".to_string()); vertex_defs.push("OFFSET_ZERO".to_string());
} else { } else {
@ -255,7 +270,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
layout: Some(bind_layouts), layout: Some(bind_layouts),
primitive: PrimitiveState { primitive: PrimitiveState {
front_face: FrontFace::Ccw, front_face: FrontFace::Ccw,
cull_mode: Some(Face::Back), cull_mode,
unclipped_depth: false, unclipped_depth: false,
polygon_mode: PolygonMode::Fill, polygon_mode: PolygonMode::Fill,
conservative: false, conservative: false,

View File

@ -15,19 +15,19 @@ use bevy::{
use crate::{pipeline::OutlinePipeline, ComputedOutlineDepth, OutlineStencil, OutlineVolume}; use crate::{pipeline::OutlinePipeline, ComputedOutlineDepth, OutlineStencil, OutlineVolume};
macro_rules! outline_vertex_uniform { #[derive(Clone, Component, ShaderType)]
($x:ident) => { pub(crate) struct OutlineStencilUniform {
#[derive(Clone, Component, ShaderType)]
pub(crate) struct $x {
#[align(16)] #[align(16)]
pub origin: Vec3, pub origin: Vec3,
pub offset: f32, pub offset: f32,
}
};
} }
outline_vertex_uniform!(OutlineStencilUniform); #[derive(Clone, Component, ShaderType)]
outline_vertex_uniform!(OutlineVolumeUniform); pub(crate) struct OutlineVolumeUniform {
#[align(16)]
pub origin: Vec3,
pub offset: f32,
}
#[derive(Clone, Component, ShaderType)] #[derive(Clone, Component, ShaderType)]
pub(crate) struct OutlineFragmentUniform { pub(crate) struct OutlineFragmentUniform {
@ -35,6 +35,16 @@ pub(crate) struct OutlineFragmentUniform {
pub colour: Vec4, 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)] #[derive(Resource)]
pub(crate) struct OutlineStencilBindGroup { pub(crate) struct OutlineStencilBindGroup {
pub bind_group: BindGroup, pub bind_group: BindGroup,
@ -50,9 +60,14 @@ pub(crate) fn extract_outline_stencil_uniforms(
query: Extract<Query<(Entity, &OutlineStencil, &ComputedOutlineDepth)>>, query: Extract<Query<(Entity, &OutlineStencil, &ComputedOutlineDepth)>>,
) { ) {
for (entity, stencil, computed) in query.iter() { for (entity, stencil, computed) in query.iter() {
commands.get_or_spawn(entity).insert(OutlineStencilUniform { commands
.get_or_spawn(entity)
.insert(OutlineStencilUniform {
origin: computed.origin, origin: computed.origin,
offset: stencil.offset, offset: stencil.offset,
})
.insert(OutlineStencilFlags {
flat_depth: computed.flat,
}); });
} }
} }
@ -73,6 +88,9 @@ pub(crate) fn extract_outline_volume_uniforms(
}) })
.insert(OutlineFragmentUniform { .insert(OutlineFragmentUniform {
colour: outline.colour.as_linear_rgba_f32().into(), colour: outline.colour.as_linear_rgba_f32().into(),
})
.insert(OutlineVolumeFlags {
flat_depth: computed.flat,
}); });
} }
} }