Unify stencil and volume shaders.
This commit is contained in:
parent
95b3a5b298
commit
e86c6d6c60
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
11
src/draw.rs
11
src/draw.rs
|
@ -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>,
|
||||||
|
|
|
@ -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
|
35
src/lib.rs
35
src/lib.rs
|
@ -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);
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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>>,
|
||||||
)>,
|
)>,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue