Add ComputedOutlinePlane and an example.
This commit is contained in:
parent
6781476bf0
commit
e1c845c434
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "bevy_mod_outline"
|
||||
version = "0.2.4"
|
||||
version = "0.3.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "A mesh outlining plugin for Bevy."
|
||||
|
@ -26,14 +26,17 @@ bevy = { version = "0.8", default-features = false, features = [
|
|||
] }
|
||||
|
||||
[features]
|
||||
default = ["align16", "bevy_ui"]
|
||||
align16 = []
|
||||
default = ["bevy_ui"]
|
||||
bevy_ui = ["bevy/bevy_ui", "bevy/bevy_sprite", "bevy/bevy_text"]
|
||||
|
||||
[[example]]
|
||||
name = "shapes"
|
||||
path = "examples/shapes.rs"
|
||||
|
||||
[[example]]
|
||||
name = "pieces"
|
||||
path = "examples/pieces.rs"
|
||||
|
||||
[[example]]
|
||||
name = "animated_fox"
|
||||
path = "examples/animated_fox.rs"
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
use std::f32::consts::TAU;
|
||||
|
||||
use bevy::{
|
||||
prelude::{
|
||||
shape::{Capsule, Torus, UVSphere},
|
||||
*,
|
||||
},
|
||||
window::close_on_esc,
|
||||
};
|
||||
|
||||
use bevy_mod_outline::*;
|
||||
|
||||
#[bevy_main]
|
||||
fn main() {
|
||||
App::new()
|
||||
.insert_resource(Msaa { samples: 4 })
|
||||
.insert_resource(ClearColor(Color::BLACK))
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_plugin(OutlinePlugin)
|
||||
.add_startup_system(setup)
|
||||
.add_system(close_on_esc)
|
||||
.add_system(rotates)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct Rotates;
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
// Add sphere with child meshes sticking out of it
|
||||
commands
|
||||
.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(
|
||||
UVSphere {
|
||||
radius: 0.75,
|
||||
sectors: 30,
|
||||
stacks: 30,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
material: materials.add(Color::rgb(0.9, 0.1, 0.1).into()),
|
||||
transform: Transform::from_translation(Vec3::new(0.0, 1.0, 0.0)),
|
||||
|
||||
..default()
|
||||
})
|
||||
.insert_bundle(OutlineBundle {
|
||||
outline: Outline {
|
||||
visible: true,
|
||||
colour: Color::WHITE,
|
||||
width: 10.0,
|
||||
},
|
||||
..default()
|
||||
})
|
||||
.insert(Rotates)
|
||||
.with_children(|parent| {
|
||||
parent
|
||||
.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(
|
||||
Capsule {
|
||||
radius: 0.2,
|
||||
rings: 15,
|
||||
depth: 1.0,
|
||||
latitudes: 15,
|
||||
longitudes: 15,
|
||||
..Default::default()
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()),
|
||||
transform: Transform::from_rotation(Quat::from_axis_angle(Vec3::X, TAU / 4.0))
|
||||
.with_translation(Vec3::new(0.0, 0.0, 0.75)),
|
||||
..default()
|
||||
})
|
||||
.insert_bundle(OutlineBundle {
|
||||
outline: Outline {
|
||||
visible: true,
|
||||
colour: Color::WHITE,
|
||||
width: 10.0,
|
||||
},
|
||||
..default()
|
||||
})
|
||||
.insert(InheritOutlinePlane);
|
||||
parent
|
||||
.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(
|
||||
Torus {
|
||||
radius: 0.5,
|
||||
ring_radius: 0.1,
|
||||
subdivisions_segments: 30,
|
||||
subdivisions_sides: 15,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()),
|
||||
transform: Transform::from_rotation(Quat::from_axis_angle(Vec3::Z, TAU / 4.0))
|
||||
.with_translation(Vec3::new(0.0, 0.0, -0.75)),
|
||||
..default()
|
||||
})
|
||||
.insert_bundle(OutlineBundle {
|
||||
outline: Outline {
|
||||
visible: true,
|
||||
colour: Color::WHITE,
|
||||
width: 10.0,
|
||||
},
|
||||
..default()
|
||||
})
|
||||
.insert(InheritOutlinePlane);
|
||||
});
|
||||
|
||||
// Add plane, light source, and camera
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(bevy::prelude::shape::Plane { size: 5.0 })),
|
||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||
..default()
|
||||
});
|
||||
commands.spawn_bundle(PointLightBundle {
|
||||
point_light: PointLight {
|
||||
intensity: 1500.0,
|
||||
shadows_enabled: true,
|
||||
..default()
|
||||
},
|
||||
transform: Transform::from_xyz(4.0, 8.0, 4.0),
|
||||
..default()
|
||||
});
|
||||
commands.spawn_bundle(Camera3dBundle {
|
||||
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
|
||||
fn rotates(mut query: Query<&mut Transform, With<Rotates>>, timer: Res<Time>) {
|
||||
for mut transform in query.iter_mut() {
|
||||
transform.rotate_axis(Vec3::Y, 0.75 * timer.delta_seconds());
|
||||
}
|
||||
}
|
|
@ -5,17 +5,10 @@
|
|||
@group(1) @binding(0)
|
||||
var<uniform> mesh: Mesh;
|
||||
|
||||
#ifdef SKINNED
|
||||
@group(1) @binding(1)
|
||||
var<uniform> joint_matrices: SkinnedMesh;
|
||||
#import bevy_pbr::skinning
|
||||
#endif
|
||||
|
||||
fn model_origin_z(model: mat4x4<f32>, view_proj: mat4x4<f32>) -> f32 {
|
||||
var origin = model[3];
|
||||
fn model_origin_z(plane: vec3<f32>, view_proj: mat4x4<f32>) -> f32 {
|
||||
var proj_zw = mat4x2<f32>(
|
||||
view_proj[0].zw, view_proj[1].zw,
|
||||
view_proj[2].zw, view_proj[3].zw);
|
||||
var zw = proj_zw * origin;
|
||||
var zw = proj_zw * vec4<f32>(plane, 1.0);
|
||||
return zw.x / zw.y;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
/// A component for storing the computed plane on which the outline lies.
|
||||
#[derive(Clone, Component, Default)]
|
||||
pub struct ComputedOutlinePlane {
|
||||
pub(crate) plane: Vec3,
|
||||
}
|
||||
|
||||
/// A component which specifies that this entity lies on the same plane as its parent.
|
||||
#[derive(Clone, Component, Default)]
|
||||
pub struct InheritOutlinePlane;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fn compute_outline_plane(
|
||||
mut root_query: Query<
|
||||
(
|
||||
&mut ComputedOutlinePlane,
|
||||
&GlobalTransform,
|
||||
Changed<GlobalTransform>,
|
||||
Option<(&Children, Changed<Children>)>,
|
||||
),
|
||||
Without<InheritOutlinePlane>,
|
||||
>,
|
||||
mut computed_query: Query<(&mut ComputedOutlinePlane, Changed<InheritOutlinePlane>)>,
|
||||
child_query: Query<(&Children, Changed<Children>)>,
|
||||
) {
|
||||
for (mut computed, transform, changed_transform, children) in root_query.iter_mut() {
|
||||
if changed_transform {
|
||||
let matrix = transform.compute_matrix();
|
||||
computed.plane = matrix.project_point3(Vec3::ZERO);
|
||||
}
|
||||
if let Some((cs, changed_children)) = children {
|
||||
let changed2 = changed_children || changed_transform;
|
||||
for child in cs.iter() {
|
||||
propagate_outline_planes(
|
||||
&computed,
|
||||
changed2,
|
||||
*child,
|
||||
&mut computed_query,
|
||||
&child_query,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_outline_planes(
|
||||
root_computed: &ComputedOutlinePlane,
|
||||
changed: bool,
|
||||
entity: Entity,
|
||||
computed_query: &mut Query<(&mut ComputedOutlinePlane, Changed<InheritOutlinePlane>)>,
|
||||
child_query: &Query<(&Children, Changed<Children>)>,
|
||||
) {
|
||||
if let Ok((mut computed, changed_inherit)) = computed_query.get_mut(entity) {
|
||||
if changed_inherit || changed {
|
||||
*computed = root_computed.clone();
|
||||
}
|
||||
if let Ok((cs, changed_children)) = child_query.get(entity) {
|
||||
let changed2 = changed_children || changed_inherit || changed;
|
||||
for child in cs.iter() {
|
||||
propagate_outline_planes(
|
||||
root_computed,
|
||||
changed2,
|
||||
*child,
|
||||
computed_query,
|
||||
child_query,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ use bevy::render::view::ExtractedView;
|
|||
|
||||
use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline};
|
||||
use crate::pipeline::{OutlinePipeline, PassType};
|
||||
use crate::uniforms::{OutlineFragmentUniform, SetOutlineBindGroup};
|
||||
use crate::uniforms::{OutlineFragmentUniform, SetOutlineBindGroup, SetOutlineStencilBindGroup};
|
||||
use crate::view_uniforms::SetOutlineViewBindGroup;
|
||||
use crate::OutlineStencil;
|
||||
|
||||
|
@ -15,6 +15,7 @@ pub type DrawStencil = (
|
|||
SetItemPipeline,
|
||||
SetMeshViewBindGroup<0>,
|
||||
SetMeshBindGroup<1>,
|
||||
SetOutlineStencilBindGroup<2>,
|
||||
DrawMesh,
|
||||
);
|
||||
|
||||
|
|
21
src/lib.rs
21
src/lib.rs
|
@ -26,6 +26,7 @@ use bevy::render::render_graph::RenderGraph;
|
|||
use bevy::render::render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions};
|
||||
use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat};
|
||||
use bevy::render::{RenderApp, RenderStage};
|
||||
use bevy::transform::TransformSystem;
|
||||
|
||||
use crate::draw::{queue_outline_mesh, queue_outline_stencil_mesh, DrawOutline, DrawStencil};
|
||||
use crate::node::{OpaqueOutline, OutlineNode, StencilOutline, TransparentOutline};
|
||||
|
@ -33,13 +34,15 @@ use crate::pipeline::{
|
|||
OutlinePipeline, COMMON_SHADER_HANDLE, OUTLINE_SHADER_HANDLE, STENCIL_SHADER_HANDLE,
|
||||
};
|
||||
use crate::uniforms::{
|
||||
extract_outline_uniforms, queue_outline_bind_group, OutlineFragmentUniform,
|
||||
extract_outline_stencil_uniforms, extract_outline_uniforms, queue_outline_bind_group,
|
||||
queue_outline_stencil_bind_group, OutlineFragmentUniform, OutlineStencilUniform,
|
||||
OutlineVertexUniform,
|
||||
};
|
||||
use crate::view_uniforms::{
|
||||
extract_outline_view_uniforms, queue_outline_view_bind_group, OutlineViewUniform,
|
||||
};
|
||||
|
||||
mod computed;
|
||||
mod draw;
|
||||
mod generate;
|
||||
mod node;
|
||||
|
@ -47,6 +50,7 @@ mod pipeline;
|
|||
mod uniforms;
|
||||
mod view_uniforms;
|
||||
|
||||
pub use computed::*;
|
||||
pub use generate::*;
|
||||
|
||||
// See https://alexanderameye.github.io/notes/rendering-outlines/
|
||||
|
@ -90,6 +94,14 @@ pub struct Outline {
|
|||
pub struct OutlineBundle {
|
||||
pub outline: Outline,
|
||||
pub stencil: OutlineStencil,
|
||||
pub plane: ComputedOutlinePlane,
|
||||
}
|
||||
|
||||
/// A bundle for stenciling meshes in the outlining pass.
|
||||
#[derive(Bundle, Clone, Default)]
|
||||
pub struct OutlineStencilBundle {
|
||||
pub stencil: OutlineStencil,
|
||||
pub plane: ComputedOutlinePlane,
|
||||
}
|
||||
|
||||
/// Adds support for rendering outlines.
|
||||
|
@ -112,9 +124,14 @@ impl Plugin for OutlinePlugin {
|
|||
);
|
||||
|
||||
app.add_plugin(ExtractComponentPlugin::<OutlineStencil>::extract_visible())
|
||||
.add_plugin(UniformComponentPlugin::<OutlineStencilUniform>::default())
|
||||
.add_plugin(UniformComponentPlugin::<OutlineVertexUniform>::default())
|
||||
.add_plugin(UniformComponentPlugin::<OutlineFragmentUniform>::default())
|
||||
.add_plugin(UniformComponentPlugin::<OutlineViewUniform>::default())
|
||||
.add_system_to_stage(
|
||||
CoreStage::PostUpdate,
|
||||
compute_outline_plane.after(TransformSystem::TransformPropagate),
|
||||
)
|
||||
.sub_app_mut(RenderApp)
|
||||
.init_resource::<DrawFunctions<StencilOutline>>()
|
||||
.init_resource::<DrawFunctions<OpaqueOutline>>()
|
||||
|
@ -125,6 +142,7 @@ impl Plugin for OutlinePlugin {
|
|||
.add_render_command::<OpaqueOutline, DrawOutline>()
|
||||
.add_render_command::<TransparentOutline, DrawOutline>()
|
||||
.add_system_to_stage(RenderStage::Extract, extract_outline_view_uniforms)
|
||||
.add_system_to_stage(RenderStage::Extract, extract_outline_stencil_uniforms)
|
||||
.add_system_to_stage(RenderStage::Extract, extract_outline_uniforms)
|
||||
.add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<StencilOutline>)
|
||||
.add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<OpaqueOutline>)
|
||||
|
@ -133,6 +151,7 @@ impl Plugin for OutlinePlugin {
|
|||
sort_phase_system::<TransparentOutline>,
|
||||
)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_outline_view_bind_group)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_outline_stencil_bind_group)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_outline_bind_group)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_outline_stencil_mesh)
|
||||
.add_system_to_stage(RenderStage::Queue, queue_outline_mesh);
|
||||
|
|
|
@ -17,16 +17,13 @@ struct OutlineViewUniform {
|
|||
};
|
||||
|
||||
struct OutlineVertexUniform {
|
||||
#ifdef ALIGN_16
|
||||
@align(16)
|
||||
#endif
|
||||
plane: vec3<f32>,
|
||||
width: f32,
|
||||
};
|
||||
|
||||
struct OutlineFragmentUniform {
|
||||
#ifdef ALIGN_16
|
||||
@align(16)
|
||||
#endif
|
||||
colour: vec4<f32>,
|
||||
};
|
||||
|
||||
|
@ -56,7 +53,7 @@ fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> {
|
|||
var clip_norm = mat4to3(view.view_proj) * (mat4to3(model) * vertex.normal);
|
||||
var ndc_pos = clip_pos.xy / clip_pos.w;
|
||||
var ndc_delta = vstage.width * normalize(clip_norm.xy) * view_uniform.scale;
|
||||
return vec4<f32>(ndc_pos + ndc_delta, model_origin_z(mesh.model, view.view_proj), 1.0);
|
||||
return vec4<f32>(ndc_pos + ndc_delta, model_origin_z(vstage.plane, view.view_proj), 1.0);
|
||||
}
|
||||
|
||||
@fragment
|
||||
|
|
|
@ -20,7 +20,7 @@ use bevy::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::uniforms::{OutlineFragmentUniform, OutlineVertexUniform};
|
||||
use crate::uniforms::{OutlineFragmentUniform, OutlineStencilUniform, OutlineVertexUniform};
|
||||
use crate::view_uniforms::OutlineViewUniform;
|
||||
use crate::ATTRIBUTE_OUTLINE_NORMAL;
|
||||
|
||||
|
@ -43,6 +43,7 @@ pub enum PassType {
|
|||
pub struct OutlinePipeline {
|
||||
mesh_pipeline: MeshPipeline,
|
||||
pub outline_view_bind_group_layout: BindGroupLayout,
|
||||
pub outline_stencil_bind_group_layout: BindGroupLayout,
|
||||
pub outline_bind_group_layout: BindGroupLayout,
|
||||
}
|
||||
|
||||
|
@ -95,9 +96,24 @@ impl FromWorld for OutlinePipeline {
|
|||
},
|
||||
],
|
||||
});
|
||||
let outline_stencil_bind_group_layout =
|
||||
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
label: Some("outline_stencil_bind_group_layout"),
|
||||
entries: &[BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: ShaderStages::VERTEX,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: BufferSize::new(OutlineStencilUniform::SHADER_SIZE.get()),
|
||||
},
|
||||
count: None,
|
||||
}],
|
||||
});
|
||||
OutlinePipeline {
|
||||
mesh_pipeline,
|
||||
outline_view_bind_group_layout,
|
||||
outline_stencil_bind_group_layout,
|
||||
outline_bind_group_layout,
|
||||
}
|
||||
}
|
||||
|
@ -114,11 +130,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
|||
let mut targets = vec![];
|
||||
let mut bind_layouts = vec![self.mesh_pipeline.view_layout.clone()];
|
||||
let mut buffer_attrs = vec![Mesh::ATTRIBUTE_POSITION.at_shader_location(0)];
|
||||
let mut shader_defs = if cfg!(feature = "align16") {
|
||||
vec!["ALIGN_16".to_string()]
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let mut shader_defs = vec![];
|
||||
bind_layouts.push(
|
||||
if mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
|
||||
&& mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
|
||||
|
@ -135,6 +147,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
|
|||
match pass_type {
|
||||
PassType::Stencil => {
|
||||
shader = STENCIL_SHADER_HANDLE;
|
||||
bind_layouts.push(self.outline_stencil_bind_group_layout.clone());
|
||||
}
|
||||
PassType::Opaque | PassType::Transparent => {
|
||||
shader = OUTLINE_SHADER_HANDLE;
|
||||
|
|
|
@ -8,6 +8,14 @@ struct VertexInput {
|
|||
#endif
|
||||
};
|
||||
|
||||
struct OutlineStencilUniform {
|
||||
@align(16)
|
||||
plane: vec3<f32>,
|
||||
};
|
||||
|
||||
@group(2) @binding(0)
|
||||
var<uniform> vstage: OutlineStencilUniform;
|
||||
|
||||
@vertex
|
||||
fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> {
|
||||
#ifdef SKINNED
|
||||
|
@ -17,7 +25,7 @@ fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> {
|
|||
#endif
|
||||
var clip_pos = view.view_proj * (model * vec4<f32>(vertex.position, 1.0));
|
||||
var ndc_pos = clip_pos.xy / clip_pos.w;
|
||||
return vec4<f32>(ndc_pos, model_origin_z(mesh.model, view.view_proj), 1.0);
|
||||
return vec4<f32>(ndc_pos, model_origin_z(vstage.plane, view.view_proj), 1.0);
|
||||
}
|
||||
|
||||
@fragment
|
||||
|
|
|
@ -13,11 +13,18 @@ use bevy::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::{pipeline::OutlinePipeline, Outline};
|
||||
use crate::{pipeline::OutlinePipeline, ComputedOutlinePlane, Outline, OutlineStencil};
|
||||
|
||||
#[derive(Clone, Component, ShaderType)]
|
||||
pub struct OutlineStencilUniform {
|
||||
#[cfg_attr(feature = "align16", align(16))]
|
||||
pub plane: Vec3,
|
||||
}
|
||||
|
||||
#[derive(Clone, Component, ShaderType)]
|
||||
pub struct OutlineVertexUniform {
|
||||
#[cfg_attr(feature = "align16", align(16))]
|
||||
#[align(16)]
|
||||
pub plane: Vec3,
|
||||
pub width: f32,
|
||||
}
|
||||
|
||||
|
@ -27,12 +34,30 @@ pub struct OutlineFragmentUniform {
|
|||
pub colour: Vec4,
|
||||
}
|
||||
|
||||
pub struct OutlineStencilBindGroup {
|
||||
pub bind_group: BindGroup,
|
||||
}
|
||||
|
||||
pub struct OutlineBindGroup {
|
||||
pub bind_group: BindGroup,
|
||||
}
|
||||
|
||||
pub fn extract_outline_uniforms(mut commands: Commands, query: Extract<Query<(Entity, &Outline)>>) {
|
||||
for (entity, outline) in query.iter() {
|
||||
pub fn extract_outline_stencil_uniforms(
|
||||
mut commands: Commands,
|
||||
query: Extract<Query<(Entity, &ComputedOutlinePlane), With<OutlineStencil>>>,
|
||||
) {
|
||||
for (entity, computed) in query.iter() {
|
||||
commands.get_or_spawn(entity).insert(OutlineStencilUniform {
|
||||
plane: computed.plane,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_outline_uniforms(
|
||||
mut commands: Commands,
|
||||
query: Extract<Query<(Entity, &Outline, &ComputedOutlinePlane)>>,
|
||||
) {
|
||||
for (entity, outline, computed) in query.iter() {
|
||||
if !outline.visible || outline.colour.a() == 0.0 {
|
||||
continue;
|
||||
}
|
||||
|
@ -40,6 +65,7 @@ pub fn extract_outline_uniforms(mut commands: Commands, query: Extract<Query<(En
|
|||
.get_or_spawn(entity)
|
||||
.insert(OutlineVertexUniform {
|
||||
width: outline.width,
|
||||
plane: computed.plane,
|
||||
})
|
||||
.insert(OutlineFragmentUniform {
|
||||
colour: outline.colour.as_linear_rgba_f32().into(),
|
||||
|
@ -47,6 +73,25 @@ pub fn extract_outline_uniforms(mut commands: Commands, query: Extract<Query<(En
|
|||
}
|
||||
}
|
||||
|
||||
pub fn queue_outline_stencil_bind_group(
|
||||
mut commands: Commands,
|
||||
render_device: Res<RenderDevice>,
|
||||
outline_pipeline: Res<OutlinePipeline>,
|
||||
vertex: Res<ComponentUniforms<OutlineStencilUniform>>,
|
||||
) {
|
||||
if let Some(vertex_binding) = vertex.binding() {
|
||||
let bind_group = render_device.create_bind_group(&BindGroupDescriptor {
|
||||
entries: &[BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: vertex_binding.clone(),
|
||||
}],
|
||||
label: Some("outline_stencil_bind_group"),
|
||||
layout: &outline_pipeline.outline_stencil_bind_group_layout,
|
||||
});
|
||||
commands.insert_resource(OutlineStencilBindGroup { bind_group });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn queue_outline_bind_group(
|
||||
mut commands: Commands,
|
||||
render_device: Res<RenderDevice>,
|
||||
|
@ -73,6 +118,25 @@ pub fn queue_outline_bind_group(
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SetOutlineStencilBindGroup<const I: usize>();
|
||||
|
||||
impl<const I: usize> EntityRenderCommand for SetOutlineStencilBindGroup<I> {
|
||||
type Param = (
|
||||
SRes<OutlineStencilBindGroup>,
|
||||
SQuery<Read<DynamicUniformIndex<OutlineStencilUniform>>>,
|
||||
);
|
||||
fn render<'w>(
|
||||
_view: Entity,
|
||||
item: Entity,
|
||||
(bind_group, query): SystemParamItem<'w, '_, Self::Param>,
|
||||
pass: &mut TrackedRenderPass<'w>,
|
||||
) -> RenderCommandResult {
|
||||
let vertex = query.get(item).unwrap();
|
||||
pass.set_bind_group(I, &bind_group.into_inner().bind_group, &[vertex.index()]);
|
||||
RenderCommandResult::Success
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SetOutlineBindGroup<const I: usize>();
|
||||
|
||||
impl<const I: usize> EntityRenderCommand for SetOutlineBindGroup<I> {
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::pipeline::OutlinePipeline;
|
|||
|
||||
#[derive(Clone, Component, ShaderType)]
|
||||
pub struct OutlineViewUniform {
|
||||
#[cfg_attr(feature = "align16", align(16))]
|
||||
#[align(16)]
|
||||
scale: Vec2,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue