From b5745994449e5c80b01b2c72aa3f00b78537c678 Mon Sep 17 00:00:00 2001 From: Antonin Peronnet <62420525+rambip@users.noreply.github.com> Date: Mon, 10 Mar 2025 22:16:52 +0100 Subject: [PATCH] don't use bevy_pbr for base bevy_gizmos plugin (#17581) # Objective This PR enables `bevy_gizmos` to be used without `bevy_pbr`, for user who want to create their custom mesh rendering logic. It can also be useful for user who just want to use bevy for drawing lines (why not). This work is part of a bigger effort to make the bevy rendering pipeline more modular. I would like to contribute an exemple to render custom meshes without `bevy_pbr`. Something like [this](https://github.com/rambip/plant-mesh/blob/main/src/shader/mod.rs) ## Solution Now, `bevy_pbr` is an optional dependency, and used only to debug lights. I query the `ViewUniforms` manually, instead of using `bevy_pbr` to get the heavy `MeshViewLayout` ## Testing I'm not used to testing with bevy at all, but I was able to use successfully in my project. It might break for some different mesh pipelines, but I don't think so. --- ## Showcase ![image](https://github.com/user-attachments/assets/7fa22d1c-8b4f-456b-a74b-1a579449e9f5) So nice ... ## Migration Guide I don't think there is any breaking change # Remaining work Before merging it, it would be useful to: - rewrite the `pipeline_2d.rs` logic to remove the `bevy_sprite` depedency too - move `view.rs` to `bevy_render`, so that it can be used in a more modular way. ~~- include the most recent changes from 0.16~~ --------- Co-authored-by: IceSentry --- crates/bevy_gizmos/Cargo.toml | 1 - crates/bevy_gizmos/src/config.rs | 10 +- crates/bevy_gizmos/src/lib.rs | 76 ++++------- crates/bevy_gizmos/src/pipeline_2d.rs | 70 +++++------ crates/bevy_gizmos/src/pipeline_3d.rs | 173 +++++++------------------- crates/bevy_gizmos/src/retained.rs | 1 - crates/bevy_gizmos/src/view.rs | 90 ++++++++++++++ crates/bevy_internal/Cargo.toml | 2 +- 8 files changed, 192 insertions(+), 231 deletions(-) create mode 100644 crates/bevy_gizmos/src/view.rs diff --git a/crates/bevy_gizmos/Cargo.toml b/crates/bevy_gizmos/Cargo.toml index 3a264c6244..a7f9f4b778 100644 --- a/crates/bevy_gizmos/Cargo.toml +++ b/crates/bevy_gizmos/Cargo.toml @@ -16,7 +16,6 @@ bevy_render = ["dep:bevy_render", "bevy_core_pipeline"] [dependencies] # Bevy bevy_pbr = { path = "../bevy_pbr", version = "0.16.0-dev", optional = true } -bevy_sprite = { path = "../bevy_sprite", version = "0.16.0-dev", optional = true } bevy_app = { path = "../bevy_app", version = "0.16.0-dev" } bevy_color = { path = "../bevy_color", version = "0.16.0-dev" } bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" } diff --git a/crates/bevy_gizmos/src/config.rs b/crates/bevy_gizmos/src/config.rs index bba3ff284c..da8916077c 100644 --- a/crates/bevy_gizmos/src/config.rs +++ b/crates/bevy_gizmos/src/config.rs @@ -2,10 +2,7 @@ pub use bevy_gizmos_macros::GizmoConfigGroup; -#[cfg(all( - feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") -))] +#[cfg(feature = "bevy_render")] use {crate::GizmoAsset, bevy_asset::Handle, bevy_ecs::component::Component}; use bevy_ecs::{reflect::ReflectResource, resource::Resource}; @@ -238,10 +235,7 @@ impl Default for GizmoLineConfig { } } -#[cfg(all( - feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") -))] +#[cfg(feature = "bevy_render")] #[derive(Component)] pub(crate) struct GizmoMeshConfig { pub line_perspective: bool, diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index fdc2243233..5790d33988 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -26,10 +26,8 @@ extern crate self as bevy_gizmos; #[derive(SystemSet, Clone, Debug, Hash, PartialEq, Eq)] pub enum GizmoRenderSystem { /// Adds gizmos to the [`Transparent2d`](bevy_core_pipeline::core_2d::Transparent2d) render phase - #[cfg(feature = "bevy_sprite")] QueueLineGizmos2d, /// Adds gizmos to the [`Transparent3d`](bevy_core_pipeline::core_3d::Transparent3d) render phase - #[cfg(feature = "bevy_pbr")] QueueLineGizmos3d, } @@ -46,13 +44,16 @@ pub mod grid; pub mod primitives; pub mod retained; pub mod rounded_box; +#[cfg(feature = "bevy_render")] +mod view; #[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))] pub mod light; -#[cfg(all(feature = "bevy_sprite", feature = "bevy_render"))] +#[cfg(feature = "bevy_render")] mod pipeline_2d; -#[cfg(all(feature = "bevy_pbr", feature = "bevy_render"))] + +#[cfg(feature = "bevy_render")] mod pipeline_3d; /// The gizmos prelude. @@ -85,13 +86,12 @@ use bevy_ecs::{ schedule::{IntoSystemConfigs, SystemSet}, system::{Res, ResMut}, }; -use bevy_math::{Vec3, Vec4}; +use bevy_math::Vec4; use bevy_reflect::TypePath; +#[cfg(feature = "bevy_render")] +use view::OnlyViewLayout; -#[cfg(all( - feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") -))] +#[cfg(feature = "bevy_render")] use crate::config::GizmoMeshConfig; use crate::{config::ErasedGizmoConfigGroup, gizmos::GizmoBuffer}; @@ -125,10 +125,7 @@ use { bytemuck::cast_slice, }; -#[cfg(all( - feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite"), -))] +#[cfg(feature = "bevy_render")] use bevy_render::render_resource::{VertexAttribute, VertexBufferLayout, VertexStepMode}; use bevy_time::Fixed; use bevy_utils::TypeIdMap; @@ -146,9 +143,10 @@ const LINE_SHADER_HANDLE: Handle = weak_handle!("15dc5869-ad30-4664-b35a const LINE_JOINT_SHADER_HANDLE: Handle = weak_handle!("7b5bdda5-df81-4711-a6cf-e587700de6f2"); -/// A [`Plugin`] that provides an immediate mode drawing api for visual debugging. +/// A [`Plugin`] for the [`RenderApp`] that provides an immediate mode drawing api for visual debugging. /// -/// Requires to be loaded after [`PbrPlugin`](bevy_pbr::PbrPlugin) or [`SpritePlugin`](bevy_sprite::SpritePlugin). +/// Additionally, it can support debugging light when the `bevy_pbr` feature is enabled, +/// see [`LightGizmoPlugin`] #[derive(Default)] pub struct GizmoPlugin; @@ -189,19 +187,8 @@ impl Plugin for GizmoPlugin { ); render_app.add_systems(ExtractSchedule, (extract_gizmo_data, extract_linegizmos)); - - #[cfg(feature = "bevy_sprite")] - if app.is_plugin_added::() { - app.add_plugins(pipeline_2d::LineGizmo2dPlugin); - } else { - tracing::warn!("bevy_sprite feature is enabled but bevy_sprite::SpritePlugin was not detected. Are you sure you loaded GizmoPlugin after SpritePlugin?"); - } - #[cfg(feature = "bevy_pbr")] - if app.is_plugin_added::() { - app.add_plugins(pipeline_3d::LineGizmo3dPlugin); - } else { - tracing::warn!("bevy_pbr feature is enabled but bevy_pbr::PbrPlugin was not detected. Are you sure you loaded GizmoPlugin after PbrPlugin?"); - } + app.add_plugins(pipeline_3d::LineGizmo3dPlugin) + .add_plugins(pipeline_2d::LineGizmo2dPlugin); } else { tracing::warn!("bevy_render feature is enabled but RenderApp was not detected. Are you sure you loaded GizmoPlugin after RenderPlugin?"); } @@ -222,9 +209,11 @@ impl Plugin for GizmoPlugin { ), ); - render_app.insert_resource(LineGizmoUniformBindgroupLayout { - layout: line_layout, - }); + render_app + .init_resource::() + .insert_resource(LineGizmoUniformBindgroupLayout { + layout: line_layout, + }); } } @@ -474,7 +463,6 @@ fn extract_gizmo_data( #[cfg(feature = "webgl")] _padding: Default::default(), }, - #[cfg(any(feature = "bevy_pbr", feature = "bevy_sprite"))] GizmoMeshConfig { line_perspective: config.line.perspective, line_style: config.line.style, @@ -503,7 +491,7 @@ struct LineGizmoUniform { line_scale: f32, /// WebGL2 structs must be 16 byte aligned. #[cfg(feature = "webgl")] - _padding: Vec3, + _padding: bevy_math::Vec3, } /// A collection of gizmos. @@ -634,7 +622,7 @@ impl RenderCommand

