From fffb75b20c04955760017b9741adebdb544b764c Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Fri, 16 Feb 2024 00:30:51 +0000 Subject: [PATCH 01/13] Initial port to Bevy 0.13. --- Cargo.toml | 6 +- examples/animated_fox.rs | 2 +- examples/flying_objects.rs | 21 +++--- examples/pieces.rs | 55 ++++++-------- examples/render_layers.rs | 15 ++-- examples/shapes.rs | 6 +- src/computed.rs | 44 +++++++----- src/lib.rs | 33 ++++----- src/node.rs | 30 ++++---- src/pipeline.rs | 142 +++++++++++++++++-------------------- src/uniforms.rs | 23 +++--- src/view_uniforms.rs | 8 +-- 12 files changed, 186 insertions(+), 199 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5924182..af24399 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["gamedev", "bevy", "outline"] categories = ["game-engines", "rendering"] [dependencies] -bevy = { version = "0.12", default-features = false, features = [ +bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "4ebc560dfb0fee5d3728d1d8f7362f484b784e4c", default-features = false, features = [ "bevy_asset", "bevy_render", "bevy_pbr", @@ -24,10 +24,10 @@ bitfield = "0.14" interpolation = "0.2" interpolation_03 = { package = "interpolation", version = "0.3", optional = true } thiserror = "1.0" -wgpu-types = "0.17" +wgpu-types = "0.19" [dev-dependencies] -bevy = { version = "0.12", default-features = false, features = [ +bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "4ebc560dfb0fee5d3728d1d8f7362f484b784e4c", default-features = false, features = [ "animation", "bevy_gltf", "bevy_pbr", diff --git a/examples/animated_fox.rs b/examples/animated_fox.rs index 416b349..3acb785 100644 --- a/examples/animated_fox.rs +++ b/examples/animated_fox.rs @@ -51,7 +51,7 @@ fn setup( size: 500000.0, subdivisions: 0, })), - material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))), ..default() }); diff --git a/examples/flying_objects.rs b/examples/flying_objects.rs index 6e6cc20..190f344 100644 --- a/examples/flying_objects.rs +++ b/examples/flying_objects.rs @@ -36,18 +36,15 @@ fn setup( mut materials: ResMut>, ) { commands.insert_resource(MyAssets { - mesh: meshes.add( - Capsule { - radius: 1.0, - rings: 10, - depth: 2.0, - latitudes: 15, - longitudes: 15, - ..default() - } - .into(), - ), - material: materials.add(Color::BEIGE.into()), + mesh: meshes.add(Mesh::from(Capsule { + radius: 1.0, + rings: 10, + depth: 2.0, + latitudes: 15, + longitudes: 15, + ..default() + })), + material: materials.add(StandardMaterial::from(Color::BEIGE)), }); // Add light source and camera diff --git a/examples/pieces.rs b/examples/pieces.rs index 2e04dec..30557c4 100644 --- a/examples/pieces.rs +++ b/examples/pieces.rs @@ -32,15 +32,12 @@ fn setup( // Add sphere with child meshes sticking out of it commands .spawn(PbrBundle { - mesh: meshes.add( - UVSphere { - radius: 0.75, - sectors: 30, - stacks: 30, - } - .into(), - ), - material: materials.add(Color::rgb(0.9, 0.1, 0.1).into()), + mesh: meshes.add(Mesh::from(UVSphere { + radius: 0.75, + sectors: 30, + stacks: 30, + })), + material: materials.add(StandardMaterial::from(Color::rgb(0.9, 0.1, 0.1))), transform: Transform::from_translation(Vec3::new(0.0, 1.0, 0.0)), ..default() }) @@ -60,18 +57,15 @@ fn setup( .with_children(|parent| { parent .spawn(PbrBundle { - mesh: meshes.add( - Capsule { - radius: 0.2, - rings: 15, - depth: 1.0, - latitudes: 15, - longitudes: 15, - ..Default::default() - } - .into(), - ), - material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()), + mesh: meshes.add(Mesh::from(Capsule { + radius: 0.2, + rings: 15, + depth: 1.0, + latitudes: 15, + longitudes: 15, + ..Default::default() + })), + material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))), transform: Transform::from_rotation(Quat::from_axis_angle(Vec3::X, TAU / 4.0)) .with_translation(Vec3::new(0.0, 0.0, 0.75)), ..default() @@ -79,16 +73,13 @@ fn setup( .insert(InheritOutlineBundle::default()); parent .spawn(PbrBundle { - mesh: meshes.add( - Torus { - radius: 0.5, - ring_radius: 0.1, - subdivisions_segments: 30, - subdivisions_sides: 15, - } - .into(), - ), - material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()), + mesh: meshes.add(Mesh::from(Torus { + radius: 0.5, + ring_radius: 0.1, + subdivisions_segments: 30, + subdivisions_sides: 15, + })), + material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))), transform: Transform::from_rotation(Quat::from_axis_angle(Vec3::Z, TAU / 4.0)) .with_translation(Vec3::new(0.0, 0.0, -0.75)), ..default() @@ -102,7 +93,7 @@ fn setup( size: 5.0, subdivisions: 0, })), - material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))), ..default() }); commands.spawn(PointLightBundle { diff --git a/examples/render_layers.rs b/examples/render_layers.rs index 3dae2ad..e379f53 100644 --- a/examples/render_layers.rs +++ b/examples/render_layers.rs @@ -1,7 +1,6 @@ use std::f32::consts::PI; use bevy::{ - core_pipeline::clear_color::ClearColorConfig, prelude::{ shape::{Plane, Torus}, *, @@ -45,7 +44,7 @@ fn setup( subdivisions_segments: 40, subdivisions_sides: 20, })), - material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()), + material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))), transform: Transform::from_rotation(Quat::from_rotation_x(0.5 * PI)) .with_translation(0.8 * Vec3::Y), ..default() @@ -67,7 +66,7 @@ fn setup( size: 5.0, subdivisions: 0, })), - material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))), ..default() }); commands.spawn(PointLightBundle { @@ -95,9 +94,6 @@ fn setup( .spawn(Camera3dBundle { camera: Camera { order: i, - ..default() - }, - camera_3d: Camera3d { clear_color: if i > 0 { ClearColorConfig::None } else { @@ -105,6 +101,7 @@ fn setup( }, ..default() }, + camera_3d: Camera3d { ..default() }, transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() }) @@ -117,11 +114,11 @@ fn setup( } fn set_camera_viewports( - win_query: Query<(&Window, Changed), With>, + win_query: Query, With>, mut query: Query<(&mut Camera, &CameraMode)>, ) { - let (win, win_changed) = win_query.get_single().unwrap(); - if win_changed { + let win = win_query.get_single().unwrap(); + if win.is_changed() { // Divide window into quadrants let size = UVec2::new(win.physical_width() / 2, win.physical_height() / 2); for (mut camera, mode) in query.iter_mut() { diff --git a/examples/shapes.rs b/examples/shapes.rs index 96ed028..6f3ecb4 100644 --- a/examples/shapes.rs +++ b/examples/shapes.rs @@ -38,7 +38,7 @@ fn setup( commands .spawn(PbrBundle { mesh: meshes.add(cube_mesh), - material: materials.add(Color::rgb(0.1, 0.1, 0.9).into()), + material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))), transform: Transform::from_xyz(0.0, 1.0, 0.0), ..default() }) @@ -61,7 +61,7 @@ fn setup( subdivisions_segments: 20, subdivisions_sides: 10, })), - material: materials.add(Color::rgb(0.9, 0.1, 0.1).into()), + material: materials.add(StandardMaterial::from(Color::rgb(0.9, 0.1, 0.1))), transform: Transform::from_xyz(0.0, 1.2, 2.0) .with_rotation(Quat::from_rotation_x(0.5 * PI)), ..default() @@ -82,7 +82,7 @@ fn setup( size: 5.0, subdivisions: 0, })), - material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))), ..default() }); commands.spawn(PointLightBundle { diff --git a/src/computed.rs b/src/computed.rs index f25d009..6d7fe6d 100644 --- a/src/computed.rs +++ b/src/computed.rs @@ -58,9 +58,13 @@ impl Sourced { } } - pub fn is_changed(&self, tuple: Option<(&U, bool)>) -> bool { + pub fn is_changed(&self, tuple: &Option>) -> bool { tuple.is_some() != matches!(self.source, Source::Set) - || if let Some((_, c)) = tuple { c } else { false } + || if let Some(r) = tuple { + r.is_changed() + } else { + false + } } } @@ -77,11 +81,11 @@ pub(crate) struct ComputedInternal { pub struct ComputedOutline(pub(crate) Option); type OutlineComponents<'a> = ( - (&'a InheritedVisibility, Changed), - (&'a GlobalTransform, Changed), - Option<(&'a OutlineVolume, Changed)>, - Option<(&'a OutlineStencil, Changed)>, - Option<(&'a OutlineMode, Changed)>, + Ref<'a, InheritedVisibility>, + Ref<'a, GlobalTransform>, + Option>, + Option>, + Option>, ); #[allow(clippy::type_complexity)] @@ -150,7 +154,7 @@ fn propagate_computed_outline( fn update_computed_outline( computed: &mut ComputedOutline, - ((visibility, changed_visibility), (transform, changed_transform), volume, stencil, mode): QueryItem<'_, OutlineComponents>, + (visibility, transform, volume, stencil, mode): QueryItem<'_, OutlineComponents>, parent_computed: &ComputedInternal, parent_entity: Option, force_update: bool, @@ -158,27 +162,31 @@ fn update_computed_outline( let changed = force_update || if let ComputedOutline(Some(computed)) = computed { computed.inherited_from != parent_entity - || changed_visibility - || (changed_transform && matches!(mode, Some((OutlineMode::FlatVertex { .. }, _)))) - || computed.volume.is_changed(volume) - || computed.stencil.is_changed(stencil) - || computed.mode.is_changed(mode) + || visibility.is_changed() + || (transform.is_changed() + && mode + .as_ref() + .map(|r| matches!(r.as_ref(), OutlineMode::FlatVertex { .. })) + .unwrap_or(false)) + || computed.volume.is_changed(&volume) + || computed.stencil.is_changed(&stencil) + || computed.mode.is_changed(&mode) } else { true }; if changed { *computed = ComputedOutline(Some(ComputedInternal { inherited_from: parent_entity, - volume: if let Some((vol, _)) = volume { + volume: if let Some(vol) = volume { Sourced::set(ComputedVolume { enabled: visibility.get() && vol.visible && vol.colour.a() != 0.0, offset: vol.width, - colour: vol.colour.into(), + colour: vol.colour.as_linear_rgba_f32().into(), }) } else { Sourced::inherit(&parent_computed.volume.value) }, - stencil: if let Some((sten, _)) = stencil { + stencil: if let Some(sten) = stencil { Sourced::set(ComputedStencil { enabled: visibility.get() && sten.enabled, offset: sten.offset, @@ -186,8 +194,8 @@ fn update_computed_outline( } else { Sourced::inherit(&parent_computed.stencil.value) }, - mode: if let Some((m, _)) = mode { - Sourced::set(match m { + mode: if let Some(m) = mode { + Sourced::set(match m.as_ref() { OutlineMode::FlatVertex { model_origin: origin, } => ComputedMode { diff --git a/src/lib.rs b/src/lib.rs index 63b9cd3..800a012 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,18 +23,20 @@ //! [`AutoGenerateOutlineNormalsPlugin`]. use bevy::asset::load_internal_asset; +use bevy::core_pipeline::core_3d::graph::{Labels3d, SubGraph3d}; use bevy::prelude::*; use bevy::render::batching::{batch_and_prepare_render_phase, write_batched_instance_buffer}; use bevy::render::extract_component::{ ExtractComponent, ExtractComponentPlugin, UniformComponentPlugin, }; use bevy::render::mesh::MeshVertexAttribute; -use bevy::render::render_graph::RenderGraph; +use bevy::render::render_graph::{RenderGraph, RenderLabel}; use bevy::render::render_phase::{sort_phase_system, AddRenderCommand, DrawFunctions}; use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat}; use bevy::render::view::{RenderLayers, VisibilitySystems}; use bevy::render::{Render, RenderApp, RenderSet}; use bevy::transform::TransformSystem; +use bevy::ui::graph::LabelsUi; use interpolation::Lerp; use crate::draw::{ @@ -72,7 +74,10 @@ pub const ATTRIBUTE_OUTLINE_NORMAL: MeshVertexAttribute = /// /// This node runs after the main 3D passes and before the UI pass. The name can be used to /// add additional constraints on node execution order with respect to other passes. -pub const OUTLINE_PASS_NODE_NAME: &str = "bevy_mod_outline_node"; +#[derive(Copy, Clone, Debug, RenderLabel, Hash, PartialEq, Eq)] +pub enum LabelsOutline { + OutlinePass, +} /// A component for stenciling meshes during outline rendering. #[derive(Clone, Component)] @@ -108,7 +113,7 @@ impl Lerp for OutlineStencil { fn lerp(&self, other: &Self, scalar: &Self::Scalar) -> Self { OutlineStencil { enabled: lerp_bool(self.enabled, other.enabled, *scalar), - offset: self.offset.lerp(&other.offset, scalar), + offset: self.offset.lerp(other.offset, *scalar), } } } @@ -139,7 +144,7 @@ impl Lerp for OutlineVolume { fn lerp(&self, other: &Self, scalar: &Self::Scalar) -> Self { OutlineVolume { visible: lerp_bool(self.visible, other.visible, *scalar), - width: self.width.lerp(&other.width, scalar), + width: self.width.lerp(other.width, *scalar), colour: { let [r, g, b, a] = self .colour @@ -165,11 +170,11 @@ impl interpolation_03::Lerp for OutlineVolume { pub struct OutlineRenderLayers(pub RenderLayers); impl ExtractComponent for OutlineRenderLayers { - type Query = ( + type QueryData = ( Option<&'static OutlineRenderLayers>, Option<&'static RenderLayers>, ); - type Filter = With; + type QueryFilter = With; type Out = Self; fn extract_component( @@ -319,21 +324,13 @@ impl Plugin for OutlinePlugin { let mut graph = world.resource_mut::(); - let draw_3d_graph = graph - .get_sub_graph_mut(bevy::core_pipeline::core_3d::graph::NAME) - .unwrap(); - draw_3d_graph.add_node(OUTLINE_PASS_NODE_NAME, node); + let draw_3d_graph = graph.get_sub_graph_mut(SubGraph3d).unwrap(); + draw_3d_graph.add_node(LabelsOutline::OutlinePass, node); // Run after main 3D pass, but before UI psss - draw_3d_graph.add_node_edge( - bevy::core_pipeline::core_3d::graph::node::END_MAIN_PASS, - OUTLINE_PASS_NODE_NAME, - ); + draw_3d_graph.add_node_edge(Labels3d::EndMainPass, LabelsOutline::OutlinePass); #[cfg(feature = "bevy_ui")] - draw_3d_graph.add_node_edge( - OUTLINE_PASS_NODE_NAME, - bevy::ui::draw_ui_graph::node::UI_PASS, - ); + draw_3d_graph.add_node_edge(LabelsOutline::OutlinePass, LabelsUi::UiPass); } fn finish(&self, app: &mut App) { diff --git a/src/node.rs b/src/node.rs index 41f1bfa..b952653 100644 --- a/src/node.rs +++ b/src/node.rs @@ -10,7 +10,7 @@ use bevy::render::render_phase::{ }; use bevy::render::render_resource::{ CachedRenderPipelineId, LoadOp, Operations, RenderPassDepthStencilAttachment, - RenderPassDescriptor, + RenderPassDescriptor, StoreOp, }; use bevy::render::view::{ExtractedView, ViewDepthTexture, ViewTarget}; use bevy::render::{ @@ -217,13 +217,15 @@ impl Node for OutlineNode { label: Some("outline_stencil_pass"), color_attachments: &[], depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { - view: &depth.view, + view: &depth.view(), depth_ops: Some(Operations { load: camera_3d.depth_load_op.clone().into(), - store: true, + store: StoreOp::Store, }), stencil_ops: None, }), + timestamp_writes: None, + occlusion_query_set: None, }; let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor); if let Some(viewport) = camera.viewport.as_ref() { @@ -235,18 +237,17 @@ impl Node for OutlineNode { if !opaque_phase.items.is_empty() { let pass_descriptor = RenderPassDescriptor { label: Some("outline_opaque_pass"), - color_attachments: &[Some(target.get_color_attachment(Operations { - load: LoadOp::Load, - store: true, - }))], + color_attachments: &[Some(target.get_color_attachment())], depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { - view: &depth.view, + view: &depth.view(), depth_ops: Some(Operations { load: LoadOp::Load, - store: true, + store: StoreOp::Store, }), stencil_ops: None, }), + timestamp_writes: None, + occlusion_query_set: None, }; let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor); if let Some(viewport) = camera.viewport.as_ref() { @@ -258,18 +259,17 @@ impl Node for OutlineNode { if !transparent_phase.items.is_empty() { let pass_descriptor = RenderPassDescriptor { label: Some("outline_transparent_pass"), - color_attachments: &[Some(target.get_color_attachment(Operations { - load: LoadOp::Load, - store: true, - }))], + color_attachments: &[Some(target.get_color_attachment())], depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { - view: &depth.view, + view: &depth.view(), depth_ops: Some(Operations { load: LoadOp::Load, - store: true, + store: StoreOp::Store, }), stencil_ops: None, }), + timestamp_writes: None, + occlusion_query_set: None, }; let mut tracked_pass = render_context.begin_tracked_render_pass(pass_descriptor); if let Some(viewport) = camera.viewport.as_ref() { diff --git a/src/pipeline.rs b/src/pipeline.rs index 1cebe5f..12dad97 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; -use bevy::ecs::query::QueryItem; -use bevy::ecs::system::lifetimeless::Read; +use bevy::ecs::system::lifetimeless::SQuery; use bevy::ecs::system::SystemParamItem; use bevy::pbr::{ setup_morph_and_skinning_defs, MeshFlags, MeshPipelineKey, MeshTransforms, MeshUniform, @@ -9,11 +8,10 @@ use bevy::pbr::{ use bevy::prelude::*; use bevy::render::batching::GetBatchData; use bevy::render::render_resource::{ - BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendState, - BufferBindingType, BufferSize, ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, - DepthStencilState, Face, FragmentState, FrontFace, MultisampleState, PolygonMode, - PrimitiveState, PrimitiveTopology, ShaderDefVal, ShaderSize, ShaderStages, ShaderType, - StencilState, TextureFormat, VertexState, + BindGroupLayout, BindGroupLayoutEntry, BindingType, BlendState, BufferBindingType, BufferSize, + ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState, Face, + FragmentState, FrontFace, MultisampleState, PolygonMode, PrimitiveState, PrimitiveTopology, + ShaderDefVal, ShaderSize, ShaderStages, ShaderType, StencilState, TextureFormat, VertexState, }; use bevy::render::renderer::RenderDevice; use bevy::render::settings::WgpuSettings; @@ -168,76 +166,71 @@ impl FromWorld for OutlinePipeline { let world = world.cell(); let mesh_pipeline = world.get_resource::().unwrap().clone(); let render_device = world.get_resource::().unwrap(); - let outline_view_bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("outline_view_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(OutlineViewUniform::min_size()), - }, - count: None, - }, - ], - }); - let outline_volume_bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("outline_volume_bind_group_layout"), - entries: &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: BufferSize::new( - OutlineVolumeUniform::SHADER_SIZE.get(), - ), - }, - count: None, + let outline_view_bind_group_layout = render_device.create_bind_group_layout( + "outline_view_bind_group_layout", + &[ + BindGroupLayoutEntry { + binding: 0, + visibility: ShaderStages::VERTEX, + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: true, + min_binding_size: Some(ViewUniform::min_size()), }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::FRAGMENT, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: BufferSize::new( - OutlineFragmentUniform::SHADER_SIZE.get(), - ), - }, - count: None, + count: None, + }, + BindGroupLayoutEntry { + binding: 1, + visibility: ShaderStages::VERTEX, + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: true, + min_binding_size: Some(OutlineViewUniform::min_size()), }, - ], - }); - let outline_stencil_bind_group_layout = - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("outline_stencil_bind_group_layout"), - entries: &[BindGroupLayoutEntry { + count: None, + }, + ], + ); + let outline_volume_bind_group_layout = render_device.create_bind_group_layout( + "outline_volume_bind_group_layout", + &[ + BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::VERTEX, ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: true, - min_binding_size: BufferSize::new(OutlineStencilUniform::SHADER_SIZE.get()), + min_binding_size: BufferSize::new(OutlineVolumeUniform::SHADER_SIZE.get()), }, count: None, - }], - }); + }, + BindGroupLayoutEntry { + binding: 1, + visibility: ShaderStages::FRAGMENT, + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: true, + min_binding_size: BufferSize::new( + OutlineFragmentUniform::SHADER_SIZE.get(), + ), + }, + count: None, + }, + ], + ); + let outline_stencil_bind_group_layout = render_device.create_bind_group_layout( + "outline_stencil_bind_group_layout", + &[BindGroupLayoutEntry { + binding: 0, + visibility: ShaderStages::VERTEX, + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: true, + min_binding_size: BufferSize::new(OutlineStencilUniform::SHADER_SIZE.get()), + }, + count: None, + }], + ); OutlinePipeline { mesh_pipeline, outline_view_bind_group_layout, @@ -373,21 +366,20 @@ impl SpecializedMeshPipeline for OutlinePipeline { } impl GetBatchData for OutlinePipeline { - type Param = (); - type Query = Read; - type QueryFilter = (); + type Param = SQuery<&'static ExtractedOutline>; type CompareData = (); type BufferData = MeshUniform; fn get_batch_data( - _: &SystemParamItem, - outline: &QueryItem, - ) -> (Self::BufferData, Option) { + param: &SystemParamItem, + entity: Entity, + ) -> Option<(Self::BufferData, Option)> { + let outline = param.get(entity).unwrap(); let ts = MeshTransforms { transform: (&outline.transform).into(), previous_transform: (&outline.transform).into(), flags: MeshFlags::NONE.bits(), }; - ((&ts).into(), None) + Some((MeshUniform::new(&ts, None), None)) } } diff --git a/src/uniforms.rs b/src/uniforms.rs index 86b04e7..6f9eb96 100644 --- a/src/uniforms.rs +++ b/src/uniforms.rs @@ -149,20 +149,23 @@ pub(crate) fn prepare_outline_volume_bind_group( pub(crate) struct SetOutlineStencilBindGroup(); impl RenderCommand for SetOutlineStencilBindGroup { - type ViewWorldQuery = (); - type ItemWorldQuery = Read>; + type ViewQuery = (); + type ItemQuery = Read>; type Param = SRes; fn render<'w>( _item: &StencilOutline, _view_data: (), - entity_data: &DynamicUniformIndex, + entity_data: Option<&DynamicUniformIndex>, bind_group: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { + let Some(dyn_uniform) = entity_data else { + return RenderCommandResult::Failure; + }; pass.set_bind_group( I, &bind_group.into_inner().bind_group, - &[entity_data.index()], + &[dyn_uniform.index()], ); RenderCommandResult::Success } @@ -171,8 +174,8 @@ impl RenderCommand for SetOutlineStencilBindGrou pub(crate) struct SetOutlineVolumeBindGroup(); impl RenderCommand

for SetOutlineVolumeBindGroup { - type ViewWorldQuery = (); - type ItemWorldQuery = ( + type ViewQuery = (); + type ItemQuery = ( Read>, Read>, ); @@ -180,14 +183,16 @@ impl RenderCommand

for SetOutlineVolumeBindGrou fn render<'w>( _item: &P, _view_data: (), - entity_data: ( + entity_data: Option<( &DynamicUniformIndex, &DynamicUniformIndex, - ), + )>, bind_group: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { - let (vertex, fragment) = entity_data; + let Some((vertex, fragment)) = entity_data else { + return RenderCommandResult::Failure; + }; pass.set_bind_group( I, &bind_group.into_inner().bind_group, diff --git a/src/view_uniforms.rs b/src/view_uniforms.rs index 5582e92..4d8eb76 100644 --- a/src/view_uniforms.rs +++ b/src/view_uniforms.rs @@ -82,16 +82,16 @@ pub(crate) fn prepare_outline_view_bind_group( pub(crate) struct SetOutlineViewBindGroup(); impl RenderCommand

for SetOutlineViewBindGroup { - type ViewWorldQuery = ( + type ViewQuery = ( Read, Read>, ); - type ItemWorldQuery = (); + type ItemQuery = (); type Param = SRes; fn render<'w>( _item: &P, - (core_view_data, outline_view_data): ROQueryItem<'w, Self::ViewWorldQuery>, - _entity_data: (), + (core_view_data, outline_view_data): ROQueryItem<'w, Self::ViewQuery>, + _entity_data: Option<()>, bind_group: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { From e8fe3d4b95833efc383eef4e10fb177ae4de2e36 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Fri, 16 Feb 2024 00:35:59 +0000 Subject: [PATCH 02/13] Fix Clippy lints. --- src/node.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node.rs b/src/node.rs index b952653..1487ae9 100644 --- a/src/node.rs +++ b/src/node.rs @@ -217,7 +217,7 @@ impl Node for OutlineNode { label: Some("outline_stencil_pass"), color_attachments: &[], depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { - view: &depth.view(), + view: depth.view(), depth_ops: Some(Operations { load: camera_3d.depth_load_op.clone().into(), store: StoreOp::Store, @@ -239,7 +239,7 @@ impl Node for OutlineNode { label: Some("outline_opaque_pass"), color_attachments: &[Some(target.get_color_attachment())], depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { - view: &depth.view(), + view: depth.view(), depth_ops: Some(Operations { load: LoadOp::Load, store: StoreOp::Store, @@ -261,7 +261,7 @@ impl Node for OutlineNode { label: Some("outline_transparent_pass"), color_attachments: &[Some(target.get_color_attachment())], depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { - view: &depth.view(), + view: depth.view(), depth_ops: Some(Operations { load: LoadOp::Load, store: StoreOp::Store, From 9622c85367e8d62c8fcb9a7cea867e601ef27d62 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Fri, 16 Feb 2024 21:51:21 +0000 Subject: [PATCH 03/13] Change deprecated shapes to new primitives in examples. Fix example lighting. --- examples/animated_fox.rs | 21 ++++++--------- examples/flying_objects.rs | 21 +++++++-------- examples/hollow.rs | 5 +--- examples/morph_targets.rs | 5 +--- examples/pieces.rs | 52 +++++++++++++++----------------------- examples/render_layers.rs | 27 +++++++++----------- examples/shapes.rs | 32 ++++++++++------------- 7 files changed, 65 insertions(+), 98 deletions(-) diff --git a/examples/animated_fox.rs b/examples/animated_fox.rs index 3acb785..4d17a57 100644 --- a/examples/animated_fox.rs +++ b/examples/animated_fox.rs @@ -1,10 +1,6 @@ use std::f32::consts::PI; -use bevy::{ - prelude::{shape::Plane, *}, - scene::SceneInstance, - window::close_on_esc, -}; +use bevy::{prelude::*, scene::SceneInstance, window::close_on_esc}; use bevy_mod_outline::{ AutoGenerateOutlineNormalsPlugin, InheritOutlineBundle, OutlineBundle, OutlinePlugin, OutlineVolume, @@ -20,10 +16,7 @@ fn main() { OutlinePlugin, AutoGenerateOutlineNormalsPlugin, )) - .insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 1.0, - }) + .insert_resource(AmbientLight::default()) .add_systems(Startup, setup) .add_systems(Update, (setup_scene_once_loaded, close_on_esc)) .run(); @@ -47,10 +40,12 @@ fn setup( // Plane commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Plane { - size: 500000.0, - subdivisions: 0, - })), + mesh: meshes.add( + Plane3d::new(Vec3::Y) + .mesh() + .size(500000.0, 500000.0) + .build(), + ), material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))), ..default() }); diff --git a/examples/flying_objects.rs b/examples/flying_objects.rs index 190f344..f019a72 100644 --- a/examples/flying_objects.rs +++ b/examples/flying_objects.rs @@ -1,9 +1,6 @@ use std::{f32::consts::TAU, num::Wrapping, time::Duration}; -use bevy::{ - prelude::{shape::Capsule, *}, - window::close_on_esc, -}; +use bevy::{prelude::*, window::close_on_esc}; use bevy_mod_outline::*; @@ -36,14 +33,14 @@ fn setup( mut materials: ResMut>, ) { commands.insert_resource(MyAssets { - mesh: meshes.add(Mesh::from(Capsule { - radius: 1.0, - rings: 10, - depth: 2.0, - latitudes: 15, - longitudes: 15, - ..default() - })), + mesh: meshes.add( + Capsule3d::new(1.0, 2.0) + .mesh() + .rings(10) + .latitudes(15) + .longitudes(15) + .build(), + ), material: materials.add(StandardMaterial::from(Color::BEIGE)), }); diff --git a/examples/hollow.rs b/examples/hollow.rs index 2efb6c7..0803c6a 100644 --- a/examples/hollow.rs +++ b/examples/hollow.rs @@ -13,10 +13,7 @@ fn main() { ), ) .add_plugins(OutlinePlugin) - .insert_resource(AmbientLight { - color: Color::WHITE, - brightness: 1.0, - }) + .insert_resource(AmbientLight::default()) .add_systems(Startup, setup) .add_systems( Update, diff --git a/examples/morph_targets.rs b/examples/morph_targets.rs index d7e04c8..a04ee46 100644 --- a/examples/morph_targets.rs +++ b/examples/morph_targets.rs @@ -27,10 +27,7 @@ fn main() { OutlinePlugin, AutoGenerateOutlineNormalsPlugin, )) - .insert_resource(AmbientLight { - brightness: 1.0, - ..default() - }) + .insert_resource(AmbientLight::default()) .add_systems(Startup, setup) .add_systems(Update, (name_morphs, setup_outlines, setup_animations)) .run(); diff --git a/examples/pieces.rs b/examples/pieces.rs index 30557c4..7cf30d3 100644 --- a/examples/pieces.rs +++ b/examples/pieces.rs @@ -1,12 +1,6 @@ use std::f32::consts::TAU; -use bevy::{ - prelude::{ - shape::{Capsule, Plane, Torus, UVSphere}, - *, - }, - window::close_on_esc, -}; +use bevy::{prelude::*, window::close_on_esc}; use bevy_mod_outline::*; @@ -32,11 +26,7 @@ fn setup( // Add sphere with child meshes sticking out of it commands .spawn(PbrBundle { - mesh: meshes.add(Mesh::from(UVSphere { - radius: 0.75, - sectors: 30, - stacks: 30, - })), + mesh: meshes.add(Sphere::new(0.75).mesh().uv(30, 30)), material: materials.add(StandardMaterial::from(Color::rgb(0.9, 0.1, 0.1))), transform: Transform::from_translation(Vec3::new(0.0, 1.0, 0.0)), ..default() @@ -57,14 +47,14 @@ fn setup( .with_children(|parent| { parent .spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Capsule { - radius: 0.2, - rings: 15, - depth: 1.0, - latitudes: 15, - longitudes: 15, - ..Default::default() - })), + mesh: meshes.add( + Capsule3d::new(0.2, 1.0) + .mesh() + .rings(15) + .latitudes(15) + .longitudes(15) + .build(), + ), material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))), transform: Transform::from_rotation(Quat::from_axis_angle(Vec3::X, TAU / 4.0)) .with_translation(Vec3::new(0.0, 0.0, 0.75)), @@ -73,12 +63,16 @@ fn setup( .insert(InheritOutlineBundle::default()); parent .spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Torus { - radius: 0.5, - ring_radius: 0.1, - subdivisions_segments: 30, - subdivisions_sides: 15, - })), + mesh: meshes.add( + Torus { + minor_radius: 0.1, + major_radius: 0.5, + } + .mesh() + .minor_resolution(15) + .major_resolution(30) + .build(), + ), material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))), transform: Transform::from_rotation(Quat::from_axis_angle(Vec3::Z, TAU / 4.0)) .with_translation(Vec3::new(0.0, 0.0, -0.75)), @@ -89,16 +83,12 @@ fn setup( // Add plane, light source, and camera commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Plane { - size: 5.0, - subdivisions: 0, - })), + mesh: meshes.add(Plane3d::new(Vec3::Y).mesh().size(5.0, 5.0).build()), material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))), ..default() }); commands.spawn(PointLightBundle { point_light: PointLight { - intensity: 1500.0, shadows_enabled: true, ..default() }, diff --git a/examples/render_layers.rs b/examples/render_layers.rs index e379f53..b093eab 100644 --- a/examples/render_layers.rs +++ b/examples/render_layers.rs @@ -1,10 +1,7 @@ use std::f32::consts::PI; use bevy::{ - prelude::{ - shape::{Plane, Torus}, - *, - }, + prelude::*, render::{camera::Viewport, view::RenderLayers}, window::{close_on_esc, PrimaryWindow}, }; @@ -38,12 +35,16 @@ fn setup( // Add torus using the regular surface normals for outlining commands .spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Torus { - radius: 0.6, - ring_radius: 0.2, - subdivisions_segments: 40, - subdivisions_sides: 20, - })), + mesh: meshes.add( + Torus { + minor_radius: 0.2, + major_radius: 0.6, + } + .mesh() + .minor_resolution(20) + .major_resolution(40) + .build(), + ), material: materials.add(StandardMaterial::from(Color::rgb(0.1, 0.1, 0.9))), transform: Transform::from_rotation(Quat::from_rotation_x(0.5 * PI)) .with_translation(0.8 * Vec3::Y), @@ -62,16 +63,12 @@ fn setup( // Add plane and light source commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Plane { - size: 5.0, - subdivisions: 0, - })), + mesh: meshes.add(Plane3d::new(Vec3::Y).mesh().size(5.0, 5.0).build()), material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))), ..default() }); commands.spawn(PointLightBundle { point_light: PointLight { - intensity: 1500.0, shadows_enabled: true, ..default() }, diff --git a/examples/shapes.rs b/examples/shapes.rs index 6f3ecb4..59e5c89 100644 --- a/examples/shapes.rs +++ b/examples/shapes.rs @@ -1,12 +1,6 @@ use std::f32::consts::{PI, TAU}; -use bevy::{ - prelude::{ - shape::{Cube, Plane, Torus}, - *, - }, - window::close_on_esc, -}; +use bevy::{prelude::*, window::close_on_esc}; use bevy_mod_outline::*; @@ -33,7 +27,7 @@ fn setup( mut materials: ResMut>, ) { // Add cube with generated outline normals - let mut cube_mesh = Mesh::from(Cube { size: 1.0 }); + let mut cube_mesh = Cuboid::new(1.0, 1.0, 1.0).mesh(); cube_mesh.generate_outline_normals().unwrap(); commands .spawn(PbrBundle { @@ -55,12 +49,16 @@ fn setup( // Add torus using the regular surface normals for outlining commands .spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Torus { - radius: 0.3, - ring_radius: 0.1, - subdivisions_segments: 20, - subdivisions_sides: 10, - })), + mesh: meshes.add( + Torus { + minor_radius: 0.1, + major_radius: 0.3, + } + .mesh() + .minor_resolution(10) + .major_resolution(20) + .build(), + ), material: materials.add(StandardMaterial::from(Color::rgb(0.9, 0.1, 0.1))), transform: Transform::from_xyz(0.0, 1.2, 2.0) .with_rotation(Quat::from_rotation_x(0.5 * PI)), @@ -78,16 +76,12 @@ fn setup( // Add plane, light source, and camera commands.spawn(PbrBundle { - mesh: meshes.add(Mesh::from(Plane { - size: 5.0, - subdivisions: 0, - })), + mesh: meshes.add(Plane3d::new(Vec3::Y).mesh().size(5.0, 5.0).build()), material: materials.add(StandardMaterial::from(Color::rgb(0.3, 0.5, 0.3))), ..default() }); commands.spawn(PointLightBundle { point_light: PointLight { - intensity: 1500.0, shadows_enabled: true, ..default() }, From 76c802bf3e90260bcfce20dd81caeed6f2cad681 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Fri, 16 Feb 2024 21:58:17 +0000 Subject: [PATCH 04/13] Update Bevy master commit hash. --- Cargo.toml | 4 ++-- src/lib.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af24399..af3eb24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["gamedev", "bevy", "outline"] categories = ["game-engines", "rendering"] [dependencies] -bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "4ebc560dfb0fee5d3728d1d8f7362f484b784e4c", default-features = false, features = [ +bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "f83de49b7a9e2c6c3ac4e94b44bcc02806aa8e90", default-features = false, features = [ "bevy_asset", "bevy_render", "bevy_pbr", @@ -27,7 +27,7 @@ thiserror = "1.0" wgpu-types = "0.19" [dev-dependencies] -bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "4ebc560dfb0fee5d3728d1d8f7362f484b784e4c", default-features = false, features = [ +bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "f83de49b7a9e2c6c3ac4e94b44bcc02806aa8e90", default-features = false, features = [ "animation", "bevy_gltf", "bevy_pbr", diff --git a/src/lib.rs b/src/lib.rs index 800a012..ab01dc8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ //! [`AutoGenerateOutlineNormalsPlugin`]. use bevy::asset::load_internal_asset; -use bevy::core_pipeline::core_3d::graph::{Labels3d, SubGraph3d}; +use bevy::core_pipeline::core_3d::graph::{Node3d, Core3d}; use bevy::prelude::*; use bevy::render::batching::{batch_and_prepare_render_phase, write_batched_instance_buffer}; use bevy::render::extract_component::{ @@ -36,7 +36,7 @@ use bevy::render::render_resource::{SpecializedMeshPipelines, VertexFormat}; use bevy::render::view::{RenderLayers, VisibilitySystems}; use bevy::render::{Render, RenderApp, RenderSet}; use bevy::transform::TransformSystem; -use bevy::ui::graph::LabelsUi; +use bevy::ui::graph::NodeUi; use interpolation::Lerp; use crate::draw::{ @@ -324,13 +324,13 @@ impl Plugin for OutlinePlugin { let mut graph = world.resource_mut::(); - let draw_3d_graph = graph.get_sub_graph_mut(SubGraph3d).unwrap(); + let draw_3d_graph = graph.get_sub_graph_mut(Core3d).unwrap(); draw_3d_graph.add_node(LabelsOutline::OutlinePass, node); // Run after main 3D pass, but before UI psss - draw_3d_graph.add_node_edge(Labels3d::EndMainPass, LabelsOutline::OutlinePass); + draw_3d_graph.add_node_edge(Node3d::EndMainPass, LabelsOutline::OutlinePass); #[cfg(feature = "bevy_ui")] - draw_3d_graph.add_node_edge(LabelsOutline::OutlinePass, LabelsUi::UiPass); + draw_3d_graph.add_node_edge(LabelsOutline::OutlinePass, NodeUi::UiPass); } fn finish(&self, app: &mut App) { From 6f3f08a9e24120b8992dd096fec320bda95df68c Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Sat, 17 Feb 2024 00:02:07 +0000 Subject: [PATCH 05/13] Fix formatting. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index ab01dc8..13f4490 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ //! [`AutoGenerateOutlineNormalsPlugin`]. use bevy::asset::load_internal_asset; -use bevy::core_pipeline::core_3d::graph::{Node3d, Core3d}; +use bevy::core_pipeline::core_3d::graph::{Core3d, Node3d}; use bevy::prelude::*; use bevy::render::batching::{batch_and_prepare_render_phase, write_batched_instance_buffer}; use bevy::render::extract_component::{ From a78157a85b882367e97c9e5c88d1b24343e08a1a Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Sun, 18 Feb 2024 10:25:07 +0000 Subject: [PATCH 06/13] Update deps to 0.13 release. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af3eb24..5f2fa8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["gamedev", "bevy", "outline"] categories = ["game-engines", "rendering"] [dependencies] -bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "f83de49b7a9e2c6c3ac4e94b44bcc02806aa8e90", default-features = false, features = [ +bevy = { version = "0.13", default-features = false, features = [ "bevy_asset", "bevy_render", "bevy_pbr", @@ -27,7 +27,7 @@ thiserror = "1.0" wgpu-types = "0.19" [dev-dependencies] -bevy = { git = "https://github.com/bevyengine/bevy.git", rev = "f83de49b7a9e2c6c3ac4e94b44bcc02806aa8e90", default-features = false, features = [ +bevy = { version = "0.13", default-features = false, features = [ "animation", "bevy_gltf", "bevy_pbr", From 66db3b80659be6cac640bada9163d5107305df4d Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Mon, 19 Feb 2024 23:01:46 +0000 Subject: [PATCH 07/13] Temporarily disable MSAA in render_layers example pending Bevy 0.13.1. --- examples/render_layers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/render_layers.rs b/examples/render_layers.rs index b093eab..13bb085 100644 --- a/examples/render_layers.rs +++ b/examples/render_layers.rs @@ -10,7 +10,7 @@ use bevy_mod_outline::{OutlineBundle, OutlinePlugin, OutlineRenderLayers, Outlin #[bevy_main] fn main() { App::new() - .insert_resource(Msaa::Sample4) + .insert_resource(Msaa::Off) // Disabled temporarily due to bevyengine/bevy#11968. .insert_resource(ClearColor(Color::BLACK)) .add_plugins((DefaultPlugins, OutlinePlugin)) .add_systems(Startup, setup) From 76ecdc80b60540afe10c349fea3b599e7c92f457 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Fri, 1 Mar 2024 21:22:37 +0000 Subject: [PATCH 08/13] Update version and read-me for 0.7.0. --- Cargo.toml | 2 +- README.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5f2fa8b..123464d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_mod_outline" -version = "0.6.2" +version = "0.7.0" edition = "2021" license = "MIT OR Apache-2.0" description = "A mesh outlining plugin for Bevy." diff --git a/README.md b/README.md index 841902a..91751b4 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ vertex extrusion method. ```toml [dependencies] -bevy_mod_outline = "0.6" +bevy_mod_outline = "0.7" ``` ## Examples @@ -66,6 +66,7 @@ cargo run --example morph_targets | This Version | Bevy version | |--------------|--------------| +| 0.7.x | 0.13.x | | 0.6.x | 0.12.x | | 0.5.x | 0.11.x | | 0.4.x | 0.10.x | From 8964bdf9d696406dc009caeacf79099d986bf218 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Fri, 1 Mar 2024 21:31:12 +0000 Subject: [PATCH 09/13] Upgrade base interpolation to 0.3 and remove interpolation_03 feature. --- Cargo.toml | 3 +-- README.md | 3 --- src/lib.rs | 18 ------------------ 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 123464d..77aa549 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,7 @@ bevy = { version = "0.13", default-features = false, features = [ "bevy_core_pipeline", ] } bitfield = "0.14" -interpolation = "0.2" -interpolation_03 = { package = "interpolation", version = "0.3", optional = true } +interpolation = "0.3" thiserror = "1.0" wgpu-types = "0.19" diff --git a/README.md b/README.md index 91751b4..7b21125 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,6 @@ cargo run --example morph_targets - `bevy_ui` _(default)_ - Adds a render graph edge to prevent clashing with the UI. This adds a dependency on the `bevy_ui` crate and can be disabled if it is not used. -- `interpolation_03` - Define `Lerp` trait impls using version 0.3 of the -`interpolation` crate in addition to 0.2. This will become the default in the -next breaking release. ## Licence diff --git a/src/lib.rs b/src/lib.rs index 13f4490..a5d6586 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,15 +118,6 @@ impl Lerp for OutlineStencil { } } -#[cfg(feature = "interpolation_03")] -impl interpolation_03::Lerp for OutlineStencil { - type Scalar = f32; - - fn lerp(&self, other: &Self, scalar: &Self::Scalar) -> Self { - ::lerp(self, other, scalar) - } -} - /// A component for rendering outlines around meshes. #[derive(Clone, Component, Default)] pub struct OutlineVolume { @@ -156,15 +147,6 @@ impl Lerp for OutlineVolume { } } -#[cfg(feature = "interpolation_03")] -impl interpolation_03::Lerp for OutlineVolume { - type Scalar = f32; - - fn lerp(&self, other: &Self, scalar: &Self::Scalar) -> Self { - ::lerp(self, other, scalar) - } -} - /// 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); From 72e8d73008ba0030cfb7351293dcfd7226243568 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Fri, 1 Mar 2024 23:06:40 +0000 Subject: [PATCH 10/13] Rename LabelsOutline to NodeOutline and fix docs. --- src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a5d6586..74c4c83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,12 +70,10 @@ pub use generate::*; pub const ATTRIBUTE_OUTLINE_NORMAL: MeshVertexAttribute = MeshVertexAttribute::new("Outline_Normal", 1585570526, VertexFormat::Float32x3); -/// Name of the render graph node which draws the outlines. -/// -/// This node runs after the main 3D passes and before the UI pass. The name can be used to -/// add additional constraints on node execution order with respect to other passes. +/// Labels for render graph nodes which draw outlines. #[derive(Copy, Clone, Debug, RenderLabel, Hash, PartialEq, Eq)] -pub enum LabelsOutline { +pub enum NodeOutline { + /// This node runs after the main 3D passes and before the UI pass. OutlinePass, } @@ -307,12 +305,12 @@ impl Plugin for OutlinePlugin { let mut graph = world.resource_mut::(); let draw_3d_graph = graph.get_sub_graph_mut(Core3d).unwrap(); - draw_3d_graph.add_node(LabelsOutline::OutlinePass, node); + draw_3d_graph.add_node(NodeOutline::OutlinePass, node); // Run after main 3D pass, but before UI psss - draw_3d_graph.add_node_edge(Node3d::EndMainPass, LabelsOutline::OutlinePass); + draw_3d_graph.add_node_edge(Node3d::EndMainPass, NodeOutline::OutlinePass); #[cfg(feature = "bevy_ui")] - draw_3d_graph.add_node_edge(LabelsOutline::OutlinePass, NodeUi::UiPass); + draw_3d_graph.add_node_edge(NodeOutline::OutlinePass, NodeUi::UiPass); } fn finish(&self, app: &mut App) { From c4d058c94e69de022fdb660326220e9abf80ee83 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Sat, 2 Mar 2024 22:32:29 +0000 Subject: [PATCH 11/13] Revert back to using SetMeshViewBindGroup. --- src/draw.rs | 71 ++++++++++++++++++++++++++++++++++++++------ src/fragment.wgsl | 2 +- src/outline.wgsl | 6 ++-- src/pipeline.rs | 67 +++++++++++++++++++++-------------------- src/view_uniforms.rs | 37 +++++++---------------- 5 files changed, 110 insertions(+), 73 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 7d9b5e3..abd5184 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -1,4 +1,7 @@ -use bevy::pbr::{DrawMesh, SetMeshBindGroup}; +use bevy::core_pipeline::prepass::{ + DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass, +}; +use bevy::pbr::{DrawMesh, MeshPipelineViewLayoutKey, SetMeshBindGroup, SetMeshViewBindGroup}; use bevy::prelude::*; use bevy::render::render_asset::RenderAssets; use bevy::render::render_phase::{DrawFunctions, RenderPhase, SetItemPipeline}; @@ -16,12 +19,47 @@ use crate::OutlineRenderLayers; pub(crate) type DrawStencil = ( SetItemPipeline, - SetOutlineViewBindGroup<0>, + SetMeshViewBindGroup<0>, SetMeshBindGroup<1>, - SetOutlineStencilBindGroup<2>, + SetOutlineViewBindGroup<2>, + SetOutlineStencilBindGroup<3>, DrawMesh, ); +fn build_mesh_pipeline_view_layout_key( + msaa: Msaa, + (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass): ( + bool, + bool, + bool, + bool, + ), +) -> MeshPipelineViewLayoutKey { + let mut view_key = MeshPipelineViewLayoutKey::empty(); + + if msaa != Msaa::Off { + view_key |= MeshPipelineViewLayoutKey::MULTISAMPLED; + } + + if normal_prepass { + view_key |= MeshPipelineViewLayoutKey::NORMAL_PREPASS; + } + + if depth_prepass { + view_key |= MeshPipelineViewLayoutKey::DEPTH_PREPASS; + } + + if motion_vector_prepass { + view_key |= MeshPipelineViewLayoutKey::MOTION_VECTOR_PREPASS; + } + + if deferred_prepass { + view_key |= MeshPipelineViewLayoutKey::DEFERRED_PREPASS; + } + + view_key +} + #[allow(clippy::too_many_arguments, clippy::type_complexity)] pub(crate) fn queue_outline_stencil_mesh( stencil_draw_functions: Res>, @@ -40,6 +78,12 @@ pub(crate) fn queue_outline_stencil_mesh( &ExtractedView, &mut RenderPhase, Option<&RenderLayers>, + ( + Has, + Has, + Has, + Has, + ), )>, ) { let draw_stencil = stencil_draw_functions @@ -51,7 +95,7 @@ pub(crate) fn queue_outline_stencil_mesh( .with_msaa(*msaa) .with_pass_type(PassType::Stencil); - for (view, mut stencil_phase, view_mask) in views.iter_mut() { + for (view, mut stencil_phase, view_mask, prepasses) in views.iter_mut() { let rangefinder = view.rangefinder3d(); let view_mask = view_mask.copied().unwrap_or_default(); for (entity, stencil_uniform, outline, outline_mask) in material_meshes.iter() { @@ -65,7 +109,8 @@ pub(crate) fn queue_outline_stencil_mesh( .with_primitive_topology(mesh.primitive_topology) .with_depth_mode(outline.depth_mode) .with_offset_zero(stencil_uniform.offset == 0.0) - .with_morph_targets(mesh.morph_targets.is_some()); + .with_morph_targets(mesh.morph_targets.is_some()) + .with_view_key(build_mesh_pipeline_view_layout_key(*msaa, prepasses)); let Ok(pipeline) = pipelines.specialize(&pipeline_cache, &stencil_pipeline, key, &mesh.layout) else { @@ -86,9 +131,10 @@ pub(crate) fn queue_outline_stencil_mesh( pub(crate) type DrawOutline = ( SetItemPipeline, - SetOutlineViewBindGroup<0>, + SetMeshViewBindGroup<0>, SetMeshBindGroup<1>, - SetOutlineVolumeBindGroup<2>, + SetOutlineViewBindGroup<2>, + SetOutlineVolumeBindGroup<3>, DrawMesh, ); @@ -113,6 +159,12 @@ pub(crate) fn queue_outline_volume_mesh( &mut RenderPhase, &mut RenderPhase, Option<&RenderLayers>, + ( + Has, + Has, + Has, + Has, + ), )>, ) { let draw_opaque_outline = opaque_draw_functions @@ -126,7 +178,7 @@ pub(crate) fn queue_outline_volume_mesh( let base_key = PipelineKey::new().with_msaa(*msaa); - for (view, mut opaque_phase, mut transparent_phase, view_mask) in views.iter_mut() { + for (view, mut opaque_phase, mut transparent_phase, view_mask, prepasses) in views.iter_mut() { let view_mask = view_mask.copied().unwrap_or_default(); let rangefinder = view.rangefinder3d(); for (entity, volume_uniform, outline, fragment_uniform, outline_mask) in @@ -149,7 +201,8 @@ pub(crate) fn queue_outline_volume_mesh( .with_depth_mode(outline.depth_mode) .with_offset_zero(volume_uniform.offset == 0.0) .with_hdr_format(view.hdr) - .with_morph_targets(mesh.morph_targets.is_some()); + .with_morph_targets(mesh.morph_targets.is_some()) + .with_view_key(build_mesh_pipeline_view_layout_key(*msaa, prepasses)); let Ok(pipeline) = pipelines.specialize(&pipeline_cache, &outline_pipeline, key, &mesh.layout) else { diff --git a/src/fragment.wgsl b/src/fragment.wgsl index 1e31003..dd1d197 100644 --- a/src/fragment.wgsl +++ b/src/fragment.wgsl @@ -11,7 +11,7 @@ struct OutlineFragmentUniform { }; #ifdef VOLUME -@group(2) @binding(1) +@group(3) @binding(1) var fstage: OutlineFragmentUniform; #endif diff --git a/src/outline.wgsl b/src/outline.wgsl index 069e1f0..a47fb00 100644 --- a/src/outline.wgsl +++ b/src/outline.wgsl @@ -42,14 +42,14 @@ struct OutlineVertexUniform { @group(0) @binding(0) var view: View; -@group(0) @binding(1) -var view_uniform: OutlineViewUniform; - #import bevy_pbr::mesh_bindings #import bevy_pbr::skinning #import bevy_pbr::morph @group(2) @binding(0) +var view_uniform: OutlineViewUniform; + +@group(3) @binding(0) var vstage: OutlineVertexUniform; #ifdef MORPH_TARGETS diff --git a/src/pipeline.rs b/src/pipeline.rs index 12dad97..3ebaed1 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -3,7 +3,8 @@ use std::borrow::Cow; use bevy::ecs::system::lifetimeless::SQuery; use bevy::ecs::system::SystemParamItem; use bevy::pbr::{ - setup_morph_and_skinning_defs, MeshFlags, MeshPipelineKey, MeshTransforms, MeshUniform, + setup_morph_and_skinning_defs, MeshFlags, MeshPipelineKey, MeshPipelineViewLayoutKey, + MeshTransforms, MeshUniform, }; use bevy::prelude::*; use bevy::render::batching::GetBatchData; @@ -16,7 +17,7 @@ use bevy::render::render_resource::{ use bevy::render::renderer::RenderDevice; use bevy::render::settings::WgpuSettings; use bevy::render::texture::BevyDefault; -use bevy::render::view::{ViewTarget, ViewUniform}; +use bevy::render::view::ViewTarget; use bevy::{ pbr::MeshPipeline, render::{ @@ -63,6 +64,7 @@ impl PipelineKey { pub offset_zero, set_offset_zero: 13; pub hdr_format, set_hdr_format: 14; pub morph_targets, set_morph_targets: 15; + view_key_int, set_view_key_int: 23, 16; } pub(crate) fn new() -> Self { @@ -141,6 +143,15 @@ impl PipelineKey { self.set_morph_targets(morph_targets); self } + + pub(crate) fn with_view_key(mut self, view_key: MeshPipelineViewLayoutKey) -> Self { + self.set_view_key_int(view_key.bits()); + self + } + + pub(crate) fn view_key(&self) -> MeshPipelineViewLayoutKey { + MeshPipelineViewLayoutKey::from_bits(self.view_key_int()).unwrap() + } } impl From for MeshPipelineKey { @@ -168,28 +179,16 @@ impl FromWorld for OutlinePipeline { let render_device = world.get_resource::().unwrap(); let outline_view_bind_group_layout = render_device.create_bind_group_layout( "outline_view_bind_group_layout", - &[ - BindGroupLayoutEntry { - binding: 0, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(ViewUniform::min_size()), - }, - count: None, - }, - BindGroupLayoutEntry { - binding: 1, - visibility: ShaderStages::VERTEX, - ty: BindingType::Buffer { - ty: BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: Some(OutlineViewUniform::min_size()), - }, - count: None, + &[BindGroupLayoutEntry { + binding: 0, + visibility: ShaderStages::VERTEX, + ty: BindingType::Buffer { + ty: BufferBindingType::Uniform, + has_dynamic_offset: true, + min_binding_size: Some(OutlineViewUniform::min_size()), }, - ], + count: None, + }], ); let outline_volume_bind_group_layout = render_device.create_bind_group_layout( "outline_volume_bind_group_layout", @@ -258,16 +257,18 @@ impl SpecializedMeshPipeline for OutlinePipeline { buffer_attrs.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0)); } - let mut bind_layouts = vec![self.outline_view_bind_group_layout.clone()]; - - bind_layouts.push(setup_morph_and_skinning_defs( - &self.mesh_pipeline.mesh_layouts, - layout, - 5, - &key.into(), - &mut vertex_defs, - &mut buffer_attrs, - )); + let mut bind_layouts = vec![ + self.mesh_pipeline.get_view_layout(key.view_key()).clone(), + setup_morph_and_skinning_defs( + &self.mesh_pipeline.mesh_layouts, + layout, + 5, + &key.into(), + &mut vertex_defs, + &mut buffer_attrs, + ), + self.outline_view_bind_group_layout.clone(), + ]; let cull_mode; if key.depth_mode() == DepthMode::Flat { diff --git a/src/view_uniforms.rs b/src/view_uniforms.rs index 4d8eb76..aebe7c0 100644 --- a/src/view_uniforms.rs +++ b/src/view_uniforms.rs @@ -9,7 +9,7 @@ use bevy::render::render_phase::{ use bevy::render::render_resource::ShaderType; use bevy::render::render_resource::{BindGroup, BindGroupEntry}; use bevy::render::renderer::RenderDevice; -use bevy::render::view::{RenderLayers, ViewUniformOffset, ViewUniforms}; +use bevy::render::view::RenderLayers; use bevy::render::Extract; use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; @@ -54,26 +54,16 @@ pub(crate) fn prepare_outline_view_bind_group( mut commands: Commands, render_device: Res, outline_pipeline: Res, - core_view_uniforms: Res, - outline_view_uniforms: Res>, + view_uniforms: Res>, ) { - if let (Some(core_view_binding), Some(outline_view_binding)) = ( - core_view_uniforms.uniforms.binding(), - outline_view_uniforms.binding(), - ) { + if let Some(view_binding) = view_uniforms.binding() { let bind_group = render_device.create_bind_group( "outline_view_bind_group", &outline_pipeline.outline_view_bind_group_layout, - &[ - BindGroupEntry { - binding: 0, - resource: core_view_binding.clone(), - }, - BindGroupEntry { - binding: 1, - resource: outline_view_binding.clone(), - }, - ], + &[BindGroupEntry { + binding: 0, + resource: view_binding.clone(), + }], ); commands.insert_resource(OutlineViewBindGroup { bind_group }); } @@ -82,24 +72,17 @@ pub(crate) fn prepare_outline_view_bind_group( pub(crate) struct SetOutlineViewBindGroup(); impl RenderCommand

for SetOutlineViewBindGroup { - type ViewQuery = ( - Read, - Read>, - ); + type ViewQuery = Read>; type ItemQuery = (); type Param = SRes; fn render<'w>( _item: &P, - (core_view_data, outline_view_data): ROQueryItem<'w, Self::ViewQuery>, + view_data: ROQueryItem<'w, Self::ViewQuery>, _entity_data: Option<()>, bind_group: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { - pass.set_bind_group( - I, - &bind_group.into_inner().bind_group, - &[core_view_data.offset, outline_view_data.index()], - ); + pass.set_bind_group(I, &bind_group.into_inner().bind_group, &[view_data.index()]); RenderCommandResult::Success } } From ff99c20c77425596a79f080586c948f44cc2555a Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Sat, 2 Mar 2024 22:54:02 +0000 Subject: [PATCH 12/13] Run outline pass after TAA if TAA plugin added first. --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 74c4c83..80d2189 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -309,6 +309,9 @@ impl Plugin for OutlinePlugin { // Run after main 3D pass, but before UI psss draw_3d_graph.add_node_edge(Node3d::EndMainPass, NodeOutline::OutlinePass); + if let Ok(_) = draw_3d_graph.get_node_state(Node3d::Taa) { + draw_3d_graph.add_node_edge(Node3d::Taa, NodeOutline::OutlinePass); + } #[cfg(feature = "bevy_ui")] draw_3d_graph.add_node_edge(NodeOutline::OutlinePass, NodeUi::UiPass); } From 249a07f2024405ae263944881af91c9942226689 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Sun, 3 Mar 2024 00:43:16 +0000 Subject: [PATCH 13/13] Fix clippy lint. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 80d2189..74a68c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -309,7 +309,7 @@ impl Plugin for OutlinePlugin { // Run after main 3D pass, but before UI psss draw_3d_graph.add_node_edge(Node3d::EndMainPass, NodeOutline::OutlinePass); - if let Ok(_) = draw_3d_graph.get_node_state(Node3d::Taa) { + if draw_3d_graph.get_node_state(Node3d::Taa).is_ok() { draw_3d_graph.add_node_edge(Node3d::Taa, NodeOutline::OutlinePass); } #[cfg(feature = "bevy_ui")]