Change outline and stencil properties to be inheritable.
This commit is contained in:
parent
65c7c3356f
commit
600f58ba73
@ -6,7 +6,8 @@ use bevy::{
|
|||||||
window::close_on_esc,
|
window::close_on_esc,
|
||||||
};
|
};
|
||||||
use bevy_mod_outline::{
|
use bevy_mod_outline::{
|
||||||
AutoGenerateOutlineNormalsPlugin, OutlineBundle, OutlinePlugin, OutlineVolume,
|
AutoGenerateOutlineNormalsPlugin, InheritOutlineBundle, OutlineBundle, OutlinePlugin,
|
||||||
|
OutlineVolume,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
@ -65,9 +66,18 @@ fn setup(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Fox
|
// Fox
|
||||||
commands.spawn(SceneBundle {
|
commands
|
||||||
|
.spawn(SceneBundle {
|
||||||
scene: asset_server.load("Fox.glb#Scene0"),
|
scene: asset_server.load("Fox.glb#Scene0"),
|
||||||
..default()
|
..default()
|
||||||
|
})
|
||||||
|
.insert(OutlineBundle {
|
||||||
|
outline: OutlineVolume {
|
||||||
|
visible: true,
|
||||||
|
width: 3.0,
|
||||||
|
colour: Color::RED,
|
||||||
|
},
|
||||||
|
..default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,14 +96,9 @@ fn setup_scene_once_loaded(
|
|||||||
{
|
{
|
||||||
if scene_manager.instance_is_ready(**scene) {
|
if scene_manager.instance_is_ready(**scene) {
|
||||||
for entity in scene_manager.iter_instance_entities(**scene) {
|
for entity in scene_manager.iter_instance_entities(**scene) {
|
||||||
commands.entity(entity).insert(OutlineBundle {
|
commands
|
||||||
outline: OutlineVolume {
|
.entity(entity)
|
||||||
visible: true,
|
.insert(InheritOutlineBundle::default());
|
||||||
width: 3.0,
|
|
||||||
colour: Color::RED,
|
|
||||||
},
|
|
||||||
..default()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
player.play(animation.0.clone_weak()).repeat();
|
player.play(animation.0.clone_weak()).repeat();
|
||||||
*done = true;
|
*done = true;
|
||||||
|
@ -56,7 +56,18 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.insert(Rotates)
|
.insert(Rotates)
|
||||||
.insert(ComputedOutlineDepth::default());
|
.insert(OutlineBundle {
|
||||||
|
outline: OutlineVolume {
|
||||||
|
visible: true,
|
||||||
|
width: 7.5,
|
||||||
|
colour: Color::BLUE,
|
||||||
|
},
|
||||||
|
stencil: OutlineStencil {
|
||||||
|
enabled: true,
|
||||||
|
offset: 0.0,
|
||||||
|
},
|
||||||
|
..default()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Once the scene is loaded, start the animation and add an outline
|
// Once the scene is loaded, start the animation and add an outline
|
||||||
@ -73,19 +84,7 @@ fn setup_scene_once_loaded(
|
|||||||
for entity in scene_manager.iter_instance_entities(**scene) {
|
for entity in scene_manager.iter_instance_entities(**scene) {
|
||||||
commands
|
commands
|
||||||
.entity(entity)
|
.entity(entity)
|
||||||
.insert(OutlineBundle {
|
.insert(InheritOutlineBundle::default());
|
||||||
outline: OutlineVolume {
|
|
||||||
visible: true,
|
|
||||||
width: 7.5,
|
|
||||||
colour: Color::BLUE,
|
|
||||||
},
|
|
||||||
stencil: OutlineStencil {
|
|
||||||
enabled: true,
|
|
||||||
offset: 0.0,
|
|
||||||
},
|
|
||||||
..default()
|
|
||||||
})
|
|
||||||
.insert(InheritOutlineDepth);
|
|
||||||
if let Ok(name) = name_query.get(entity) {
|
if let Ok(name) = name_query.get(entity) {
|
||||||
if name.as_str() == "inside" {
|
if name.as_str() == "inside" {
|
||||||
commands.entity(entity).insert(RotatesHue);
|
commands.entity(entity).insert(RotatesHue);
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
use bevy::{prelude::*, scene::SceneInstance};
|
use bevy::{prelude::*, scene::SceneInstance};
|
||||||
use bevy_mod_outline::{
|
use bevy_mod_outline::{
|
||||||
AutoGenerateOutlineNormalsPlugin, OutlineBundle, OutlinePlugin, OutlineVolume,
|
AutoGenerateOutlineNormalsPlugin, InheritOutlineBundle, OutlineBundle, OutlinePlugin,
|
||||||
|
OutlineVolume,
|
||||||
};
|
};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
@ -46,9 +47,18 @@ fn setup(asset_server: Res<AssetServer>, mut commands: Commands) {
|
|||||||
the_wave: asset_server.load("MorphStressTest.gltf#Animation2"),
|
the_wave: asset_server.load("MorphStressTest.gltf#Animation2"),
|
||||||
mesh: asset_server.load("MorphStressTest.gltf#Mesh0/Primitive0"),
|
mesh: asset_server.load("MorphStressTest.gltf#Mesh0/Primitive0"),
|
||||||
});
|
});
|
||||||
commands.spawn(SceneBundle {
|
commands
|
||||||
|
.spawn(SceneBundle {
|
||||||
scene: asset_server.load("MorphStressTest.gltf#Scene0"),
|
scene: asset_server.load("MorphStressTest.gltf#Scene0"),
|
||||||
..default()
|
..default()
|
||||||
|
})
|
||||||
|
.insert(OutlineBundle {
|
||||||
|
outline: OutlineVolume {
|
||||||
|
visible: true,
|
||||||
|
width: 3.0,
|
||||||
|
colour: Color::RED,
|
||||||
|
},
|
||||||
|
..default()
|
||||||
});
|
});
|
||||||
commands.spawn(DirectionalLightBundle {
|
commands.spawn(DirectionalLightBundle {
|
||||||
directional_light: DirectionalLight {
|
directional_light: DirectionalLight {
|
||||||
@ -78,14 +88,9 @@ fn setup_outlines(
|
|||||||
if let Ok(scene) = scene_query.get_single() {
|
if let Ok(scene) = scene_query.get_single() {
|
||||||
if scene_manager.instance_is_ready(**scene) {
|
if scene_manager.instance_is_ready(**scene) {
|
||||||
for entity in scene_manager.iter_instance_entities(**scene) {
|
for entity in scene_manager.iter_instance_entities(**scene) {
|
||||||
commands.entity(entity).insert(OutlineBundle {
|
commands
|
||||||
outline: OutlineVolume {
|
.entity(entity)
|
||||||
visible: true,
|
.insert(InheritOutlineBundle::default());
|
||||||
width: 3.0,
|
|
||||||
colour: Color::RED,
|
|
||||||
},
|
|
||||||
..default()
|
|
||||||
});
|
|
||||||
*has_setup = true;
|
*has_setup = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,19 +29,6 @@ fn setup(
|
|||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
) {
|
) {
|
||||||
let outline = OutlineBundle {
|
|
||||||
outline: OutlineVolume {
|
|
||||||
visible: true,
|
|
||||||
colour: Color::WHITE,
|
|
||||||
width: 10.0,
|
|
||||||
},
|
|
||||||
stencil: OutlineStencil {
|
|
||||||
offset: 5.0,
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
..default()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add sphere with child meshes sticking out of it
|
// Add sphere with child meshes sticking out of it
|
||||||
commands
|
commands
|
||||||
.spawn(PbrBundle {
|
.spawn(PbrBundle {
|
||||||
@ -57,7 +44,18 @@ fn setup(
|
|||||||
transform: Transform::from_translation(Vec3::new(0.0, 1.0, 0.0)),
|
transform: Transform::from_translation(Vec3::new(0.0, 1.0, 0.0)),
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.insert(outline.clone())
|
.insert(OutlineBundle {
|
||||||
|
outline: OutlineVolume {
|
||||||
|
visible: true,
|
||||||
|
colour: Color::WHITE,
|
||||||
|
width: 10.0,
|
||||||
|
},
|
||||||
|
stencil: OutlineStencil {
|
||||||
|
offset: 5.0,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
..default()
|
||||||
|
})
|
||||||
.insert(Rotates)
|
.insert(Rotates)
|
||||||
.with_children(|parent| {
|
.with_children(|parent| {
|
||||||
parent
|
parent
|
||||||
@ -78,8 +76,7 @@ fn setup(
|
|||||||
.with_translation(Vec3::new(0.0, 0.0, 0.75)),
|
.with_translation(Vec3::new(0.0, 0.0, 0.75)),
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.insert(outline.clone())
|
.insert(InheritOutlineBundle::default());
|
||||||
.insert(InheritOutlineDepth);
|
|
||||||
parent
|
parent
|
||||||
.spawn(PbrBundle {
|
.spawn(PbrBundle {
|
||||||
mesh: meshes.add(
|
mesh: meshes.add(
|
||||||
@ -96,8 +93,7 @@ fn setup(
|
|||||||
.with_translation(Vec3::new(0.0, 0.0, -0.75)),
|
.with_translation(Vec3::new(0.0, 0.0, -0.75)),
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.insert(outline.clone())
|
.insert(InheritOutlineBundle::default());
|
||||||
.insert(InheritOutlineDepth);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add plane, light source, and camera
|
// Add plane, light source, and camera
|
||||||
|
232
src/computed.rs
232
src/computed.rs
@ -1,76 +1,113 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::{ecs::query::QueryItem, prelude::*};
|
||||||
|
|
||||||
use crate::uniforms::DepthMode;
|
use crate::{uniforms::DepthMode, InheritOutline, OutlineMode, OutlineStencil, OutlineVolume};
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub(crate) struct ComputedVolume {
|
||||||
|
pub(crate) enabled: bool,
|
||||||
|
pub(crate) offset: f32,
|
||||||
|
pub(crate) colour: Vec4,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub(crate) struct ComputedStencil {
|
||||||
|
pub(crate) enabled: bool,
|
||||||
|
pub(crate) offset: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct ComputedMode {
|
||||||
|
pub(crate) world_origin: Vec3,
|
||||||
|
pub(crate) depth_mode: DepthMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ComputedMode {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
world_origin: Vec3::NAN,
|
||||||
|
depth_mode: DepthMode::Real,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
pub(crate) enum Source {
|
||||||
|
#[default]
|
||||||
|
Set,
|
||||||
|
Inherited,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub(crate) struct Sourced<T: Clone + Default> {
|
||||||
|
pub(crate) value: T,
|
||||||
|
pub(crate) source: Source,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone + Default> Sourced<T> {
|
||||||
|
pub fn inherit(value: &T) -> Self {
|
||||||
|
Sourced {
|
||||||
|
value: value.clone(),
|
||||||
|
source: Source::Inherited,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(value: T) -> Self {
|
||||||
|
Sourced {
|
||||||
|
value,
|
||||||
|
source: Source::Set,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_changed<U: Component>(&self, tuple: Option<(&U, bool)>) -> bool {
|
||||||
|
tuple.is_some() != matches!(self.source, Source::Set)
|
||||||
|
|| if let Some((_, c)) = tuple { c } else { false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub(crate) struct ComputedInternal {
|
||||||
|
pub(crate) inherited_from: Option<Entity>,
|
||||||
|
pub(crate) volume: Sourced<ComputedVolume>,
|
||||||
|
pub(crate) stencil: Sourced<ComputedStencil>,
|
||||||
|
pub(crate) mode: Sourced<ComputedMode>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A component for storing the computed depth at which the outline lies.
|
/// A component for storing the computed depth at which the outline lies.
|
||||||
#[derive(Clone, Component, Default)]
|
#[derive(Clone, Component, Default)]
|
||||||
pub struct ComputedOutlineDepth {
|
pub struct ComputedOutline(pub(crate) Option<ComputedInternal>);
|
||||||
pub(crate) world_origin: Vec3,
|
|
||||||
pub(crate) depth_mode: DepthMode,
|
|
||||||
pub(crate) inherited: Option<Entity>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A component which specifies how the outline depth should be computed.
|
type OutlineComponents<'a> = (
|
||||||
#[derive(Clone, Component)]
|
(&'a GlobalTransform, Changed<GlobalTransform>),
|
||||||
#[non_exhaustive]
|
Option<(&'a OutlineVolume, Changed<OutlineVolume>)>,
|
||||||
pub enum SetOutlineDepth {
|
Option<(&'a OutlineStencil, Changed<OutlineStencil>)>,
|
||||||
/// A flat plane facing the camera and intersecting the specified point in model-space.
|
Option<(&'a OutlineMode, Changed<OutlineMode>)>,
|
||||||
Flat { model_origin: Vec3 },
|
);
|
||||||
/// Real model-space.
|
|
||||||
Real,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A component which specifies that this outline lies at the same depth as its parent.
|
|
||||||
#[derive(Clone, Component, Default)]
|
|
||||||
pub struct InheritOutlineDepth;
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub(crate) fn compute_outline_depth(
|
pub(crate) fn compute_outline(
|
||||||
mut root_query: Query<
|
mut root_query: Query<
|
||||||
(
|
(
|
||||||
Entity,
|
Entity,
|
||||||
&mut ComputedOutlineDepth,
|
&mut ComputedOutline,
|
||||||
&GlobalTransform,
|
OutlineComponents,
|
||||||
Changed<GlobalTransform>,
|
|
||||||
Option<(&SetOutlineDepth, Changed<SetOutlineDepth>)>,
|
|
||||||
Option<&Children>,
|
Option<&Children>,
|
||||||
),
|
),
|
||||||
Without<InheritOutlineDepth>,
|
Without<InheritOutline>,
|
||||||
>,
|
>,
|
||||||
mut computed_query: Query<&mut ComputedOutlineDepth, With<InheritOutlineDepth>>,
|
mut child_query_mut: Query<(&mut ComputedOutline, OutlineComponents), With<InheritOutline>>,
|
||||||
child_query: Query<&Children>,
|
child_query: Query<&Children>,
|
||||||
) {
|
) {
|
||||||
for (entity, mut computed, transform, changed_transform, set_depth, children) in
|
for (entity, mut computed, components, children) in root_query.iter_mut() {
|
||||||
root_query.iter_mut()
|
let changed = update_computed_outline(&mut computed, components, &default(), None, false);
|
||||||
{
|
|
||||||
let changed = !computed.depth_mode.is_valid()
|
|
||||||
|| computed.inherited.is_some()
|
|
||||||
|| changed_transform
|
|
||||||
|| set_depth.filter(|(_, c)| *c).is_some();
|
|
||||||
if changed {
|
|
||||||
let (origin, depth_mode) = if let Some((sd, _)) = set_depth {
|
|
||||||
match sd {
|
|
||||||
SetOutlineDepth::Flat {
|
|
||||||
model_origin: origin,
|
|
||||||
} => (*origin, DepthMode::Flat),
|
|
||||||
SetOutlineDepth::Real => (Vec3::NAN, DepthMode::Real),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(Vec3::ZERO, DepthMode::Flat)
|
|
||||||
};
|
|
||||||
let matrix = transform.compute_matrix();
|
|
||||||
computed.world_origin = matrix.project_point3(origin);
|
|
||||||
computed.depth_mode = depth_mode;
|
|
||||||
computed.inherited = None;
|
|
||||||
}
|
|
||||||
if let Some(cs) = children {
|
if let Some(cs) = children {
|
||||||
|
let parent_computed = &computed.0.as_ref().unwrap().clone();
|
||||||
for child in cs.iter() {
|
for child in cs.iter() {
|
||||||
propagate_outline_depth(
|
propagate_computed_outline(
|
||||||
&computed,
|
parent_computed,
|
||||||
changed,
|
changed,
|
||||||
entity,
|
entity,
|
||||||
*child,
|
*child,
|
||||||
&mut computed_query,
|
&mut child_query_mut,
|
||||||
&child_query,
|
&child_query,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -78,31 +115,92 @@ pub(crate) fn compute_outline_depth(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_outline_depth(
|
fn propagate_computed_outline(
|
||||||
root_computed: &ComputedOutlineDepth,
|
parent_computed: &ComputedInternal,
|
||||||
mut changed: bool,
|
parent_changed: bool,
|
||||||
parent: Entity,
|
parent_entity: Entity,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
computed_query: &mut Query<&mut ComputedOutlineDepth, With<InheritOutlineDepth>>,
|
child_query_mut: &mut Query<(&mut ComputedOutline, OutlineComponents), With<InheritOutline>>,
|
||||||
child_query: &Query<&Children>,
|
child_query: &Query<&Children>,
|
||||||
) {
|
) {
|
||||||
if let Ok(mut computed) = computed_query.get_mut(entity) {
|
if let Ok((mut computed, components)) = child_query_mut.get_mut(entity) {
|
||||||
changed |= !computed.depth_mode.is_valid() | (computed.inherited != Some(parent));
|
let changed = update_computed_outline(
|
||||||
if changed {
|
&mut computed,
|
||||||
*computed = root_computed.clone();
|
components,
|
||||||
computed.inherited = Some(parent);
|
parent_computed,
|
||||||
}
|
Some(parent_entity),
|
||||||
|
parent_changed,
|
||||||
|
);
|
||||||
if let Ok(cs) = child_query.get(entity) {
|
if let Ok(cs) = child_query.get(entity) {
|
||||||
|
let parent_computed = &computed.0.as_ref().unwrap().clone();
|
||||||
for child in cs.iter() {
|
for child in cs.iter() {
|
||||||
propagate_outline_depth(
|
propagate_computed_outline(
|
||||||
root_computed,
|
parent_computed,
|
||||||
changed,
|
changed,
|
||||||
entity,
|
entity,
|
||||||
*child,
|
*child,
|
||||||
computed_query,
|
child_query_mut,
|
||||||
child_query,
|
child_query,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_computed_outline(
|
||||||
|
computed: &mut ComputedOutline,
|
||||||
|
((transform, changed_transform), volume, stencil, mode): QueryItem<'_, OutlineComponents>,
|
||||||
|
parent_computed: &ComputedInternal,
|
||||||
|
parent_entity: Option<Entity>,
|
||||||
|
force_update: bool,
|
||||||
|
) -> bool {
|
||||||
|
let changed = force_update
|
||||||
|
|| if let ComputedOutline(Some(computed)) = computed {
|
||||||
|
computed.inherited_from != parent_entity
|
||||||
|
|| (changed_transform && matches!(mode, Some((OutlineMode::FlatVertex { .. }, _))))
|
||||||
|
|| computed.volume.is_changed(volume)
|
||||||
|
|| computed.stencil.is_changed(stencil)
|
||||||
|
|| computed.mode.is_changed(mode)
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
if changed {
|
||||||
|
*computed = ComputedOutline(Some(ComputedInternal {
|
||||||
|
inherited_from: parent_entity,
|
||||||
|
volume: if let Some((vol, _)) = volume {
|
||||||
|
Sourced::set(ComputedVolume {
|
||||||
|
enabled: vol.visible && vol.colour.a() != 0.0,
|
||||||
|
offset: vol.width,
|
||||||
|
colour: vol.colour.into(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Sourced::inherit(&parent_computed.volume.value)
|
||||||
|
},
|
||||||
|
stencil: if let Some((sten, _)) = stencil {
|
||||||
|
Sourced::set(ComputedStencil {
|
||||||
|
enabled: sten.enabled,
|
||||||
|
offset: sten.offset,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Sourced::inherit(&parent_computed.stencil.value)
|
||||||
|
},
|
||||||
|
mode: if let Some((m, _)) = mode {
|
||||||
|
Sourced::set(match m {
|
||||||
|
OutlineMode::FlatVertex {
|
||||||
|
model_origin: origin,
|
||||||
|
} => ComputedMode {
|
||||||
|
world_origin: transform.compute_matrix().project_point3(*origin),
|
||||||
|
depth_mode: DepthMode::Flat,
|
||||||
|
},
|
||||||
|
OutlineMode::RealVertex => ComputedMode {
|
||||||
|
world_origin: Vec3::NAN,
|
||||||
|
depth_mode: DepthMode::Real,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Sourced::inherit(&parent_computed.mode.value)
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
}
|
||||||
|
31
src/draw.rs
31
src/draw.rs
@ -8,9 +8,8 @@ use bevy::render::view::{ExtractedView, RenderLayers};
|
|||||||
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::{
|
||||||
DepthMode, OutlineFragmentUniform, OutlineStencilFlags, OutlineStencilUniform,
|
ExtractedOutline, OutlineFragmentUniform, OutlineStencilUniform, OutlineVolumeUniform,
|
||||||
OutlineVolumeFlags, OutlineVolumeUniform, SetOutlineStencilBindGroup,
|
SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup,
|
||||||
SetOutlineVolumeBindGroup,
|
|
||||||
};
|
};
|
||||||
use crate::view_uniforms::SetOutlineViewBindGroup;
|
use crate::view_uniforms::SetOutlineViewBindGroup;
|
||||||
use crate::OutlineRenderLayers;
|
use crate::OutlineRenderLayers;
|
||||||
@ -34,9 +33,8 @@ pub(crate) fn queue_outline_stencil_mesh(
|
|||||||
render_meshes: Res<RenderAssets<Mesh>>,
|
render_meshes: Res<RenderAssets<Mesh>>,
|
||||||
material_meshes: Query<(
|
material_meshes: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&Handle<Mesh>,
|
|
||||||
&OutlineStencilUniform,
|
&OutlineStencilUniform,
|
||||||
&OutlineStencilFlags,
|
&ExtractedOutline,
|
||||||
&OutlineRenderLayers,
|
&OutlineRenderLayers,
|
||||||
)>,
|
)>,
|
||||||
mut views: Query<(
|
mut views: Query<(
|
||||||
@ -57,21 +55,16 @@ pub(crate) fn queue_outline_stencil_mesh(
|
|||||||
for (view, mut stencil_phase, view_mask) in views.iter_mut() {
|
for (view, mut stencil_phase, view_mask) in views.iter_mut() {
|
||||||
let rangefinder = view.rangefinder3d();
|
let rangefinder = view.rangefinder3d();
|
||||||
let view_mask = view_mask.copied().unwrap_or_default();
|
let view_mask = view_mask.copied().unwrap_or_default();
|
||||||
for (entity, mesh_handle, stencil_uniform, stencil_flags, outline_mask) in
|
for (entity, stencil_uniform, outline, outline_mask) in material_meshes.iter() {
|
||||||
material_meshes.iter()
|
|
||||||
{
|
|
||||||
if !view_mask.intersects(outline_mask) {
|
if !view_mask.intersects(outline_mask) {
|
||||||
continue; // Layer not enabled
|
continue; // Layer not enabled
|
||||||
}
|
}
|
||||||
if stencil_flags.depth_mode == DepthMode::Invalid {
|
let Some(mesh) = render_meshes.get(&outline.mesh) else {
|
||||||
continue; // DepthMode not propagated
|
|
||||||
}
|
|
||||||
let Some(mesh) = render_meshes.get(mesh_handle) else {
|
|
||||||
continue; // No mesh
|
continue; // No mesh
|
||||||
};
|
};
|
||||||
let key = base_key
|
let key = base_key
|
||||||
.with_primitive_topology(mesh.primitive_topology)
|
.with_primitive_topology(mesh.primitive_topology)
|
||||||
.with_depth_mode(stencil_flags.depth_mode)
|
.with_depth_mode(outline.depth_mode)
|
||||||
.with_offset_zero(stencil_uniform.offset == 0.0)
|
.with_offset_zero(stencil_uniform.offset == 0.0)
|
||||||
.with_morph_targets(mesh.morph_targets.is_some());
|
.with_morph_targets(mesh.morph_targets.is_some());
|
||||||
let Ok(pipeline) =
|
let Ok(pipeline) =
|
||||||
@ -110,9 +103,8 @@ pub(crate) fn queue_outline_volume_mesh(
|
|||||||
render_meshes: Res<RenderAssets<Mesh>>,
|
render_meshes: Res<RenderAssets<Mesh>>,
|
||||||
material_meshes: Query<(
|
material_meshes: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&Handle<Mesh>,
|
|
||||||
&OutlineVolumeUniform,
|
&OutlineVolumeUniform,
|
||||||
&OutlineVolumeFlags,
|
&ExtractedOutline,
|
||||||
&OutlineFragmentUniform,
|
&OutlineFragmentUniform,
|
||||||
&OutlineRenderLayers,
|
&OutlineRenderLayers,
|
||||||
)>,
|
)>,
|
||||||
@ -137,16 +129,13 @@ pub(crate) fn queue_outline_volume_mesh(
|
|||||||
for (view, mut opaque_phase, mut transparent_phase, view_mask) in views.iter_mut() {
|
for (view, mut opaque_phase, mut transparent_phase, view_mask) in views.iter_mut() {
|
||||||
let view_mask = view_mask.copied().unwrap_or_default();
|
let view_mask = view_mask.copied().unwrap_or_default();
|
||||||
let rangefinder = view.rangefinder3d();
|
let rangefinder = view.rangefinder3d();
|
||||||
for (entity, mesh_handle, volume_uniform, volume_flags, fragment_uniform, outline_mask) in
|
for (entity, volume_uniform, outline, fragment_uniform, outline_mask) in
|
||||||
material_meshes.iter()
|
material_meshes.iter()
|
||||||
{
|
{
|
||||||
if !view_mask.intersects(outline_mask) {
|
if !view_mask.intersects(outline_mask) {
|
||||||
continue; // Layer not enabled
|
continue; // Layer not enabled
|
||||||
}
|
}
|
||||||
if volume_flags.depth_mode == DepthMode::Invalid {
|
let Some(mesh) = render_meshes.get(&outline.mesh) else {
|
||||||
continue; // DepthMode not propagated
|
|
||||||
}
|
|
||||||
let Some(mesh) = render_meshes.get(mesh_handle) else {
|
|
||||||
continue; // No mesh
|
continue; // No mesh
|
||||||
};
|
};
|
||||||
let transparent = fragment_uniform.colour[3] < 1.0;
|
let transparent = fragment_uniform.colour[3] < 1.0;
|
||||||
@ -157,7 +146,7 @@ pub(crate) fn queue_outline_volume_mesh(
|
|||||||
} else {
|
} else {
|
||||||
PassType::Opaque
|
PassType::Opaque
|
||||||
})
|
})
|
||||||
.with_depth_mode(volume_flags.depth_mode)
|
.with_depth_mode(outline.depth_mode)
|
||||||
.with_offset_zero(volume_uniform.offset == 0.0)
|
.with_offset_zero(volume_uniform.offset == 0.0)
|
||||||
.with_hdr_format(view.hdr)
|
.with_hdr_format(view.hdr)
|
||||||
.with_morph_targets(mesh.morph_targets.is_some());
|
.with_morph_targets(mesh.morph_targets.is_some());
|
||||||
|
94
src/lib.rs
94
src/lib.rs
@ -3,17 +3,19 @@
|
|||||||
//!
|
//!
|
||||||
//! Outlines are rendered in a seperate pass following the main 3D pass. The effect of this
|
//! Outlines are rendered in a seperate pass following the main 3D pass. The effect of this
|
||||||
//! pass is to present the outlines in depth sorted order according to the model translation
|
//! pass is to present the outlines in depth sorted order according to the model translation
|
||||||
//! of each mesh. This ensures that outlines are not clipped by other geometry.
|
//! of each mesh. This ensures that outlines are not clipped by non-outline geometry.
|
||||||
//!
|
//!
|
||||||
//! The [`OutlineVolume`] component will, by itself, cover the original object entirely with
|
//! The [`OutlineVolume`] component will, by itself, cover the original object entirely with
|
||||||
//! the outline colour. The [`OutlineStencil`] component must also be added to prevent the body
|
//! the outline colour. The [`OutlineStencil`] component must also be added to prevent the body
|
||||||
//! of an object from being filled it. This must be added to any entity which needs to appear on
|
//! of an object from being filled it. This must be added to any entity which needs to appear on
|
||||||
//! top of an outline.
|
//! top of an outline.
|
||||||
//!
|
//!
|
||||||
|
//! The [`OutlineMode`] component specifies the rendering method. Outlines may be flattened into
|
||||||
|
//! a plane in order to further avoid clipping, or left in real space.
|
||||||
|
//!
|
||||||
//! The [`OutlineBundle`] and [`OutlineStencilBundle`] bundles can be used to add the right
|
//! The [`OutlineBundle`] and [`OutlineStencilBundle`] bundles can be used to add the right
|
||||||
//! components, including the required [`ComputedOutlineDepth`] component. Optionally, the
|
//! components, including the required [`ComputedOutline`] component. Outlines can be inherited
|
||||||
//! [`SetOutlineDepth`] and [`InheritOutlineDepth`] components may also be added to control the
|
//! from the parent via the [`InheritOutline`] component and [`InheritOutlineBundle`].
|
||||||
//! depth ordering of outlines.
|
|
||||||
//!
|
//!
|
||||||
//! Vertex extrusion works best with meshes that have smooth surfaces. To avoid visual
|
//! Vertex extrusion works best with meshes that have smooth surfaces. To avoid visual
|
||||||
//! artefacts when outlining meshes with hard edges, see the
|
//! artefacts when outlining meshes with hard edges, see the
|
||||||
@ -29,7 +31,7 @@ use bevy::render::mesh::MeshVertexAttribute;
|
|||||||
use bevy::render::render_graph::RenderGraph;
|
use bevy::render::render_graph::RenderGraph;
|
||||||
use bevy::render::render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions};
|
use bevy::render::render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions};
|
||||||
use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat};
|
use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat};
|
||||||
use bevy::render::view::RenderLayers;
|
use bevy::render::view::{RenderLayers, VisibilitySystems};
|
||||||
use bevy::render::{Render, RenderApp, RenderSet};
|
use bevy::render::{Render, RenderApp, RenderSet};
|
||||||
use bevy::transform::TransformSystem;
|
use bevy::transform::TransformSystem;
|
||||||
use interpolation::Lerp;
|
use interpolation::Lerp;
|
||||||
@ -40,9 +42,8 @@ use crate::draw::{
|
|||||||
use crate::node::{OpaqueOutline, OutlineNode, StencilOutline, TransparentOutline};
|
use crate::node::{OpaqueOutline, OutlineNode, StencilOutline, TransparentOutline};
|
||||||
use crate::pipeline::{OutlinePipeline, FRAGMENT_SHADER_HANDLE, OUTLINE_SHADER_HANDLE};
|
use crate::pipeline::{OutlinePipeline, FRAGMENT_SHADER_HANDLE, OUTLINE_SHADER_HANDLE};
|
||||||
use crate::uniforms::{
|
use crate::uniforms::{
|
||||||
extract_outline_stencil_uniforms, extract_outline_volume_uniforms,
|
extract_outline_uniforms, queue_outline_stencil_bind_group, queue_outline_volume_bind_group,
|
||||||
queue_outline_stencil_bind_group, queue_outline_volume_bind_group, OutlineFragmentUniform,
|
set_outline_visibility, OutlineFragmentUniform, OutlineStencilUniform, OutlineVolumeUniform,
|
||||||
OutlineStencilUniform, OutlineVolumeUniform,
|
|
||||||
};
|
};
|
||||||
use crate::view_uniforms::{
|
use crate::view_uniforms::{
|
||||||
extract_outline_view_uniforms, queue_outline_view_bind_group, OutlineViewUniform,
|
extract_outline_view_uniforms, queue_outline_view_bind_group, OutlineViewUniform,
|
||||||
@ -148,7 +149,7 @@ impl ExtractComponent for OutlineRenderLayers {
|
|||||||
Option<&'static OutlineRenderLayers>,
|
Option<&'static OutlineRenderLayers>,
|
||||||
Option<&'static RenderLayers>,
|
Option<&'static RenderLayers>,
|
||||||
);
|
);
|
||||||
type Filter = Or<(With<OutlineVolume>, With<OutlineStencil>)>;
|
type Filter = With<ComputedOutline>;
|
||||||
type Out = Self;
|
type Out = Self;
|
||||||
|
|
||||||
fn extract_component(
|
fn extract_component(
|
||||||
@ -163,19 +164,51 @@ impl ExtractComponent for OutlineRenderLayers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A component which specifies how the outline should be rendered.
|
||||||
|
#[derive(Clone, Component)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum OutlineMode {
|
||||||
|
/// Vertex extrusion flattened into a plane facing the camera and intersecting the specified
|
||||||
|
/// point in model-space.
|
||||||
|
FlatVertex { model_origin: Vec3 },
|
||||||
|
/// Vertex extrusion in real model-space.
|
||||||
|
RealVertex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OutlineMode {
|
||||||
|
fn default() -> Self {
|
||||||
|
OutlineMode::FlatVertex {
|
||||||
|
model_origin: Vec3::ZERO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A component for inheriting outlines from the parent entity.
|
||||||
|
#[derive(Clone, Component, Default)]
|
||||||
|
pub struct InheritOutline;
|
||||||
|
|
||||||
/// A bundle for rendering stenciled outlines around meshes.
|
/// A bundle for rendering stenciled outlines around meshes.
|
||||||
#[derive(Bundle, Clone, Default)]
|
#[derive(Bundle, Clone, Default)]
|
||||||
pub struct OutlineBundle {
|
pub struct OutlineBundle {
|
||||||
pub outline: OutlineVolume,
|
pub outline: OutlineVolume,
|
||||||
pub stencil: OutlineStencil,
|
pub stencil: OutlineStencil,
|
||||||
pub plane: ComputedOutlineDepth,
|
pub mode: OutlineMode,
|
||||||
|
pub computed: ComputedOutline,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bundle for stenciling meshes in the outlining pass.
|
/// A bundle for stenciling meshes in the outlining pass.
|
||||||
#[derive(Bundle, Clone, Default)]
|
#[derive(Bundle, Clone, Default)]
|
||||||
pub struct OutlineStencilBundle {
|
pub struct OutlineStencilBundle {
|
||||||
pub stencil: OutlineStencil,
|
pub stencil: OutlineStencil,
|
||||||
pub plane: ComputedOutlineDepth,
|
pub mode: OutlineMode,
|
||||||
|
pub computed: ComputedOutline,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A bundle for inheriting outlines from the parent entity.
|
||||||
|
#[derive(Bundle, Clone, Default)]
|
||||||
|
pub struct InheritOutlineBundle {
|
||||||
|
pub inherit: InheritOutline,
|
||||||
|
pub computed: ComputedOutline,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds support for rendering outlines.
|
/// Adds support for rendering outlines.
|
||||||
@ -205,7 +238,10 @@ impl Plugin for OutlinePlugin {
|
|||||||
))
|
))
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PostUpdate,
|
PostUpdate,
|
||||||
compute_outline_depth.after(TransformSystem::TransformPropagate),
|
(
|
||||||
|
compute_outline.after(TransformSystem::TransformPropagate),
|
||||||
|
set_outline_visibility.in_set(VisibilitySystems::CheckVisibility),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.sub_app_mut(RenderApp)
|
.sub_app_mut(RenderApp)
|
||||||
.init_resource::<DrawFunctions<StencilOutline>>()
|
.init_resource::<DrawFunctions<StencilOutline>>()
|
||||||
@ -215,35 +251,31 @@ impl Plugin for OutlinePlugin {
|
|||||||
.add_render_command::<StencilOutline, DrawStencil>()
|
.add_render_command::<StencilOutline, DrawStencil>()
|
||||||
.add_render_command::<OpaqueOutline, DrawOutline>()
|
.add_render_command::<OpaqueOutline, DrawOutline>()
|
||||||
.add_render_command::<TransparentOutline, DrawOutline>()
|
.add_render_command::<TransparentOutline, DrawOutline>()
|
||||||
.add_systems(ExtractSchedule, extract_outline_view_uniforms)
|
|
||||||
.add_systems(ExtractSchedule, extract_outline_stencil_uniforms)
|
|
||||||
.add_systems(ExtractSchedule, extract_outline_volume_uniforms)
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
ExtractSchedule,
|
||||||
sort_phase_system::<StencilOutline>.in_set(RenderSet::PhaseSort),
|
(extract_outline_uniforms, extract_outline_view_uniforms),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
Render,
|
||||||
sort_phase_system::<OpaqueOutline>.in_set(RenderSet::PhaseSort),
|
(
|
||||||
|
sort_phase_system::<OpaqueOutline>,
|
||||||
|
sort_phase_system::<TransparentOutline>,
|
||||||
|
)
|
||||||
|
.in_set(RenderSet::PhaseSort),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
Render,
|
||||||
sort_phase_system::<TransparentOutline>.in_set(RenderSet::PhaseSort),
|
(
|
||||||
|
queue_outline_view_bind_group,
|
||||||
|
queue_outline_stencil_bind_group,
|
||||||
|
queue_outline_volume_bind_group,
|
||||||
|
)
|
||||||
|
.in_set(RenderSet::Queue),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
Render,
|
||||||
queue_outline_view_bind_group.in_set(RenderSet::Queue),
|
(queue_outline_stencil_mesh, queue_outline_volume_mesh).in_set(RenderSet::Queue),
|
||||||
)
|
);
|
||||||
.add_systems(
|
|
||||||
Render,
|
|
||||||
queue_outline_stencil_bind_group.in_set(RenderSet::Queue),
|
|
||||||
)
|
|
||||||
.add_systems(
|
|
||||||
Render,
|
|
||||||
queue_outline_volume_bind_group.in_set(RenderSet::Queue),
|
|
||||||
)
|
|
||||||
.add_systems(Render, queue_outline_stencil_mesh.in_set(RenderSet::Queue))
|
|
||||||
.add_systems(Render, queue_outline_volume_mesh.in_set(RenderSet::Queue));
|
|
||||||
|
|
||||||
let world = &mut app.sub_app_mut(RenderApp).world;
|
let world = &mut app.sub_app_mut(RenderApp).world;
|
||||||
let node = OutlineNode::new(world);
|
let node = OutlineNode::new(world);
|
||||||
|
@ -13,10 +13,13 @@ use bevy::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{node::StencilOutline, pipeline::OutlinePipeline, ComputedOutline};
|
||||||
node::StencilOutline, pipeline::OutlinePipeline, ComputedOutlineDepth, OutlineStencil,
|
|
||||||
OutlineVolume,
|
#[derive(Component)]
|
||||||
};
|
pub(crate) struct ExtractedOutline {
|
||||||
|
pub depth_mode: DepthMode,
|
||||||
|
pub mesh: Handle<Mesh>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Component, ShaderType)]
|
#[derive(Clone, Component, ShaderType)]
|
||||||
pub(crate) struct OutlineStencilUniform {
|
pub(crate) struct OutlineStencilUniform {
|
||||||
@ -38,30 +41,12 @@ pub(crate) struct OutlineFragmentUniform {
|
|||||||
pub colour: Vec4,
|
pub colour: Vec4,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
pub(crate) enum DepthMode {
|
pub(crate) enum DepthMode {
|
||||||
#[default]
|
|
||||||
Invalid = 0,
|
|
||||||
Flat = 1,
|
Flat = 1,
|
||||||
Real = 2,
|
Real = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DepthMode {
|
|
||||||
pub fn is_valid(&self) -> bool {
|
|
||||||
*self != DepthMode::Invalid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub(crate) struct OutlineStencilFlags {
|
|
||||||
pub depth_mode: DepthMode,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
pub(crate) struct OutlineVolumeFlags {
|
|
||||||
pub depth_mode: DepthMode,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub(crate) struct OutlineStencilBindGroup {
|
pub(crate) struct OutlineStencilBindGroup {
|
||||||
pub bind_group: BindGroup,
|
pub bind_group: BindGroup,
|
||||||
@ -72,47 +57,47 @@ pub(crate) struct OutlineVolumeBindGroup {
|
|||||||
pub bind_group: BindGroup,
|
pub bind_group: BindGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn extract_outline_stencil_uniforms(
|
pub(crate) fn set_outline_visibility(
|
||||||
mut commands: Commands,
|
mut query: Query<(&mut ComputedVisibility, &ComputedOutline)>,
|
||||||
query: Extract<Query<(Entity, &OutlineStencil, &ComputedOutlineDepth)>>,
|
|
||||||
) {
|
) {
|
||||||
for (entity, stencil, computed) in query.iter() {
|
for (mut visibility, computed) in query.iter_mut() {
|
||||||
if !stencil.enabled {
|
if let ComputedOutline(Some(computed)) = computed {
|
||||||
continue;
|
if computed.volume.value.enabled || computed.stencil.value.enabled {
|
||||||
|
visibility.set_visible_in_view();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
commands
|
|
||||||
.get_or_spawn(entity)
|
|
||||||
.insert(OutlineStencilUniform {
|
|
||||||
origin: computed.world_origin,
|
|
||||||
offset: stencil.offset,
|
|
||||||
})
|
|
||||||
.insert(OutlineStencilFlags {
|
|
||||||
depth_mode: computed.depth_mode,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn extract_outline_volume_uniforms(
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub(crate) fn extract_outline_uniforms(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
query: Extract<Query<(Entity, &OutlineVolume, &ComputedOutlineDepth)>>,
|
query: Extract<Query<(Entity, &ComputedOutline, &Handle<Mesh>)>>,
|
||||||
) {
|
) {
|
||||||
for (entity, outline, computed) in query.iter() {
|
for (entity, computed, mesh) in query.iter() {
|
||||||
if !outline.visible || outline.colour.a() == 0.0 {
|
let cmds = &mut commands.get_or_spawn(entity);
|
||||||
continue;
|
if let ComputedOutline(Some(computed)) = computed {
|
||||||
}
|
cmds.insert(ExtractedOutline {
|
||||||
commands
|
depth_mode: computed.mode.value.depth_mode,
|
||||||
.get_or_spawn(entity)
|
mesh: mesh.clone_weak(),
|
||||||
.insert(OutlineVolumeUniform {
|
});
|
||||||
origin: computed.world_origin,
|
if computed.volume.value.enabled {
|
||||||
offset: outline.width,
|
cmds.insert(OutlineVolumeUniform {
|
||||||
|
origin: computed.mode.value.world_origin,
|
||||||
|
offset: computed.volume.value.offset,
|
||||||
})
|
})
|
||||||
.insert(OutlineFragmentUniform {
|
.insert(OutlineFragmentUniform {
|
||||||
colour: outline.colour.as_linear_rgba_f32().into(),
|
colour: computed.volume.value.colour,
|
||||||
})
|
|
||||||
.insert(OutlineVolumeFlags {
|
|
||||||
depth_mode: computed.depth_mode,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if computed.stencil.value.enabled {
|
||||||
|
cmds.insert(OutlineStencilUniform {
|
||||||
|
origin: computed.mode.value.world_origin,
|
||||||
|
offset: computed.stencil.value.offset,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn queue_outline_stencil_bind_group(
|
pub(crate) fn queue_outline_stencil_bind_group(
|
||||||
|
Loading…
Reference in New Issue
Block a user