for SetLineGizmoBindGroup #[inline] fn render<'w>( _item: &P, - _view: ROQueryItem<'w, Self::ViewQuery>, + _views: ROQueryItem<'w, Self::ViewQuery>, uniform_index: Option>, bind_group: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, @@ -653,10 +641,7 @@ impl RenderCommand

for SetLineGizmoBindGroup #[cfg(feature = "bevy_render")] struct DrawLineGizmo; -#[cfg(all( - feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") -))] +#[cfg(feature = "bevy_render")] impl RenderCommand

for DrawLineGizmo { type Param = SRes>; type ViewQuery = (); @@ -716,10 +701,7 @@ impl RenderCommand

for DrawLineGizmo #[cfg(feature = "bevy_render")] struct DrawLineJointGizmo; -#[cfg(all( - feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") -))] +#[cfg(feature = "bevy_render")] impl RenderCommand

for DrawLineJointGizmo { type Param = SRes>; type ViewQuery = (); @@ -789,10 +771,7 @@ impl RenderCommand

for DrawLineJointGizmo { } } -#[cfg(all( - feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") -))] +#[cfg(feature = "bevy_render")] fn line_gizmo_vertex_buffer_layouts(strip: bool) -> Vec { use VertexFormat::*; let mut position_layout = VertexBufferLayout { @@ -847,10 +826,7 @@ fn line_gizmo_vertex_buffer_layouts(strip: bool) -> Vec { } } -#[cfg(all( - feature = "bevy_render", - any(feature = "bevy_pbr", feature = "bevy_sprite") -))] +#[cfg(feature = "bevy_render")] fn line_joint_gizmo_vertex_buffer_layouts() -> Vec { use VertexFormat::*; let mut position_layout = VertexBufferLayout { diff --git a/crates/bevy_gizmos/src/pipeline_2d.rs b/crates/bevy_gizmos/src/pipeline_2d.rs index 72a2428ff0..8bbb1371bd 100644 --- a/crates/bevy_gizmos/src/pipeline_2d.rs +++ b/crates/bevy_gizmos/src/pipeline_2d.rs @@ -1,3 +1,4 @@ +use crate::view::{OnlyViewLayout, SetViewBindGroup}; use crate::{ config::{GizmoLineJoint, GizmoLineStyle, GizmoMeshConfig}, line_gizmo_vertex_buffer_layouts, line_joint_gizmo_vertex_buffer_layouts, DrawLineGizmo, @@ -10,7 +11,7 @@ use bevy_core_pipeline::core_2d::{Transparent2d, CORE_2D_DEPTH_FORMAT}; use bevy_ecs::{ prelude::Entity, resource::Resource, - schedule::{IntoSystemConfigs, IntoSystemSetConfigs}, + schedule::IntoSystemConfigs, system::{Query, Res, ResMut}, world::{FromWorld, World}, }; @@ -25,9 +26,8 @@ use bevy_render::{ }, render_resource::*, view::{ExtractedView, Msaa, RenderLayers, ViewTarget}, - Render, RenderApp, RenderSet, + Render, RenderApp, }; -use bevy_sprite::{Mesh2dPipeline, Mesh2dPipelineKey, SetMesh2dViewBindGroup}; use tracing::error; pub struct LineGizmo2dPlugin; @@ -44,15 +44,6 @@ impl Plugin for LineGizmo2dPlugin { .add_render_command::() .init_resource::>() .init_resource::>() - .configure_sets( - Render, - GizmoRenderSystem::QueueLineGizmos2d - .in_set(RenderSet::Queue) - .ambiguous_with(bevy_sprite::queue_sprites) - .ambiguous_with( - bevy_sprite::queue_material2d_meshes::, - ), - ) .add_systems( Render, (queue_line_gizmos_2d, queue_line_joint_gizmos_2d) @@ -73,14 +64,15 @@ impl Plugin for LineGizmo2dPlugin { #[derive(Clone, Resource)] struct LineGizmoPipeline { - mesh_pipeline: Mesh2dPipeline, + view_layout: BindGroupLayout, uniform_layout: BindGroupLayout, } impl FromWorld for LineGizmoPipeline { fn from_world(render_world: &mut World) -> Self { + let view_layout = render_world.resource::().0.clone(); LineGizmoPipeline { - mesh_pipeline: render_world.resource::().clone(), + view_layout, uniform_layout: render_world .resource::() .layout @@ -91,7 +83,8 @@ impl FromWorld for LineGizmoPipeline { #[derive(PartialEq, Eq, Hash, Clone)] struct LineGizmoPipelineKey { - mesh_key: Mesh2dPipelineKey, + hdr: bool, + msaa: Msaa, strip: bool, line_style: GizmoLineStyle, } @@ -100,7 +93,7 @@ impl SpecializedRenderPipeline for LineGizmoPipeline { type Key = LineGizmoPipelineKey; fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let format = if key.mesh_key.contains(Mesh2dPipelineKey::HDR) { + let format = if key.hdr { ViewTarget::TEXTURE_FORMAT_HDR } else { TextureFormat::bevy_default() @@ -111,10 +104,7 @@ impl SpecializedRenderPipeline for LineGizmoPipeline { "SIXTEEN_BYTE_ALIGNMENT".into(), ]; - let layout = vec![ - self.mesh_pipeline.view_layout.clone(), - self.uniform_layout.clone(), - ]; + let layout = vec![self.view_layout.clone(), self.uniform_layout.clone()]; let fragment_entry_point = match key.line_style { GizmoLineStyle::Solid => "fragment_solid", @@ -158,7 +148,7 @@ impl SpecializedRenderPipeline for LineGizmoPipeline { }, }), multisample: MultisampleState { - count: key.mesh_key.msaa_samples(), + count: key.msaa.samples(), mask: !0, alpha_to_coverage_enabled: false, }, @@ -171,14 +161,15 @@ impl SpecializedRenderPipeline for LineGizmoPipeline { #[derive(Clone, Resource)] struct LineJointGizmoPipeline { - mesh_pipeline: Mesh2dPipeline, + view_layout: BindGroupLayout, uniform_layout: BindGroupLayout, } impl FromWorld for LineJointGizmoPipeline { fn from_world(render_world: &mut World) -> Self { + let view_layout = render_world.resource::().0.clone(); LineJointGizmoPipeline { - mesh_pipeline: render_world.resource::().clone(), + view_layout, uniform_layout: render_world .resource::() .layout @@ -189,7 +180,8 @@ impl FromWorld for LineJointGizmoPipeline { #[derive(PartialEq, Eq, Hash, Clone)] struct LineJointGizmoPipelineKey { - mesh_key: Mesh2dPipelineKey, + hdr: bool, + msaa: Msaa, joints: GizmoLineJoint, } @@ -197,7 +189,7 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline { type Key = LineJointGizmoPipelineKey; fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let format = if key.mesh_key.contains(Mesh2dPipelineKey::HDR) { + let format = if key.hdr { ViewTarget::TEXTURE_FORMAT_HDR } else { TextureFormat::bevy_default() @@ -208,10 +200,7 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline { "SIXTEEN_BYTE_ALIGNMENT".into(), ]; - let layout = vec![ - self.mesh_pipeline.view_layout.clone(), - self.uniform_layout.clone(), - ]; + let layout = vec![self.view_layout.clone(), self.uniform_layout.clone()]; if key.joints == GizmoLineJoint::None { error!("There is no entry point for line joints with GizmoLineJoints::None. Please consider aborting the drawing process before reaching this stage."); @@ -259,7 +248,7 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline { }, }), multisample: MultisampleState { - count: key.mesh_key.msaa_samples(), + count: key.msaa.samples(), mask: !0, alpha_to_coverage_enabled: false, }, @@ -272,19 +261,19 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline { type DrawLineGizmo2d = ( SetItemPipeline, - SetMesh2dViewBindGroup<0>, + SetViewBindGroup<0>, SetLineGizmoBindGroup<1>, DrawLineGizmo, ); type DrawLineGizmo2dStrip = ( SetItemPipeline, - SetMesh2dViewBindGroup<0>, + SetViewBindGroup<0>, SetLineGizmoBindGroup<1>, DrawLineGizmo, ); type DrawLineJointGizmo2d = ( SetItemPipeline, - SetMesh2dViewBindGroup<0>, + SetViewBindGroup<0>, SetLineGizmoBindGroup<1>, DrawLineJointGizmo, ); @@ -311,9 +300,6 @@ fn queue_line_gizmos_2d( continue; }; - let mesh_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples()) - | Mesh2dPipelineKey::from_hdr(view.hdr); - let render_layers = render_layers.unwrap_or_default(); for (entity, main_entity, config) in &line_gizmos { if !config.render_layers.intersects(render_layers) { @@ -329,7 +315,8 @@ fn queue_line_gizmos_2d( &pipeline_cache, &pipeline, LineGizmoPipelineKey { - mesh_key, + msaa: *msaa, + hdr: view.hdr, strip: false, line_style: config.line_style, }, @@ -350,7 +337,8 @@ fn queue_line_gizmos_2d( &pipeline_cache, &pipeline, LineGizmoPipelineKey { - mesh_key, + msaa: *msaa, + hdr: view.hdr, strip: true, line_style: config.line_style, }, @@ -389,9 +377,6 @@ fn queue_line_joint_gizmos_2d( continue; }; - let mesh_key = Mesh2dPipelineKey::from_msaa_samples(msaa.samples()) - | Mesh2dPipelineKey::from_hdr(view.hdr); - let render_layers = render_layers.unwrap_or_default(); for (entity, main_entity, config) in &line_gizmos { if !config.render_layers.intersects(render_layers) { @@ -410,7 +395,8 @@ fn queue_line_joint_gizmos_2d( &pipeline_cache, &pipeline, LineJointGizmoPipelineKey { - mesh_key, + msaa: *msaa, + hdr: view.hdr, joints: config.line_joints, }, ); diff --git a/crates/bevy_gizmos/src/pipeline_3d.rs b/crates/bevy_gizmos/src/pipeline_3d.rs index 51308965d1..9afa2f7b41 100644 --- a/crates/bevy_gizmos/src/pipeline_3d.rs +++ b/crates/bevy_gizmos/src/pipeline_3d.rs @@ -1,26 +1,22 @@ use crate::{ config::{GizmoLineJoint, GizmoLineStyle, GizmoMeshConfig}, - line_gizmo_vertex_buffer_layouts, line_joint_gizmo_vertex_buffer_layouts, DrawLineGizmo, - DrawLineJointGizmo, GizmoRenderSystem, GpuLineGizmo, LineGizmoUniformBindgroupLayout, - SetLineGizmoBindGroup, LINE_JOINT_SHADER_HANDLE, LINE_SHADER_HANDLE, + line_gizmo_vertex_buffer_layouts, line_joint_gizmo_vertex_buffer_layouts, + view::{prepare_view_bind_groups, OnlyViewLayout, SetViewBindGroup}, + DrawLineGizmo, DrawLineJointGizmo, GizmoRenderSystem, GpuLineGizmo, + LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_JOINT_SHADER_HANDLE, + LINE_SHADER_HANDLE, }; use bevy_app::{App, Plugin}; -use bevy_core_pipeline::{ - core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT}, - oit::OrderIndependentTransparencySettings, - prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass}, -}; +use bevy_core_pipeline::core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT}; +use bevy_ecs::schedule::IntoSystemConfigs; use bevy_ecs::{ prelude::Entity, - query::Has, resource::Resource, - schedule::{IntoSystemConfigs, IntoSystemSetConfigs}, system::{Query, Res, ResMut}, world::{FromWorld, World}, }; use bevy_image::BevyDefault as _; -use bevy_pbr::{MeshPipeline, MeshPipelineKey, SetMeshViewBindGroup}; use bevy_render::sync_world::MainEntity; use bevy_render::{ render_asset::{prepare_assets, RenderAssets}, @@ -33,7 +29,6 @@ use bevy_render::{ Render, RenderApp, RenderSet, }; use tracing::error; - pub struct LineGizmo3dPlugin; impl Plugin for LineGizmo3dPlugin { fn build(&self, app: &mut App) { @@ -47,15 +42,13 @@ impl Plugin for LineGizmo3dPlugin { .add_render_command::() .init_resource::>() .init_resource::>() - .configure_sets( - Render, - GizmoRenderSystem::QueueLineGizmos3d - .in_set(RenderSet::Queue) - .ambiguous_with(bevy_pbr::queue_material_meshes::), - ) .add_systems( Render, - (queue_line_gizmos_3d, queue_line_joint_gizmos_3d) + ( + queue_line_gizmos_3d, + queue_line_joint_gizmos_3d, + prepare_view_bind_groups.in_set(RenderSet::Prepare), + ) .in_set(GizmoRenderSystem::QueueLineGizmos3d) .after(prepare_assets::), ); @@ -72,15 +65,17 @@ impl Plugin for LineGizmo3dPlugin { } #[derive(Clone, Resource)] -struct LineGizmoPipeline { - mesh_pipeline: MeshPipeline, +pub(crate) struct LineGizmoPipeline { + view_layout: BindGroupLayout, uniform_layout: BindGroupLayout, } impl FromWorld for LineGizmoPipeline { fn from_world(render_world: &mut World) -> Self { + let view_layout = render_world.resource::().0.clone(); + LineGizmoPipeline { - mesh_pipeline: render_world.resource::().clone(), + view_layout, uniform_layout: render_world .resource::() .layout @@ -90,8 +85,9 @@ impl FromWorld for LineGizmoPipeline { } #[derive(PartialEq, Eq, Hash, Clone)] -struct LineGizmoPipelineKey { - view_key: MeshPipelineKey, +pub(crate) struct LineGizmoPipelineKey { + msaa: Msaa, + hdr: bool, strip: bool, perspective: bool, line_style: GizmoLineStyle, @@ -110,18 +106,13 @@ impl SpecializedRenderPipeline for LineGizmoPipeline { shader_defs.push("PERSPECTIVE".into()); } - let format = if key.view_key.contains(MeshPipelineKey::HDR) { + let format = if key.hdr { ViewTarget::TEXTURE_FORMAT_HDR } else { TextureFormat::bevy_default() }; - let view_layout = self - .mesh_pipeline - .get_view_layout(key.view_key.into()) - .clone(); - - let layout = vec![view_layout, self.uniform_layout.clone()]; + let layout = vec![self.view_layout.clone(), self.uniform_layout.clone()]; let fragment_entry_point = match key.line_style { GizmoLineStyle::Solid => "fragment_solid", @@ -156,7 +147,7 @@ impl SpecializedRenderPipeline for LineGizmoPipeline { bias: DepthBiasState::default(), }), multisample: MultisampleState { - count: key.view_key.msaa_samples(), + count: key.msaa.samples(), mask: !0, alpha_to_coverage_enabled: false, }, @@ -169,14 +160,16 @@ impl SpecializedRenderPipeline for LineGizmoPipeline { #[derive(Clone, Resource)] struct LineJointGizmoPipeline { - mesh_pipeline: MeshPipeline, + view_layout: BindGroupLayout, uniform_layout: BindGroupLayout, } impl FromWorld for LineJointGizmoPipeline { fn from_world(render_world: &mut World) -> Self { + let view_layout = render_world.resource::().0.clone(); + LineJointGizmoPipeline { - mesh_pipeline: render_world.resource::().clone(), + view_layout, uniform_layout: render_world .resource::() .layout @@ -187,7 +180,8 @@ impl FromWorld for LineJointGizmoPipeline { #[derive(PartialEq, Eq, Hash, Clone)] struct LineJointGizmoPipelineKey { - view_key: MeshPipelineKey, + msaa: Msaa, + hdr: bool, perspective: bool, joints: GizmoLineJoint, } @@ -205,18 +199,13 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline { shader_defs.push("PERSPECTIVE".into()); } - let format = if key.view_key.contains(MeshPipelineKey::HDR) { + let format = if key.hdr { ViewTarget::TEXTURE_FORMAT_HDR } else { TextureFormat::bevy_default() }; - let view_layout = self - .mesh_pipeline - .get_view_layout(key.view_key.into()) - .clone(); - - let layout = vec![view_layout, self.uniform_layout.clone()]; + let layout = vec![self.view_layout.clone(), self.uniform_layout.clone()]; if key.joints == GizmoLineJoint::None { error!("There is no entry point for line joints with GizmoLineJoints::None. Please consider aborting the drawing process before reaching this stage."); @@ -255,7 +244,7 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline { bias: DepthBiasState::default(), }), multisample: MultisampleState { - count: key.view_key.msaa_samples(), + count: key.msaa.samples(), mask: !0, alpha_to_coverage_enabled: false, }, @@ -268,19 +257,19 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline { type DrawLineGizmo3d = ( SetItemPipeline, - SetMeshViewBindGroup<0>, + SetViewBindGroup<0>, SetLineGizmoBindGroup<1>, DrawLineGizmo, ); type DrawLineGizmo3dStrip = ( SetItemPipeline, - SetMeshViewBindGroup<0>, + SetViewBindGroup<0>, SetLineGizmoBindGroup<1>, DrawLineGizmo, ); type DrawLineJointGizmo3d = ( SetItemPipeline, - SetMeshViewBindGroup<0>, + SetViewBindGroup<0>, SetLineGizmoBindGroup<1>, DrawLineJointGizmo, ); @@ -293,18 +282,7 @@ fn queue_line_gizmos_3d( line_gizmos: Query<(Entity, &MainEntity, &GizmoMeshConfig)>, line_gizmo_assets: Res>, mut transparent_render_phases: ResMut>, - views: Query<( - &ExtractedView, - &Msaa, - Option<&RenderLayers>, - ( - Has, - Has, - Has, - Has, - Has, - ), - )>, + views: Query<(&ExtractedView, &Msaa, Option<&RenderLayers>)>, ) { let draw_function = draw_functions.read().get_id::().unwrap(); let draw_function_strip = draw_functions @@ -312,13 +290,7 @@ fn queue_line_gizmos_3d( .get_id::() .unwrap(); - for ( - view, - msaa, - render_layers, - (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass, oit), - ) in &views - { + for (view, msaa, render_layers) in &views { let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity) else { continue; @@ -326,29 +298,6 @@ fn queue_line_gizmos_3d( let render_layers = render_layers.unwrap_or_default(); - let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples()) - | MeshPipelineKey::from_hdr(view.hdr); - - if normal_prepass { - view_key |= MeshPipelineKey::NORMAL_PREPASS; - } - - if depth_prepass { - view_key |= MeshPipelineKey::DEPTH_PREPASS; - } - - if motion_vector_prepass { - view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS; - } - - if deferred_prepass { - view_key |= MeshPipelineKey::DEFERRED_PREPASS; - } - - if oit { - view_key |= MeshPipelineKey::OIT_ENABLED; - } - for (entity, main_entity, config) in &line_gizmos { if !config.render_layers.intersects(render_layers) { continue; @@ -363,7 +312,8 @@ fn queue_line_gizmos_3d( &pipeline_cache, &pipeline, LineGizmoPipelineKey { - view_key, + msaa: *msaa, + hdr: view.hdr, strip: false, perspective: config.line_perspective, line_style: config.line_style, @@ -385,7 +335,8 @@ fn queue_line_gizmos_3d( &pipeline_cache, &pipeline, LineGizmoPipelineKey { - view_key, + msaa: *msaa, + hdr: view.hdr, strip: true, perspective: config.line_perspective, line_style: config.line_style, @@ -413,30 +364,14 @@ fn queue_line_joint_gizmos_3d( line_gizmos: Query<(Entity, &MainEntity, &GizmoMeshConfig)>, line_gizmo_assets: Res>, mut transparent_render_phases: ResMut>, - views: Query<( - &ExtractedView, - &Msaa, - Option<&RenderLayers>, - ( - Has, - Has, - Has, - Has, - ), - )>, + mut views: Query<(&ExtractedView, &Msaa, Option<&RenderLayers>)>, ) { let draw_function = draw_functions .read() .get_id::() .unwrap(); - for ( - view, - msaa, - render_layers, - (normal_prepass, depth_prepass, motion_vector_prepass, deferred_prepass), - ) in &views - { + for (view, msaa, render_layers) in &mut views { let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity) else { continue; @@ -444,25 +379,6 @@ fn queue_line_joint_gizmos_3d( let render_layers = render_layers.unwrap_or_default(); - let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples()) - | MeshPipelineKey::from_hdr(view.hdr); - - if normal_prepass { - view_key |= MeshPipelineKey::NORMAL_PREPASS; - } - - if depth_prepass { - view_key |= MeshPipelineKey::DEPTH_PREPASS; - } - - if motion_vector_prepass { - view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS; - } - - if deferred_prepass { - view_key |= MeshPipelineKey::DEFERRED_PREPASS; - } - for (entity, main_entity, config) in &line_gizmos { if !config.render_layers.intersects(render_layers) { continue; @@ -480,7 +396,8 @@ fn queue_line_joint_gizmos_3d( &pipeline_cache, &pipeline, LineJointGizmoPipelineKey { - view_key, + msaa: *msaa, + hdr: view.hdr, perspective: config.line_perspective, joints: config.line_joints, }, diff --git a/crates/bevy_gizmos/src/retained.rs b/crates/bevy_gizmos/src/retained.rs index 51170144b1..cf3785179a 100644 --- a/crates/bevy_gizmos/src/retained.rs +++ b/crates/bevy_gizmos/src/retained.rs @@ -143,7 +143,6 @@ pub(crate) fn extract_linegizmos( #[cfg(feature = "webgl")] _padding: Default::default(), }, - #[cfg(any(feature = "bevy_pbr", feature = "bevy_sprite"))] crate::config::GizmoMeshConfig { line_perspective: gizmo.line_config.perspective, line_style: gizmo.line_config.style, diff --git a/crates/bevy_gizmos/src/view.rs b/crates/bevy_gizmos/src/view.rs new file mode 100644 index 0000000000..34fa94c6c5 --- /dev/null +++ b/crates/bevy_gizmos/src/view.rs @@ -0,0 +1,90 @@ +use bevy_ecs::{ + component::Component, + entity::Entity, + query::With, + resource::Resource, + system::{lifetimeless::Read, Commands, Query, Res}, + world::FromWorld, +}; +use bevy_render::{ + render_phase::{PhaseItem, RenderCommand, RenderCommandResult}, + render_resource::{ + binding_types::uniform_buffer, BindGroup, BindGroupLayout, BindGroupLayoutEntry, + DynamicBindGroupEntries, DynamicBindGroupLayoutEntries, ShaderStages, + }, + renderer::RenderDevice, + view::{ExtractedView, ViewUniform, ViewUniforms}, +}; + +#[derive(Component)] +pub(crate) struct ViewBindGroup(BindGroup); + +/// very common layout: just the view uniform +#[derive(Resource)] +pub(crate) struct OnlyViewLayout(pub BindGroupLayout); + +impl FromWorld for OnlyViewLayout { + fn from_world(world: &mut bevy_ecs::world::World) -> Self { + let render_device = world.resource::(); + + let view_layout = + render_device.create_bind_group_layout("mesh_view_layout", &view_layout_entries()); + + Self(view_layout) + } +} + +pub(crate) struct SetViewBindGroup; + +impl RenderCommand

for SetViewBindGroup { + type Param = (); + + type ViewQuery = Read; + + type ItemQuery = (); + + fn render<'w>( + _: &P, + view: bevy_ecs::query::ROQueryItem<'w, Self::ViewQuery>, + _: Option>, + _: bevy_ecs::system::SystemParamItem<'w, '_, Self::Param>, + pass: &mut bevy_render::render_phase::TrackedRenderPass<'w>, + ) -> RenderCommandResult { + pass.set_bind_group(I, &view.0, &[0]); + RenderCommandResult::Success + } +} + +pub(crate) fn prepare_view_bind_groups( + mut commands: Commands, + render_device: Res, + view_uniforms: Res, + layout: Res, + views: Query>, +) { + let Some(view_binding) = view_uniforms.uniforms.binding() else { + return; + }; + + let entries = DynamicBindGroupEntries::new_with_indices(((0, view_binding.clone()),)); + for entity in &views { + commands + .entity(entity) + .insert(ViewBindGroup(render_device.create_bind_group( + "view_bind_group", + &layout.0, + &entries, + ))); + } +} + +pub(crate) fn view_layout_entries() -> Vec { + DynamicBindGroupLayoutEntries::new_with_indices( + ShaderStages::FRAGMENT, + (( + 0, + uniform_buffer::(true).visibility(ShaderStages::VERTEX_FRAGMENT), + ),), + ) + .to_vec() +} diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index b0be2f00c8..073de918bd 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -172,7 +172,7 @@ bevy_ci_testing = ["bevy_dev_tools/bevy_ci_testing", "bevy_render?/ci_limits"] # Enable animation support, and glTF animation loading animation = ["bevy_animation", "bevy_gltf?/bevy_animation"] -bevy_sprite = ["dep:bevy_sprite", "bevy_gizmos?/bevy_sprite", "bevy_image"] +bevy_sprite = ["dep:bevy_sprite", "bevy_gizmos", "bevy_image"] bevy_pbr = ["dep:bevy_pbr", "bevy_gizmos?/bevy_pbr", "bevy_image"] bevy_window = ["dep:bevy_window", "dep:bevy_a11y"] bevy_core_pipeline = ["dep:bevy_core_pipeline", "bevy_image"]