diff --git a/Cargo.toml b/Cargo.toml index bc1a045..33b8bcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_mod_outline" -version = "0.3.5" +version = "0.4.0" edition = "2021" license = "MIT OR Apache-2.0" description = "A mesh outlining plugin for Bevy." @@ -11,7 +11,7 @@ keywords = ["gamedev", "bevy", "outline"] categories = ["game-engines", "rendering"] [dependencies] -bevy = { version = "0.9", default-features = false, features = [ +bevy = { version = "0.10", default-features = false, features = [ "bevy_asset", "bevy_render", "bevy_pbr", @@ -22,7 +22,7 @@ interpolation = "0.2" thiserror = "1.0" [dev-dependencies] -bevy = { version = "0.9", default-features = false, features = [ +bevy = { version = "0.10", default-features = false, features = [ "bevy_winit", "x11", ] } @@ -48,4 +48,4 @@ name = "animated_fox" path = "examples/animated_fox.rs" required-features = [ "bevy/animation", "bevy/bevy_gltf", "bevy/png", "bevy/bevy_scene" -] \ No newline at end of file +] diff --git a/examples/animated_fox.rs b/examples/animated_fox.rs index 68d738d..0ba8be2 100644 --- a/examples/animated_fox.rs +++ b/examples/animated_fox.rs @@ -1,6 +1,10 @@ use std::f32::consts::PI; -use bevy::{prelude::*, scene::SceneInstance, window::close_on_esc}; +use bevy::{ + prelude::{shape::Plane, *}, + scene::SceneInstance, + window::close_on_esc, +}; use bevy_mod_outline::{ AutoGenerateOutlineNormalsPlugin, OutlineBundle, OutlinePlugin, OutlineVolume, }; @@ -41,7 +45,10 @@ fn setup( // Plane commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(shape::Plane { size: 500000.0 })), + mesh: meshes.add(Mesh::from(Plane { + size: 500000.0, + subdivisions: 0, + })), material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), ..default() }); diff --git a/examples/pieces.rs b/examples/pieces.rs index 397234d..b9a100a 100644 --- a/examples/pieces.rs +++ b/examples/pieces.rs @@ -2,7 +2,7 @@ use std::f32::consts::TAU; use bevy::{ prelude::{ - shape::{Capsule, Torus, UVSphere}, + shape::{Capsule, Plane, Torus, UVSphere}, *, }, window::close_on_esc, @@ -13,7 +13,7 @@ use bevy_mod_outline::*; #[bevy_main] fn main() { App::new() - .insert_resource(Msaa { samples: 4 }) + .insert_resource(Msaa::Sample4) .insert_resource(ClearColor(Color::BLACK)) .add_plugins(DefaultPlugins) .add_plugin(OutlinePlugin) @@ -101,7 +101,10 @@ fn setup( // Add plane, light source, and camera commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(bevy::prelude::shape::Plane { size: 5.0 })), + mesh: meshes.add(Mesh::from(Plane { + size: 5.0, + subdivisions: 0, + })), material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), ..default() }); diff --git a/examples/render_layers.rs b/examples/render_layers.rs index b3c2c1a..2182372 100644 --- a/examples/render_layers.rs +++ b/examples/render_layers.rs @@ -2,16 +2,19 @@ use std::f32::consts::PI; use bevy::{ core_pipeline::clear_color::ClearColorConfig, - prelude::{shape::Torus, *}, + prelude::{ + shape::{Plane, Torus}, + *, + }, render::{camera::Viewport, view::RenderLayers}, - window::close_on_esc, + window::{close_on_esc, PrimaryWindow}, }; use bevy_mod_outline::{OutlineBundle, OutlinePlugin, OutlineRenderLayers, OutlineVolume}; #[bevy_main] fn main() { App::new() - .insert_resource(Msaa { samples: 4 }) + .insert_resource(Msaa::Sample4) .insert_resource(ClearColor(Color::BLACK)) .add_plugins(DefaultPlugins) .add_plugin(OutlinePlugin) @@ -62,7 +65,10 @@ fn setup( // Add plane and light source commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(bevy::prelude::shape::Plane { size: 5.0 })), + mesh: meshes.add(Mesh::from(Plane { + size: 5.0, + subdivisions: 0, + })), material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), ..default() }); @@ -90,7 +96,7 @@ fn setup( commands .spawn(Camera3dBundle { camera: Camera { - priority: i, + order: i, ..default() }, camera_3d: Camera3d { @@ -112,10 +118,13 @@ fn setup( } } -fn set_camera_viewports(windows: Res, mut query: Query<(&mut Camera, &CameraMode)>) { - if windows.is_changed() { +fn set_camera_viewports( + win_query: Query<(&Window, Changed), With>, + mut query: Query<(&mut Camera, &CameraMode)>, +) { + let (win, win_changed) = win_query.get_single().unwrap(); + if win_changed { // Divide window into quadrants - let win = windows.primary(); let size = UVec2::new(win.physical_width() / 2, win.physical_height() / 2); for (mut camera, mode) in query.iter_mut() { let offset = UVec2::new( diff --git a/examples/shapes.rs b/examples/shapes.rs index 358fcd2..b00f010 100644 --- a/examples/shapes.rs +++ b/examples/shapes.rs @@ -2,7 +2,7 @@ use std::f32::consts::{PI, TAU}; use bevy::{ prelude::{ - shape::{Cube, Torus}, + shape::{Cube, Plane, Torus}, *, }, window::close_on_esc, @@ -13,7 +13,7 @@ use bevy_mod_outline::*; #[bevy_main] fn main() { App::new() - .insert_resource(Msaa { samples: 4 }) + .insert_resource(Msaa::Sample4) .insert_resource(ClearColor(Color::BLACK)) .add_plugins(DefaultPlugins) .add_plugin(OutlinePlugin) @@ -81,7 +81,10 @@ fn setup( // Add plane, light source, and camera commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(bevy::prelude::shape::Plane { size: 5.0 })), + mesh: meshes.add(Mesh::from(Plane { + size: 5.0, + subdivisions: 0, + })), material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), ..default() }); diff --git a/src/draw.rs b/src/draw.rs index 345e1b5..82704c7 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -29,7 +29,7 @@ pub(crate) fn queue_outline_stencil_mesh( stencil_pipeline: Res, msaa: Res, mut pipelines: ResMut>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, render_meshes: Res>, material_meshes: Query<( Entity, @@ -50,7 +50,7 @@ pub(crate) fn queue_outline_stencil_mesh( .unwrap(); let base_key = PipelineKey::new() - .with_msaa_samples(msaa.samples) + .with_msaa(*msaa) .with_pass_type(PassType::Stencil); for (view, mut stencil_phase, view_mask) in views.iter_mut() { @@ -68,7 +68,7 @@ pub(crate) fn queue_outline_stencil_mesh( .with_depth_mode(stencil_flags.depth_mode) .with_offset_zero(stencil_uniform.offset == 0.0); let pipeline = pipelines - .specialize(&mut pipeline_cache, &stencil_pipeline, key, &mesh.layout) + .specialize(&pipeline_cache, &stencil_pipeline, key, &mesh.layout) .unwrap(); let distance = rangefinder.distance(&Mat4::from_translation(stencil_uniform.origin)); @@ -99,7 +99,7 @@ pub(crate) fn queue_outline_volume_mesh( outline_pipeline: Res, msaa: Res, mut pipelines: ResMut>, - mut pipeline_cache: ResMut, + pipeline_cache: Res, render_meshes: Res>, material_meshes: Query<( Entity, @@ -125,7 +125,7 @@ pub(crate) fn queue_outline_volume_mesh( .get_id::() .unwrap(); - let base_key = PipelineKey::new().with_msaa_samples(msaa.samples); + let base_key = PipelineKey::new().with_msaa(*msaa); for (view, mut opaque_phase, mut transparent_phase, view_mask) in views.iter_mut() { let view_mask = view_mask.copied().unwrap_or_default(); @@ -149,7 +149,7 @@ pub(crate) fn queue_outline_volume_mesh( .with_offset_zero(volume_uniform.offset == 0.0) .with_hdr_format(view.hdr); let pipeline = pipelines - .specialize(&mut pipeline_cache, &outline_pipeline, key, &mesh.layout) + .specialize(&pipeline_cache, &outline_pipeline, key, &mesh.layout) .unwrap(); let distance = rangefinder.distance(&Mat4::from_translation(volume_uniform.origin)); if transparent { diff --git a/src/lib.rs b/src/lib.rs index d5c5ce6..d5e1038 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,7 +31,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::view::RenderLayers; -use bevy::render::{RenderApp, RenderStage}; +use bevy::render::{RenderApp, RenderSet}; use bevy::transform::TransformSystem; use interpolation::Lerp; @@ -82,9 +82,10 @@ pub struct OutlineStencil { impl ExtractComponent for OutlineStencil { type Query = &'static OutlineStencil; type Filter = (); + type Out = Self; - fn extract_component(item: QueryItem) -> Self { - item.clone() + fn extract_component(item: QueryItem) -> Option { + Some(item.clone()) } } @@ -143,14 +144,17 @@ impl ExtractComponent for OutlineRenderLayers { Option<&'static RenderLayers>, ); type Filter = Or<(With, With)>; + type Out = Self; fn extract_component( (outline_mask, object_mask): (Option<&OutlineRenderLayers>, Option<&RenderLayers>), - ) -> Self { - outline_mask - .copied() - .or_else(|| object_mask.copied().map(OutlineRenderLayers)) - .unwrap_or_default() + ) -> Option { + Some( + outline_mask + .copied() + .or_else(|| object_mask.copied().map(OutlineRenderLayers)) + .unwrap_or_default(), + ) } } @@ -193,9 +197,10 @@ impl Plugin for OutlinePlugin { .add_plugin(UniformComponentPlugin::::default()) .add_plugin(UniformComponentPlugin::::default()) .add_plugin(UniformComponentPlugin::::default()) - .add_system_to_stage( - CoreStage::PostUpdate, - compute_outline_depth.after(TransformSystem::TransformPropagate), + .add_system( + compute_outline_depth + .in_base_set(CoreSet::PostUpdate) + .after(TransformSystem::TransformPropagate), ) .sub_app_mut(RenderApp) .init_resource::>() @@ -206,20 +211,17 @@ impl Plugin for OutlinePlugin { .add_render_command::() .add_render_command::() .add_render_command::() - .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_volume_uniforms) - .add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::) - .add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::) - .add_system_to_stage( - RenderStage::PhaseSort, - sort_phase_system::, - ) - .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_volume_bind_group) - .add_system_to_stage(RenderStage::Queue, queue_outline_stencil_mesh) - .add_system_to_stage(RenderStage::Queue, queue_outline_volume_mesh); + .add_system(extract_outline_view_uniforms.in_schedule(ExtractSchedule)) + .add_system(extract_outline_stencil_uniforms.in_schedule(ExtractSchedule)) + .add_system(extract_outline_volume_uniforms.in_schedule(ExtractSchedule)) + .add_system(sort_phase_system::.in_set(RenderSet::PhaseSort)) + .add_system(sort_phase_system::.in_set(RenderSet::PhaseSort)) + .add_system(sort_phase_system::.in_set(RenderSet::PhaseSort)) + .add_system(queue_outline_view_bind_group.in_set(RenderSet::Queue)) + .add_system(queue_outline_stencil_bind_group.in_set(RenderSet::Queue)) + .add_system(queue_outline_volume_bind_group.in_set(RenderSet::Queue)) + .add_system(queue_outline_stencil_mesh.in_set(RenderSet::Queue)) + .add_system(queue_outline_volume_mesh.in_set(RenderSet::Queue)); let world = &mut app.sub_app_mut(RenderApp).world; let node = OutlineNode::new(world); @@ -230,28 +232,22 @@ impl Plugin for OutlinePlugin { .get_sub_graph_mut(bevy::core_pipeline::core_3d::graph::NAME) .unwrap(); draw_3d_graph.add_node(OUTLINE_PASS_NODE_NAME, node); - draw_3d_graph - .add_slot_edge( - draw_3d_graph.input_node().unwrap().id, - bevy::core_pipeline::core_3d::graph::input::VIEW_ENTITY, - OUTLINE_PASS_NODE_NAME, - OutlineNode::IN_VIEW, - ) - .unwrap(); + draw_3d_graph.add_slot_edge( + draw_3d_graph.input_node().id, + bevy::core_pipeline::core_3d::graph::input::VIEW_ENTITY, + OUTLINE_PASS_NODE_NAME, + OutlineNode::IN_VIEW, + ); // Run after main 3D pass, but before UI psss - draw_3d_graph - .add_node_edge( - bevy::core_pipeline::core_3d::graph::node::MAIN_PASS, - OUTLINE_PASS_NODE_NAME, - ) - .unwrap(); + draw_3d_graph.add_node_edge( + bevy::core_pipeline::core_3d::graph::node::MAIN_PASS, + OUTLINE_PASS_NODE_NAME, + ); #[cfg(feature = "bevy_ui")] - draw_3d_graph - .add_node_edge( - OUTLINE_PASS_NODE_NAME, - bevy::ui::draw_ui_graph::node::UI_PASS, - ) - .unwrap(); + draw_3d_graph.add_node_edge( + OUTLINE_PASS_NODE_NAME, + bevy::ui::draw_ui_graph::node::UI_PASS, + ); } } diff --git a/src/node.rs b/src/node.rs index 84d029a..50349a6 100644 --- a/src/node.rs +++ b/src/node.rs @@ -5,8 +5,7 @@ use bevy::prelude::*; use bevy::render::camera::ExtractedCamera; use bevy::render::render_graph::{NodeRunError, SlotInfo, SlotType}; use bevy::render::render_phase::{ - CachedRenderPipelinePhaseItem, DrawFunctionId, DrawFunctions, EntityPhaseItem, PhaseItem, - RenderPhase, TrackedRenderPass, + CachedRenderPipelinePhaseItem, DrawFunctionId, PhaseItem, RenderPhase, }; use bevy::render::render_resource::{ CachedRenderPipelineId, LoadOp, Operations, RenderPassDepthStencilAttachment, @@ -29,6 +28,11 @@ pub(crate) struct StencilOutline { impl PhaseItem for StencilOutline { type SortKey = Reverse; + #[inline] + fn entity(&self) -> Entity { + self.entity + } + fn sort_key(&self) -> Self::SortKey { Reverse(FloatOrd(self.distance)) } @@ -38,13 +42,6 @@ impl PhaseItem for StencilOutline { } } -impl EntityPhaseItem for StencilOutline { - #[inline] - fn entity(&self) -> Entity { - self.entity - } -} - impl CachedRenderPipelinePhaseItem for StencilOutline { #[inline] fn cached_pipeline(&self) -> CachedRenderPipelineId { @@ -62,6 +59,11 @@ pub(crate) struct OpaqueOutline { impl PhaseItem for OpaqueOutline { type SortKey = Reverse; + #[inline] + fn entity(&self) -> Entity { + self.entity + } + fn sort_key(&self) -> Self::SortKey { Reverse(FloatOrd(self.distance)) } @@ -71,13 +73,6 @@ impl PhaseItem for OpaqueOutline { } } -impl EntityPhaseItem for OpaqueOutline { - #[inline] - fn entity(&self) -> Entity { - self.entity - } -} - impl CachedRenderPipelinePhaseItem for OpaqueOutline { #[inline] fn cached_pipeline(&self) -> CachedRenderPipelineId { @@ -95,6 +90,11 @@ pub(crate) struct TransparentOutline { impl PhaseItem for TransparentOutline { type SortKey = FloatOrd; + #[inline] + fn entity(&self) -> Entity { + self.entity + } + fn sort_key(&self) -> Self::SortKey { FloatOrd(self.distance) } @@ -104,13 +104,6 @@ impl PhaseItem for TransparentOutline { } } -impl EntityPhaseItem for TransparentOutline { - #[inline] - fn entity(&self) -> Entity { - self.entity - } -} - impl CachedRenderPipelinePhaseItem for TransparentOutline { #[inline] fn cached_pipeline(&self) -> CachedRenderPipelineId { @@ -182,19 +175,11 @@ impl Node for OutlineNode { stencil_ops: None, }), }; - let draw_functions = world.resource::>(); - let render_pass = render_context - .command_encoder - .begin_render_pass(&pass_descriptor); - let mut draw_functions = draw_functions.write(); - let mut tracked_pass = TrackedRenderPass::new(render_pass); + let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor); if let Some(viewport) = camera.viewport.as_ref() { tracked_pass.set_camera_viewport(viewport); } - for item in &stencil_phase.items { - let draw_function = draw_functions.get_mut(item.draw_function).unwrap(); - draw_function.draw(world, &mut tracked_pass, view_entity, item); - } + stencil_phase.render(&mut tracked_pass, world, view_entity); } if !opaque_phase.items.is_empty() { @@ -213,19 +198,11 @@ impl Node for OutlineNode { stencil_ops: None, }), }; - let draw_functions = world.resource::>(); - let render_pass = render_context - .command_encoder - .begin_render_pass(&pass_descriptor); - let mut draw_functions = draw_functions.write(); - let mut tracked_pass = TrackedRenderPass::new(render_pass); + let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor); if let Some(viewport) = camera.viewport.as_ref() { tracked_pass.set_camera_viewport(viewport); } - for item in &opaque_phase.items { - let draw_function = draw_functions.get_mut(item.draw_function).unwrap(); - draw_function.draw(world, &mut tracked_pass, view_entity, item); - } + opaque_phase.render(&mut tracked_pass, world, view_entity); } if !transparent_phase.items.is_empty() { @@ -244,19 +221,11 @@ impl Node for OutlineNode { stencil_ops: None, }), }; - let draw_functions = world.resource::>(); - let render_pass = render_context - .command_encoder - .begin_render_pass(&pass_descriptor); - let mut draw_functions = draw_functions.write(); - let mut tracked_pass = TrackedRenderPass::new(render_pass); + let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor); if let Some(viewport) = camera.viewport.as_ref() { tracked_pass.set_camera_viewport(viewport); } - for item in &transparent_phase.items { - let draw_function = draw_functions.get_mut(item.draw_function).unwrap(); - draw_function.draw(world, &mut tracked_pass, view_entity, item); - } + transparent_phase.render(&mut tracked_pass, world, view_entity); } Ok(()) diff --git a/src/pipeline.rs b/src/pipeline.rs index a368b50..828d32a 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -1,13 +1,14 @@ use std::borrow::Cow; +use bevy::pbr::{MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS}; use bevy::prelude::*; use bevy::reflect::TypeUuid; use bevy::render::render_resource::{ BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState, BufferBindingType, BufferSize, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, Face, FragmentState, FrontFace, MultisampleState, PolygonMode, - PrimitiveState, PrimitiveTopology, ShaderSize, ShaderStages, StencilState, TextureFormat, - VertexState, + PrimitiveState, PrimitiveTopology, ShaderDefVal, ShaderSize, ShaderStages, StencilState, + TextureFormat, VertexState, }; use bevy::render::renderer::RenderDevice; use bevy::render::texture::BevyDefault; @@ -61,13 +62,19 @@ impl PipelineKey { PipelineKey(0) } - pub(crate) fn with_msaa_samples(mut self, msaa_samples: u32) -> Self { - self.set_msaa_samples_minus_one(msaa_samples - 1); + pub(crate) fn with_msaa(mut self, msaa: Msaa) -> Self { + self.set_msaa_samples_minus_one(msaa as u32 - 1); self } - pub(crate) fn msaa_samples(&self) -> u32 { - self.msaa_samples_minus_one() + 1 + pub(crate) fn msaa(&self) -> Msaa { + match self.msaa_samples_minus_one() + 1 { + x if x == Msaa::Off as u32 => Msaa::Off, + x if x == Msaa::Sample2 as u32 => Msaa::Sample2, + x if x == Msaa::Sample4 as u32 => Msaa::Sample4, + x if x == Msaa::Sample8 as u32 => Msaa::Sample8, + x => panic!("Invalid value for Msaa: {}", x), + } } pub(crate) fn with_primitive_topology(mut self, primitive_topology: PrimitiveTopology) -> Self { @@ -213,15 +220,28 @@ impl SpecializedMeshPipeline for OutlinePipeline { mesh_layout: &MeshVertexBufferLayout, ) -> Result { let mut targets = vec![]; - let mut bind_layouts = vec![self.mesh_pipeline.view_layout.clone()]; + let mut bind_layouts = vec![if key.msaa() == Msaa::Off { + self.mesh_pipeline.view_layout.clone() + } else { + self.mesh_pipeline.view_layout_multisampled.clone() + }]; let mut buffer_attrs = vec![Mesh::ATTRIBUTE_POSITION.at_shader_location(0)]; - let mut vertex_defs = vec![]; + let mut vertex_defs = vec![ + ShaderDefVal::Int( + "MAX_CASCADES_PER_LIGHT".to_string(), + MAX_CASCADES_PER_LIGHT as i32, + ), + ShaderDefVal::Int( + "MAX_DIRECTIONAL_LIGHTS".to_string(), + MAX_DIRECTIONAL_LIGHTS as i32, + ), + ]; let mut fragment_defs = vec![]; bind_layouts.push( if mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX) && mesh_layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT) { - vertex_defs.push("SKINNED".to_string()); + vertex_defs.push(ShaderDefVal::from("SKINNED")); buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(2)); buffer_attrs.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(3)); self.mesh_pipeline.skinned_mesh_layout.clone() @@ -232,7 +252,7 @@ impl SpecializedMeshPipeline for OutlinePipeline { bind_layouts.push(self.outline_view_bind_group_layout.clone()); let cull_mode; if key.depth_mode() == DepthMode::Flat { - vertex_defs.push("FLAT_DEPTH".to_string()); + vertex_defs.push(ShaderDefVal::from("FLAT_DEPTH")); cull_mode = Some(Face::Back); } else if key.pass_type() == PassType::Stencil { cull_mode = Some(Face::Back); @@ -240,7 +260,7 @@ impl SpecializedMeshPipeline for OutlinePipeline { cull_mode = Some(Face::Front); } if key.offset_zero() { - vertex_defs.push("OFFSET_ZERO".to_string()); + vertex_defs.push(ShaderDefVal::from("OFFSET_ZERO")); } else { buffer_attrs.push( if mesh_layout.contains(ATTRIBUTE_OUTLINE_NORMAL) { @@ -256,7 +276,7 @@ impl SpecializedMeshPipeline for OutlinePipeline { bind_layouts.push(self.outline_stencil_bind_group_layout.clone()); } PassType::Opaque | PassType::Transparent => { - fragment_defs.push("VOLUME".to_string()); + fragment_defs.push(ShaderDefVal::from("VOLUME")); targets.push(Some(ColorTargetState { format: if key.hdr_format() { ViewTarget::TEXTURE_FORMAT_HDR @@ -288,7 +308,7 @@ impl SpecializedMeshPipeline for OutlinePipeline { entry_point: "fragment".into(), targets, }), - layout: Some(bind_layouts), + layout: bind_layouts, primitive: PrimitiveState { front_face: FrontFace::Ccw, cull_mode, @@ -315,10 +335,11 @@ impl SpecializedMeshPipeline for OutlinePipeline { }, }), multisample: MultisampleState { - count: key.msaa_samples(), + count: key.msaa().samples(), mask: !0, alpha_to_coverage_enabled: false, }, + push_constant_ranges: default(), label: Some(Cow::Borrowed("outline_pipeline")), }) } diff --git a/src/uniforms.rs b/src/uniforms.rs index 10ee1ea..5efa110 100644 --- a/src/uniforms.rs +++ b/src/uniforms.rs @@ -1,19 +1,22 @@ use bevy::{ ecs::system::{ - lifetimeless::{Read, SQuery, SRes}, + lifetimeless::{Read, SRes}, SystemParamItem, }, prelude::*, render::{ extract_component::{ComponentUniforms, DynamicUniformIndex}, - render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass}, + render_phase::{PhaseItem, RenderCommand, RenderCommandResult, TrackedRenderPass}, render_resource::{BindGroup, BindGroupDescriptor, BindGroupEntry, ShaderType}, renderer::RenderDevice, Extract, }, }; -use crate::{pipeline::OutlinePipeline, ComputedOutlineDepth, OutlineStencil, OutlineVolume}; +use crate::{ + node::StencilOutline, pipeline::OutlinePipeline, ComputedOutlineDepth, OutlineStencil, + OutlineVolume, +}; #[derive(Clone, Component, ShaderType)] pub(crate) struct OutlineStencilUniform { @@ -150,40 +153,46 @@ pub(crate) fn queue_outline_volume_bind_group( pub(crate) struct SetOutlineStencilBindGroup(); -impl EntityRenderCommand for SetOutlineStencilBindGroup { - type Param = ( - SRes, - SQuery>>, - ); +impl RenderCommand for SetOutlineStencilBindGroup { + type ViewWorldQuery = (); + type ItemWorldQuery = Read>; + type Param = SRes; fn render<'w>( - _view: Entity, - item: Entity, - (bind_group, query): SystemParamItem<'w, '_, Self::Param>, + _item: &StencilOutline, + _view_data: (), + entity_data: &DynamicUniformIndex, + bind_group: 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()]); + pass.set_bind_group( + I, + &bind_group.into_inner().bind_group, + &[entity_data.index()], + ); RenderCommandResult::Success } } pub(crate) struct SetOutlineVolumeBindGroup(); -impl EntityRenderCommand for SetOutlineVolumeBindGroup { - type Param = ( - SRes, - SQuery<( - Read>, - Read>, - )>, +impl RenderCommand

