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_phase::{DrawFunctions, RenderPhase, SetItemPipeline};
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::pipeline::{OutlinePipeline, PassType, PipelineKey};
@ -12,6 +12,7 @@ use crate::uniforms::{
OutlineVolumeUniform, SetOutlineStencilBindGroup, SetOutlineVolumeBindGroup,
};
use crate::view_uniforms::SetOutlineViewBindGroup;
use crate::OutlineRenderLayers;
pub(crate) type DrawStencil = (
SetItemPipeline,
@ -22,7 +23,7 @@ pub(crate) type DrawStencil = (
DrawMesh,
);
#[allow(clippy::too_many_arguments)]
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
pub(crate) fn queue_outline_stencil_mesh(
stencil_draw_functions: Res<DrawFunctions<StencilOutline>>,
stencil_pipeline: Res<OutlinePipeline>,
@ -35,8 +36,13 @@ pub(crate) fn queue_outline_stencil_mesh(
&Handle<Mesh>,
&OutlineStencilUniform,
&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
.read()
@ -47,9 +53,16 @@ pub(crate) fn queue_outline_stencil_mesh(
.with_msaa_samples(msaa.samples)
.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();
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) {
let key = base_key
.with_primitive_topology(mesh.primitive_topology)
@ -80,7 +93,7 @@ pub(crate) type DrawOutline = (
DrawMesh,
);
#[allow(clippy::too_many_arguments)]
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
pub(crate) fn queue_outline_volume_mesh(
opaque_draw_functions: Res<DrawFunctions<OpaqueOutline>>,
transparent_draw_functions: Res<DrawFunctions<TransparentOutline>>,
@ -95,11 +108,13 @@ pub(crate) fn queue_outline_volume_mesh(
&OutlineVolumeUniform,
&OutlineVolumeFlags,
&OutlineFragmentUniform,
Option<&OutlineRenderLayers>,
)>,
mut views: Query<(
&ExtractedView,
&mut RenderPhase<OpaqueOutline>,
&mut RenderPhase<TransparentOutline>,
Option<&RenderLayers>,
)>,
) {
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);
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();
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()
{
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) {
let transparent = fragment_uniform.colour[3] < 1.0;
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_phase::{sort_phase_system, AddRenderCommand, DrawFunctions};
use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat};
use bevy::render::view::RenderLayers;
use bevy::render::{RenderApp, RenderStage};
use bevy::transform::TransformSystem;
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.
#[derive(Bundle, Clone, Default)]
pub struct OutlineBundle {
@ -166,6 +180,7 @@ impl Plugin for OutlinePlugin {
);
app.add_plugin(ExtractComponentPlugin::<OutlineStencil>::extract_visible())
.add_plugin(ExtractComponentPlugin::<OutlineRenderLayers>::default())
.add_plugin(UniformComponentPlugin::<OutlineStencilUniform>::default())
.add_plugin(UniformComponentPlugin::<OutlineVolumeUniform>::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::{BindGroup, BindGroupDescriptor, BindGroupEntry};
use bevy::render::renderer::RenderDevice;
use bevy::render::view::RenderLayers;
use bevy::render::Extract;
use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline};
@ -24,21 +25,26 @@ pub(crate) struct OutlineViewBindGroup {
bind_group: BindGroup,
}
#[allow(clippy::type_complexity)]
pub(crate) fn extract_outline_view_uniforms(
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 {
continue;
}
if let Some(size) = camera.logical_viewport_size() {
commands
.get_or_spawn(entity)
let mut entity_commands = commands.get_or_spawn(entity);
entity_commands
.insert(OutlineViewUniform { scale: 2.0 / size })
.insert(RenderPhase::<StencilOutline>::default())
.insert(RenderPhase::<OpaqueOutline>::default())
.insert(RenderPhase::<TransparentOutline>::default());
if let Some(view_mask) = view_mask {
entity_commands.insert(*view_mask);
}
}
}
}