Merge pull request #9 from mxgrey/outline_render_layers_v0.2

Introduce OutlineRenderLayers for masking which views an outline appears on.
This commit is contained in:
Robin KAY 2023-01-14 02:36:03 +00:00
parent cfd5d12261
commit ae1fe650c6
3 changed files with 53 additions and 12 deletions

View File

@ -3,7 +3,7 @@ use bevy::prelude::*;
use bevy::render::render_asset::RenderAssets; use bevy::render::render_asset::RenderAssets;
use bevy::render::render_phase::{DrawFunctions, RenderPhase, SetItemPipeline}; use bevy::render::render_phase::{DrawFunctions, RenderPhase, SetItemPipeline};
use bevy::render::render_resource::{PipelineCache, SpecializedMeshPipelines}; use bevy::render::render_resource::{PipelineCache, SpecializedMeshPipelines};
use bevy::render::view::ExtractedView; 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};
@ -12,6 +12,7 @@ use crate::uniforms::{
OutlineVolumeUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup, OutlineVolumeUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup,
}; };
use crate::view_uniforms::SetOutlineViewBindGroup; use crate::view_uniforms::SetOutlineViewBindGroup;
use crate::OutlineRenderLayers;
pub(crate) type DrawStencil = ( pub(crate) type DrawStencil = (
SetItemPipeline, SetItemPipeline,
@ -22,7 +23,7 @@ pub(crate) type DrawStencil = (
DrawMesh, DrawMesh,
); );
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments, clippy::type_complexity)]
pub(crate) fn queue_outline_stencil_mesh( pub(crate) fn queue_outline_stencil_mesh(
stencil_draw_functions: Res<DrawFunctions<StencilOutline>>, stencil_draw_functions: Res<DrawFunctions<StencilOutline>>,
stencil_pipeline: Res<OutlinePipeline>, stencil_pipeline: Res<OutlinePipeline>,
@ -35,8 +36,13 @@ pub(crate) fn queue_outline_stencil_mesh(
&Handle<Mesh>, &Handle<Mesh>,
&OutlineStencilUniform, &OutlineStencilUniform,
&OutlineStencilFlags, &OutlineStencilFlags,
Option<&OutlineRenderLayers>,
)>,
mut views: Query<(
&ExtractedView,
&mut RenderPhase<StencilOutline>,
Option<&RenderLayers>,
)>, )>,
mut views: Query<(&ExtractedView, &mut RenderPhase<StencilOutline>)>,
) { ) {
let draw_stencil = stencil_draw_functions let draw_stencil = stencil_draw_functions
.read() .read()
@ -47,9 +53,16 @@ pub(crate) fn queue_outline_stencil_mesh(
.with_msaa_samples(msaa.samples) .with_msaa_samples(msaa.samples)
.with_pass_type(PassType::Stencil); .with_pass_type(PassType::Stencil);
for (view, mut stencil_phase) in views.iter_mut() { for (view, mut stencil_phase, view_mask) in views.iter_mut() {
let rangefinder = view.rangefinder3d(); let rangefinder = view.rangefinder3d();
for (entity, mesh_handle, stencil_uniform, stencil_flags) in material_meshes.iter() { let view_mask = view_mask.copied().unwrap_or_default();
for (entity, mesh_handle, stencil_uniform, stencil_flags, outline_mask) in
material_meshes.iter()
{
let outline_mask = outline_mask.copied().unwrap_or_default();
if !view_mask.intersects(&outline_mask) {
continue;
}
if let Some(mesh) = render_meshes.get(mesh_handle) { if let Some(mesh) = render_meshes.get(mesh_handle) {
let key = base_key let key = base_key
.with_primitive_topology(mesh.primitive_topology) .with_primitive_topology(mesh.primitive_topology)
@ -80,7 +93,7 @@ pub(crate) type DrawOutline = (
DrawMesh, DrawMesh,
); );
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments, clippy::type_complexity)]
pub(crate) fn queue_outline_volume_mesh( pub(crate) 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>>,
@ -95,11 +108,13 @@ pub(crate) fn queue_outline_volume_mesh(
&OutlineVolumeUniform, &OutlineVolumeUniform,
&OutlineVolumeFlags, &OutlineVolumeFlags,
&OutlineFragmentUniform, &OutlineFragmentUniform,
Option<&OutlineRenderLayers>,
)>, )>,
mut views: Query<( mut views: Query<(
&ExtractedView, &ExtractedView,
&mut RenderPhase<OpaqueOutline>, &mut RenderPhase<OpaqueOutline>,
&mut RenderPhase<TransparentOutline>, &mut RenderPhase<TransparentOutline>,
Option<&RenderLayers>,
)>, )>,
) { ) {
let draw_opaque_outline = opaque_draw_functions let draw_opaque_outline = opaque_draw_functions
@ -113,11 +128,16 @@ pub(crate) fn queue_outline_volume_mesh(
let base_key = PipelineKey::new().with_msaa_samples(msaa.samples); let base_key = PipelineKey::new().with_msaa_samples(msaa.samples);
for (view, mut opaque_phase, mut transparent_phase) 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 rangefinder = view.rangefinder3d(); let rangefinder = view.rangefinder3d();
for (entity, mesh_handle, volume_uniform, volume_flags, fragment_uniform) in for (entity, mesh_handle, volume_uniform, volume_flags, fragment_uniform, outline_mask) in
material_meshes.iter() material_meshes.iter()
{ {
let outline_mask = outline_mask.copied().unwrap_or_default();
if !view_mask.intersects(&outline_mask) {
continue;
}
if let Some(mesh) = render_meshes.get(mesh_handle) { if let Some(mesh) = render_meshes.get(mesh_handle) {
let transparent = fragment_uniform.colour[3] < 1.0; let transparent = fragment_uniform.colour[3] < 1.0;
let key = base_key let key = base_key

View File

@ -30,6 +30,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::{RenderApp, RenderStage}; use bevy::render::{RenderApp, RenderStage};
use bevy::transform::TransformSystem; use bevy::transform::TransformSystem;
use interpolation::Lerp; use interpolation::Lerp;
@ -132,6 +133,19 @@ impl Lerp for OutlineVolume {
} }
} }
/// A component for specifying what layer(s) the outline should be rendered for.
#[derive(Component, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut, Default)]
pub struct OutlineRenderLayers(pub RenderLayers);
impl ExtractComponent for OutlineRenderLayers {
type Query = &'static OutlineRenderLayers;
type Filter = ();
fn extract_component(item: &OutlineRenderLayers) -> Self {
*item
}
}
/// 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 {
@ -166,6 +180,7 @@ impl Plugin for OutlinePlugin {
); );
app.add_plugin(ExtractComponentPlugin::<OutlineStencil>::extract_visible()) app.add_plugin(ExtractComponentPlugin::<OutlineStencil>::extract_visible())
.add_plugin(ExtractComponentPlugin::<OutlineRenderLayers>::default())
.add_plugin(UniformComponentPlugin::<OutlineStencilUniform>::default()) .add_plugin(UniformComponentPlugin::<OutlineStencilUniform>::default())
.add_plugin(UniformComponentPlugin::<OutlineVolumeUniform>::default()) .add_plugin(UniformComponentPlugin::<OutlineVolumeUniform>::default())
.add_plugin(UniformComponentPlugin::<OutlineFragmentUniform>::default()) .add_plugin(UniformComponentPlugin::<OutlineFragmentUniform>::default())

View File

@ -8,6 +8,7 @@ use bevy::render::render_phase::{
use bevy::render::render_resource::ShaderType; use bevy::render::render_resource::ShaderType;
use bevy::render::render_resource::{BindGroup, BindGroupDescriptor, BindGroupEntry}; use bevy::render::render_resource::{BindGroup, BindGroupDescriptor, BindGroupEntry};
use bevy::render::renderer::RenderDevice; use bevy::render::renderer::RenderDevice;
use bevy::render::view::RenderLayers;
use bevy::render::Extract; use bevy::render::Extract;
use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline};
@ -24,21 +25,26 @@ pub(crate) struct OutlineViewBindGroup {
bind_group: BindGroup, bind_group: BindGroup,
} }
#[allow(clippy::type_complexity)]
pub(crate) fn extract_outline_view_uniforms( pub(crate) fn extract_outline_view_uniforms(
mut commands: Commands, mut commands: Commands,
query: Extract<Query<(Entity, &Camera), With<Camera3d>>>, query: Extract<Query<(Entity, &Camera, Option<&RenderLayers>), With<Camera3d>>>,
) { ) {
for (entity, camera) in query.iter() { for (entity, camera, view_mask) in query.iter() {
if !camera.is_active { if !camera.is_active {
continue; continue;
} }
if let Some(size) = camera.logical_viewport_size() { if let Some(size) = camera.logical_viewport_size() {
commands let mut entity_commands = commands.get_or_spawn(entity);
.get_or_spawn(entity) entity_commands
.insert(OutlineViewUniform { scale: 2.0 / size }) .insert(OutlineViewUniform { scale: 2.0 / size })
.insert(RenderPhase::<StencilOutline>::default()) .insert(RenderPhase::<StencilOutline>::default())
.insert(RenderPhase::<OpaqueOutline>::default()) .insert(RenderPhase::<OpaqueOutline>::default())
.insert(RenderPhase::<TransparentOutline>::default()); .insert(RenderPhase::<TransparentOutline>::default());
if let Some(view_mask) = view_mask {
entity_commands.insert(*view_mask);
}
} }
} }
} }