for SetOutlineVolumeBindGroup { + type ViewWorldQuery = (); + type ItemWorldQuery = ( + Read>, + Read>, ); + type Param = SRes; fn render<'w>( - _view: Entity, - item: Entity, - (bind_group, query): SystemParamItem<'w, '_, Self::Param>, + _item: &P, + _view_data: (), + entity_data: ( + &DynamicUniformIndex, + &DynamicUniformIndex, + ), + bind_group: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { - let (vertex, fragment) = query.get(item).unwrap(); + let (vertex, fragment) = entity_data; pass.set_bind_group( I, &bind_group.into_inner().bind_group, diff --git a/src/view_uniforms.rs b/src/view_uniforms.rs index 4e579c5..cbd4968 100644 --- a/src/view_uniforms.rs +++ b/src/view_uniforms.rs @@ -1,9 +1,9 @@ -use bevy::ecs::system::lifetimeless::{Read, SQuery, SRes}; +use bevy::ecs::system::lifetimeless::{Read, SRes}; use bevy::ecs::system::SystemParamItem; use bevy::prelude::*; use bevy::render::extract_component::{ComponentUniforms, DynamicUniformIndex}; use bevy::render::render_phase::{ - EntityRenderCommand, RenderCommandResult, RenderPhase, TrackedRenderPass, + PhaseItem, RenderCommand, RenderCommandResult, RenderPhase, TrackedRenderPass, }; use bevy::render::render_resource::ShaderType; use bevy::render::render_resource::{BindGroup, BindGroupDescriptor, BindGroupEntry}; @@ -70,23 +70,18 @@ pub(crate) fn queue_outline_view_bind_group( pub(crate) struct SetOutlineViewBindGroup(); -impl EntityRenderCommand for SetOutlineViewBindGroup { - type Param = ( - SRes, - SQuery>>, - ); +impl RenderCommand

for SetOutlineViewBindGroup { + type ViewWorldQuery = Read>; + type ItemWorldQuery = (); + type Param = SRes; fn render<'w>( - view: Entity, - _item: Entity, - (bind_group, query): SystemParamItem<'w, '_, Self::Param>, + _item: &P, + view_data: &DynamicUniformIndex, + _entity_data: (), + bind_group: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { - let view_index = query.get(view).unwrap(); - pass.set_bind_group( - I, - &bind_group.into_inner().bind_group, - &[view_index.index()], - ); + pass.set_bind_group(I, &bind_group.into_inner().bind_group, &[view_data.index()]); RenderCommandResult::Success } }