Unify stencil and volume shaders.

This commit is contained in:
Robin KAY 2022-11-18 00:50:52 +00:00
parent 95b3a5b298
commit e86c6d6c60
9 changed files with 122 additions and 142 deletions

View File

@ -1,14 +0,0 @@
#define_import_path bevy_mod_outline::common
#import bevy_pbr::mesh_view_bindings
#import bevy_pbr::mesh_types
@group(1) @binding(0)
var<uniform> mesh: Mesh;
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 * vec4<f32>(plane, 1.0);
return zw.x / zw.y;
}

View File

@ -3,7 +3,7 @@ use bevy::prelude::*;
/// 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 ComputedOutlineDepth {
pub(crate) plane: Vec3, pub(crate) origin: Vec3,
} }
/// A component which specifies that this entity lies at the same depth as its parent. /// A component which specifies that this entity lies at the same depth as its parent.
@ -27,7 +27,7 @@ pub(crate) fn compute_outline_depth(
for (mut computed, transform, changed_transform, children) in root_query.iter_mut() { for (mut computed, transform, changed_transform, children) in root_query.iter_mut() {
if changed_transform { if changed_transform {
let matrix = transform.compute_matrix(); let matrix = transform.compute_matrix();
computed.plane = matrix.project_point3(Vec3::ZERO); computed.origin = matrix.project_point3(Vec3::ZERO);
} }
if let Some((cs, changed_children)) = children { if let Some((cs, changed_children)) = children {
let changed2 = changed_children || changed_transform; let changed2 = changed_children || changed_transform;

View File

@ -7,7 +7,9 @@ use bevy::render::view::ExtractedView;
use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline};
use crate::pipeline::{OutlinePipeline, PassType}; use crate::pipeline::{OutlinePipeline, PassType};
use crate::uniforms::{OutlineFragmentUniform, SetOutlineBindGroup, SetOutlineStencilBindGroup}; use crate::uniforms::{
OutlineFragmentUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup,
};
use crate::view_uniforms::SetOutlineViewBindGroup; use crate::view_uniforms::SetOutlineViewBindGroup;
use crate::OutlineStencil; use crate::OutlineStencil;
@ -15,7 +17,8 @@ pub type DrawStencil = (
SetItemPipeline, SetItemPipeline,
SetMeshViewBindGroup<0>, SetMeshViewBindGroup<0>,
SetMeshBindGroup<1>, SetMeshBindGroup<1>,
SetOutlineStencilBindGroup<2>, SetOutlineViewBindGroup<2>,
SetOutlineStencilBindGroup<3>,
DrawMesh, DrawMesh,
); );
@ -68,12 +71,12 @@ pub type DrawOutline = (
SetMeshViewBindGroup<0>, SetMeshViewBindGroup<0>,
SetMeshBindGroup<1>, SetMeshBindGroup<1>,
SetOutlineViewBindGroup<2>, SetOutlineViewBindGroup<2>,
SetOutlineBindGroup<3>, SetOutlineVolumeBindGroup<3>,
DrawMesh, DrawMesh,
); );
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn queue_outline_mesh( pub fn queue_outline_volume_mesh(
opaque_draw_functions: Res<DrawFunctions<OpaqueOutline>>, opaque_draw_functions: Res<DrawFunctions<OpaqueOutline>>,
transparent_draw_functions: Res<DrawFunctions<TransparentOutline>>, transparent_draw_functions: Res<DrawFunctions<TransparentOutline>>,
outline_pipeline: Res<OutlinePipeline>, outline_pipeline: Res<OutlinePipeline>,

24
src/fragment.wgsl Normal file
View File

@ -0,0 +1,24 @@
#ifdef VOLUME
struct OutlineFragmentUniform {
@align(16)
colour: vec4<f32>,
};
@group(3) @binding(1)
var<uniform> fstage: OutlineFragmentUniform;
@fragment
fn fragment() -> @location(0) vec4<f32> {
return fstage.colour;
}
#else
// Stencil
@fragment
fn fragment() {
return;
}
#endif

View File

@ -28,15 +28,15 @@ use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat};
use bevy::render::{RenderApp, RenderStage}; use bevy::render::{RenderApp, RenderStage};
use bevy::transform::TransformSystem; use bevy::transform::TransformSystem;
use crate::draw::{queue_outline_mesh, queue_outline_stencil_mesh, DrawOutline, DrawStencil}; use crate::draw::{
use crate::node::{OpaqueOutline, OutlineNode, StencilOutline, TransparentOutline}; queue_outline_stencil_mesh, queue_outline_volume_mesh, DrawOutline, DrawStencil,
use crate::pipeline::{
OutlinePipeline, COMMON_SHADER_HANDLE, OUTLINE_SHADER_HANDLE, STENCIL_SHADER_HANDLE,
}; };
use crate::node::{OpaqueOutline, OutlineNode, StencilOutline, TransparentOutline};
use crate::pipeline::{OutlinePipeline, FRAGMENT_SHADER_HANDLE, OUTLINE_SHADER_HANDLE};
use crate::uniforms::{ use crate::uniforms::{
extract_outline_stencil_uniforms, extract_outline_uniforms, queue_outline_bind_group, extract_outline_stencil_uniforms, extract_outline_volume_uniforms,
queue_outline_stencil_bind_group, OutlineFragmentUniform, OutlineStencilUniform, queue_outline_stencil_bind_group, queue_outline_volume_bind_group, OutlineFragmentUniform,
OutlineVertexUniform, 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,
@ -109,23 +109,22 @@ pub struct OutlinePlugin;
impl Plugin for OutlinePlugin { impl Plugin for OutlinePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
load_internal_asset!(app, COMMON_SHADER_HANDLE, "common.wgsl", Shader::from_wgsl);
load_internal_asset!(
app,
STENCIL_SHADER_HANDLE,
"stencil.wgsl",
Shader::from_wgsl
);
load_internal_asset!( load_internal_asset!(
app, app,
OUTLINE_SHADER_HANDLE, OUTLINE_SHADER_HANDLE,
"outline.wgsl", "outline.wgsl",
Shader::from_wgsl Shader::from_wgsl
); );
load_internal_asset!(
app,
FRAGMENT_SHADER_HANDLE,
"fragment.wgsl",
Shader::from_wgsl
);
app.add_plugin(ExtractComponentPlugin::<OutlineStencil>::extract_visible()) app.add_plugin(ExtractComponentPlugin::<OutlineStencil>::extract_visible())
.add_plugin(UniformComponentPlugin::<OutlineStencilUniform>::default()) .add_plugin(UniformComponentPlugin::<OutlineStencilUniform>::default())
.add_plugin(UniformComponentPlugin::<OutlineVertexUniform>::default()) .add_plugin(UniformComponentPlugin::<OutlineVolumeUniform>::default())
.add_plugin(UniformComponentPlugin::<OutlineFragmentUniform>::default()) .add_plugin(UniformComponentPlugin::<OutlineFragmentUniform>::default())
.add_plugin(UniformComponentPlugin::<OutlineViewUniform>::default()) .add_plugin(UniformComponentPlugin::<OutlineViewUniform>::default())
.add_system_to_stage( .add_system_to_stage(
@ -143,7 +142,7 @@ impl Plugin for OutlinePlugin {
.add_render_command::<TransparentOutline, DrawOutline>() .add_render_command::<TransparentOutline, DrawOutline>()
.add_system_to_stage(RenderStage::Extract, extract_outline_view_uniforms) .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_stencil_uniforms)
.add_system_to_stage(RenderStage::Extract, extract_outline_uniforms) .add_system_to_stage(RenderStage::Extract, extract_outline_volume_uniforms)
.add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<StencilOutline>) .add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<StencilOutline>)
.add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<OpaqueOutline>) .add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<OpaqueOutline>)
.add_system_to_stage( .add_system_to_stage(
@ -152,9 +151,9 @@ impl Plugin for OutlinePlugin {
) )
.add_system_to_stage(RenderStage::Queue, queue_outline_view_bind_group) .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_stencil_bind_group)
.add_system_to_stage(RenderStage::Queue, queue_outline_bind_group) .add_system_to_stage(RenderStage::Queue, queue_outline_volume_bind_group)
.add_system_to_stage(RenderStage::Queue, queue_outline_stencil_mesh) .add_system_to_stage(RenderStage::Queue, queue_outline_stencil_mesh)
.add_system_to_stage(RenderStage::Queue, queue_outline_mesh); .add_system_to_stage(RenderStage::Queue, queue_outline_volume_mesh);
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);

View File

@ -1,8 +1,11 @@
#import bevy_mod_outline::common #import bevy_pbr::mesh_view_bindings
#import bevy_pbr::mesh_types
struct VertexInput { struct VertexInput {
@location(0) position: vec3<f32>, @location(0) position: vec3<f32>,
#ifndef OFFSET_ZERO
@location(1) normal: vec3<f32>, @location(1) normal: vec3<f32>,
#endif
#ifdef SKINNED #ifdef SKINNED
@location(2) joint_indexes: vec4<u32>, @location(2) joint_indexes: vec4<u32>,
@location(3) joint_weights: vec4<f32>, @location(3) joint_weights: vec4<f32>,
@ -10,22 +13,18 @@ struct VertexInput {
}; };
struct OutlineViewUniform { struct OutlineViewUniform {
#ifdef ALIGN_16
@align(16) @align(16)
#endif
scale: vec2<f32>, scale: vec2<f32>,
}; };
struct OutlineVertexUniform { struct OutlineVertexUniform {
@align(16) @align(16)
plane: vec3<f32>, origin: vec3<f32>,
width: f32, offset: f32,
}; };
struct OutlineFragmentUniform { @group(1) @binding(0)
@align(16) var<uniform> mesh: Mesh;
colour: vec4<f32>,
};
@group(2) @binding(0) @group(2) @binding(0)
var<uniform> view_uniform: OutlineViewUniform; var<uniform> view_uniform: OutlineViewUniform;
@ -33,15 +32,20 @@ var<uniform> view_uniform: OutlineViewUniform;
@group(3) @binding(0) @group(3) @binding(0)
var<uniform> vstage: OutlineVertexUniform; var<uniform> vstage: OutlineVertexUniform;
@group(3) @binding(1)
var<uniform> fstage: OutlineFragmentUniform;
fn mat4to3(m: mat4x4<f32>) -> mat3x3<f32> { fn mat4to3(m: mat4x4<f32>) -> mat3x3<f32> {
return mat3x3<f32>( return mat3x3<f32>(
m[0].xyz, m[1].xyz, m[2].xyz m[0].xyz, m[1].xyz, m[2].xyz
); );
} }
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 * vec4<f32>(plane, 1.0);
return zw.x / zw.y;
}
@vertex @vertex
fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> { fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> {
#ifdef SKINNED #ifdef SKINNED
@ -49,14 +53,13 @@ fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> {
#else #else
let model = mesh.model; let model = mesh.model;
#endif #endif
var 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));
var clip_norm = mat4to3(view.view_proj) * (mat4to3(model) * vertex.normal); let ndc_pos = clip_pos.xy / clip_pos.w;
var ndc_pos = clip_pos.xy / clip_pos.w; #ifdef OFFSET_ZERO
var ndc_delta = vstage.width * normalize(clip_norm.xy) * view_uniform.scale; let ndc_delta = vec2<f32>(0.0, 0.0);
return vec4<f32>(ndc_pos + ndc_delta, model_origin_z(vstage.plane, view.view_proj), 1.0); #else
} let clip_norm = mat4to3(view.view_proj) * (mat4to3(model) * vertex.normal);
let ndc_delta = vstage.offset * normalize(clip_norm.xy) * view_uniform.scale;
@fragment #endif
fn fragment() -> @location(0) vec4<f32> { return vec4<f32>(ndc_pos + ndc_delta, model_origin_z(vstage.origin, view.view_proj), 1.0);
return fstage.colour;
} }

View File

@ -20,19 +20,16 @@ use bevy::{
}, },
}; };
use crate::uniforms::{OutlineFragmentUniform, OutlineStencilUniform, OutlineVertexUniform}; use crate::uniforms::{OutlineFragmentUniform, OutlineStencilUniform, OutlineVolumeUniform};
use crate::view_uniforms::OutlineViewUniform; use crate::view_uniforms::OutlineViewUniform;
use crate::ATTRIBUTE_OUTLINE_NORMAL; use crate::ATTRIBUTE_OUTLINE_NORMAL;
pub const COMMON_SHADER_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 9448276477068917228);
pub const STENCIL_SHADER_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 12033806834125368121);
pub const OUTLINE_SHADER_HANDLE: HandleUntyped = pub const OUTLINE_SHADER_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 2101625026478770097); HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 2101625026478770097);
pub const FRAGMENT_SHADER_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 12033806834125368121);
#[derive(Clone, Copy, PartialEq, Eq, Hash)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum PassType { pub enum PassType {
Stencil, Stencil,
@ -44,7 +41,7 @@ pub struct OutlinePipeline {
mesh_pipeline: MeshPipeline, mesh_pipeline: MeshPipeline,
pub outline_view_bind_group_layout: BindGroupLayout, pub outline_view_bind_group_layout: BindGroupLayout,
pub outline_stencil_bind_group_layout: BindGroupLayout, pub outline_stencil_bind_group_layout: BindGroupLayout,
pub outline_bind_group_layout: BindGroupLayout, pub outline_volume_bind_group_layout: BindGroupLayout,
} }
impl FromWorld for OutlinePipeline { impl FromWorld for OutlinePipeline {
@ -66,9 +63,9 @@ impl FromWorld for OutlinePipeline {
count: None, count: None,
}], }],
}); });
let outline_bind_group_layout = let outline_volume_bind_group_layout =
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some("outline_bind_group_layout"), label: Some("outline_volume_bind_group_layout"),
entries: &[ entries: &[
BindGroupLayoutEntry { BindGroupLayoutEntry {
binding: 0, binding: 0,
@ -77,7 +74,7 @@ impl FromWorld for OutlinePipeline {
ty: BufferBindingType::Uniform, ty: BufferBindingType::Uniform,
has_dynamic_offset: true, has_dynamic_offset: true,
min_binding_size: BufferSize::new( min_binding_size: BufferSize::new(
OutlineVertexUniform::SHADER_SIZE.get(), OutlineVolumeUniform::SHADER_SIZE.get(),
), ),
}, },
count: None, count: None,
@ -114,7 +111,7 @@ impl FromWorld for OutlinePipeline {
mesh_pipeline, mesh_pipeline,
outline_view_bind_group_layout, outline_view_bind_group_layout,
outline_stencil_bind_group_layout, outline_stencil_bind_group_layout,
outline_bind_group_layout, outline_volume_bind_group_layout,
} }
} }
} }
@ -130,12 +127,13 @@ impl SpecializedMeshPipeline for OutlinePipeline {
let mut targets = vec![]; let mut targets = vec![];
let mut bind_layouts = vec![self.mesh_pipeline.view_layout.clone()]; 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 buffer_attrs = vec![Mesh::ATTRIBUTE_POSITION.at_shader_location(0)];
let mut shader_defs = vec![]; let mut vertex_defs = vec![];
let mut fragment_defs = vec![];
bind_layouts.push( bind_layouts.push(
if mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX) if mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
&& mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT) && mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
{ {
shader_defs.push("SKINNED".to_string()); vertex_defs.push("SKINNED".to_string());
buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(2)); buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(2));
buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(3)); buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(3));
self.mesh_pipeline.skinned_mesh_layout.clone() self.mesh_pipeline.skinned_mesh_layout.clone()
@ -143,14 +141,14 @@ impl SpecializedMeshPipeline for OutlinePipeline {
self.mesh_pipeline.mesh_layout.clone() self.mesh_pipeline.mesh_layout.clone()
}, },
); );
let shader; bind_layouts.push(self.outline_view_bind_group_layout.clone());
match pass_type { match pass_type {
PassType::Stencil => { PassType::Stencil => {
shader = STENCIL_SHADER_HANDLE; vertex_defs.push("OFFSET_ZERO".to_string());
bind_layouts.push(self.outline_stencil_bind_group_layout.clone()); bind_layouts.push(self.outline_stencil_bind_group_layout.clone());
} }
PassType::Opaque | PassType::Transparent => { PassType::Opaque | PassType::Transparent => {
shader = OUTLINE_SHADER_HANDLE; fragment_defs.push("VOLUME".to_string());
targets.push(Some(ColorTargetState { targets.push(Some(ColorTargetState {
format: TextureFormat::bevy_default(), format: TextureFormat::bevy_default(),
blend: Some(if pass_type == PassType::Transparent { blend: Some(if pass_type == PassType::Transparent {
@ -161,8 +159,7 @@ impl SpecializedMeshPipeline for OutlinePipeline {
write_mask: ColorWrites::ALL, write_mask: ColorWrites::ALL,
})); }));
bind_layouts.push(self.outline_view_bind_group_layout.clone()); bind_layouts.push(self.outline_volume_bind_group_layout.clone());
bind_layouts.push(self.outline_bind_group_layout.clone());
buffer_attrs.push( buffer_attrs.push(
if mesh_layout.contains(ATTRIBUTE_OUTLINE_NORMAL) { if mesh_layout.contains(ATTRIBUTE_OUTLINE_NORMAL) {
ATTRIBUTE_OUTLINE_NORMAL ATTRIBUTE_OUTLINE_NORMAL
@ -176,14 +173,14 @@ impl SpecializedMeshPipeline for OutlinePipeline {
let buffers = vec![mesh_layout.get_layout(&buffer_attrs)?]; let buffers = vec![mesh_layout.get_layout(&buffer_attrs)?];
Ok(RenderPipelineDescriptor { Ok(RenderPipelineDescriptor {
vertex: VertexState { vertex: VertexState {
shader: shader.clone().typed::<Shader>(), shader: OUTLINE_SHADER_HANDLE.typed::<Shader>(),
entry_point: "vertex".into(), entry_point: "vertex".into(),
shader_defs: shader_defs.clone(), shader_defs: vertex_defs,
buffers, buffers,
}, },
fragment: Some(FragmentState { fragment: Some(FragmentState {
shader: shader.typed::<Shader>(), shader: FRAGMENT_SHADER_HANDLE.typed::<Shader>(),
shader_defs, shader_defs: fragment_defs,
entry_point: "fragment".into(), entry_point: "fragment".into(),
targets, targets,
}), }),

View File

@ -1,34 +0,0 @@
#import bevy_mod_outline::common
struct VertexInput {
@location(0) position: vec3<f32>,
#ifdef SKINNED
@location(2) joint_indexes: vec4<u32>,
@location(3) joint_weights: vec4<f32>,
#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
let model = skin_model(vertex.joint_indexes, vertex.joint_weights);
#else
let model = mesh.model;
#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(vstage.plane, view.view_proj), 1.0);
}
@fragment
fn fragment() {
return;
}

View File

@ -15,18 +15,19 @@ use bevy::{
use crate::{pipeline::OutlinePipeline, ComputedOutlineDepth, Outline, OutlineStencil}; use crate::{pipeline::OutlinePipeline, ComputedOutlineDepth, Outline, OutlineStencil};
#[derive(Clone, Component, ShaderType)] macro_rules! outline_vertex_uniform {
pub struct OutlineStencilUniform { ($x:ident) => {
#[derive(Clone, Component, ShaderType)]
pub struct $x {
#[align(16)] #[align(16)]
pub plane: Vec3, pub origin: Vec3,
pub offset: f32,
}
};
} }
#[derive(Clone, Component, ShaderType)] outline_vertex_uniform!(OutlineStencilUniform);
pub struct OutlineVertexUniform { outline_vertex_uniform!(OutlineVolumeUniform);
#[align(16)]
pub plane: Vec3,
pub width: f32,
}
#[derive(Clone, Component, ShaderType)] #[derive(Clone, Component, ShaderType)]
pub struct OutlineFragmentUniform { pub struct OutlineFragmentUniform {
@ -38,7 +39,7 @@ pub struct OutlineStencilBindGroup {
pub bind_group: BindGroup, pub bind_group: BindGroup,
} }
pub struct OutlineBindGroup { pub struct OutlineVolumeBindGroup {
pub bind_group: BindGroup, pub bind_group: BindGroup,
} }
@ -48,12 +49,13 @@ pub fn extract_outline_stencil_uniforms(
) { ) {
for (entity, computed) in query.iter() { for (entity, computed) in query.iter() {
commands.get_or_spawn(entity).insert(OutlineStencilUniform { commands.get_or_spawn(entity).insert(OutlineStencilUniform {
plane: computed.plane, origin: computed.origin,
offset: 0.0,
}); });
} }
} }
pub fn extract_outline_uniforms( pub fn extract_outline_volume_uniforms(
mut commands: Commands, mut commands: Commands,
query: Extract<Query<(Entity, &Outline, &ComputedOutlineDepth)>>, query: Extract<Query<(Entity, &Outline, &ComputedOutlineDepth)>>,
) { ) {
@ -63,9 +65,9 @@ pub fn extract_outline_uniforms(
} }
commands commands
.get_or_spawn(entity) .get_or_spawn(entity)
.insert(OutlineVertexUniform { .insert(OutlineVolumeUniform {
width: outline.width, origin: computed.origin,
plane: computed.plane, offset: outline.width,
}) })
.insert(OutlineFragmentUniform { .insert(OutlineFragmentUniform {
colour: outline.colour.as_linear_rgba_f32().into(), colour: outline.colour.as_linear_rgba_f32().into(),
@ -92,11 +94,11 @@ pub fn queue_outline_stencil_bind_group(
} }
} }
pub fn queue_outline_bind_group( pub fn queue_outline_volume_bind_group(
mut commands: Commands, mut commands: Commands,
render_device: Res<RenderDevice>, render_device: Res<RenderDevice>,
outline_pipeline: Res<OutlinePipeline>, outline_pipeline: Res<OutlinePipeline>,
vertex: Res<ComponentUniforms<OutlineVertexUniform>>, vertex: Res<ComponentUniforms<OutlineVolumeUniform>>,
fragment: Res<ComponentUniforms<OutlineFragmentUniform>>, fragment: Res<ComponentUniforms<OutlineFragmentUniform>>,
) { ) {
if let (Some(vertex_binding), Some(fragment_binding)) = (vertex.binding(), fragment.binding()) { if let (Some(vertex_binding), Some(fragment_binding)) = (vertex.binding(), fragment.binding()) {
@ -111,10 +113,10 @@ pub fn queue_outline_bind_group(
resource: fragment_binding.clone(), resource: fragment_binding.clone(),
}, },
], ],
label: Some("outline_bind_group"), label: Some("outline_volume_bind_group"),
layout: &outline_pipeline.outline_bind_group_layout, layout: &outline_pipeline.outline_volume_bind_group_layout,
}); });
commands.insert_resource(OutlineBindGroup { bind_group }); commands.insert_resource(OutlineVolumeBindGroup { bind_group });
} }
} }
@ -137,13 +139,13 @@ impl<const I: usize> EntityRenderCommand for SetOutlineStencilBindGroup<I> {
} }
} }
pub struct SetOutlineBindGroup<const I: usize>(); pub struct SetOutlineVolumeBindGroup<const I: usize>();
impl<const I: usize> EntityRenderCommand for SetOutlineBindGroup<I> { impl<const I: usize> EntityRenderCommand for SetOutlineVolumeBindGroup<I> {
type Param = ( type Param = (
SRes<OutlineBindGroup>, SRes<OutlineVolumeBindGroup>,
SQuery<( SQuery<(
Read<DynamicUniformIndex<OutlineVertexUniform>>, Read<DynamicUniformIndex<OutlineVolumeUniform>>,
Read<DynamicUniformIndex<OutlineFragmentUniform>>, Read<DynamicUniformIndex<OutlineFragmentUniform>>,
)>, )>,
); );