Add non-flat depth mode.
This commit is contained in:
parent
10f2d985d3
commit
7b5650fbdb
|
@ -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;
|
||||||
|
|
20
src/draw.rs
20
src/draw.rs
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue