diff --git a/crates/bevy_core_pipeline/src/deferred/mod.rs b/crates/bevy_core_pipeline/src/deferred/mod.rs index 1ddc66a285..f544204ec2 100644 --- a/crates/bevy_core_pipeline/src/deferred/mod.rs +++ b/crates/bevy_core_pipeline/src/deferred/mod.rs @@ -3,6 +3,7 @@ pub mod node; use core::ops::Range; +use crate::core_3d::Opaque3dBinKey; use crate::prepass::OpaqueNoLightmap3dBinKey; use bevy_ecs::prelude::*; use bevy_render::sync_world::MainEntity; @@ -25,7 +26,7 @@ pub const DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT: TextureFormat = TextureFormat: /// Used to render all 3D meshes with materials that have no transparency. #[derive(PartialEq, Eq, Hash)] pub struct Opaque3dDeferred { - pub key: OpaqueNoLightmap3dBinKey, + pub key: Opaque3dBinKey, pub representative_entity: (Entity, MainEntity), pub batch_range: Range, pub extra_index: PhaseItemExtraIndex, @@ -68,7 +69,7 @@ impl PhaseItem for Opaque3dDeferred { } impl BinnedPhaseItem for Opaque3dDeferred { - type BinKey = OpaqueNoLightmap3dBinKey; + type BinKey = Opaque3dBinKey; #[inline] fn new( diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index ac5cbeca42..211bbe9926 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -2,8 +2,9 @@ mod prepass_bindings; use crate::material_bind_groups::MaterialBindGroupAllocator; use bevy_render::{ - mesh::{Mesh3d, MeshVertexBufferLayoutRef, RenderMesh}, + mesh::{allocator::MeshAllocator, Mesh3d, MeshVertexBufferLayoutRef, RenderMesh}, render_resource::binding_types::uniform_buffer, + renderer::RenderAdapter, sync_world::RenderEntity, view::{RenderVisibilityRanges, VISIBILITY_RANGES_STORAGE_BUFFER_COUNT}, }; @@ -11,7 +12,10 @@ pub use prepass_bindings::*; use bevy_asset::{load_internal_asset, AssetServer}; use bevy_core_pipeline::{ - core_3d::CORE_3D_DEPTH_FORMAT, deferred::*, prelude::Camera3d, prepass::*, + core_3d::{Opaque3dBatchSetKey, Opaque3dBinKey, CORE_3D_DEPTH_FORMAT}, + deferred::*, + prelude::Camera3d, + prepass::*, }; use bevy_ecs::{ prelude::*, @@ -259,12 +263,18 @@ pub struct PrepassPipeline { pub skins_use_uniform_buffers: bool, pub depth_clip_control_supported: bool, + + /// Whether binding arrays (a.k.a. bindless textures) are usable on the + /// current render device. + pub binding_arrays_are_usable: bool, + _marker: PhantomData, } impl FromWorld for PrepassPipeline { fn from_world(world: &mut World) -> Self { let render_device = world.resource::(); + let render_adapter = world.resource::(); let asset_server = world.resource::(); let visibility_ranges_buffer_binding_type = render_device @@ -352,6 +362,7 @@ impl FromWorld for PrepassPipeline { material_pipeline: world.resource::>().clone(), skins_use_uniform_buffers: skin::skins_use_uniform_buffers(render_device), depth_clip_control_supported, + binding_arrays_are_usable: binding_arrays_are_usable(render_device, render_adapter), _marker: PhantomData, } } @@ -505,6 +516,10 @@ where shader_defs.push("BINDLESS".into()); } + if self.binding_arrays_are_usable { + shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into()); + } + if key .mesh_key .contains(MeshPipelineKey::VISIBILITY_RANGE_DITHER) @@ -764,7 +779,10 @@ pub fn queue_prepass_material_meshes( render_material_instances: Res>, render_lightmaps: Res, render_visibility_ranges: Res, - material_bind_group_allocator: Res>, + (mesh_allocator, material_bind_group_allocator): ( + Res, + Res>, + ), mut opaque_prepass_render_phases: ResMut>, mut alpha_mask_prepass_render_phases: ResMut>, mut opaque_deferred_render_phases: ResMut>, @@ -893,15 +911,11 @@ pub fn queue_prepass_material_meshes( mesh_key |= MeshPipelineKey::DEFERRED_PREPASS; } - // Even though we don't use the lightmap in the prepass, the - // `SetMeshBindGroup` render command will bind the data for it. So - // we need to include the appropriate flag in the mesh pipeline key - // to ensure that the necessary bind group layout entries are - // present. - if render_lightmaps + let lightmap_slab_index = render_lightmaps .render_lightmaps - .contains_key(visible_entity) - { + .get(visible_entity) + .map(|lightmap| lightmap.slab_index); + if lightmap_slab_index.is_some() { mesh_key |= MeshPipelineKey::LIGHTMAPPED; } @@ -949,12 +963,18 @@ pub fn queue_prepass_material_meshes( { MeshPipelineKey::BLEND_OPAQUE | MeshPipelineKey::BLEND_ALPHA_TO_COVERAGE => { if deferred { + let (vertex_slab, index_slab) = + mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id); opaque_deferred_phase.as_mut().unwrap().add( - OpaqueNoLightmap3dBinKey { - batch_set_key: OpaqueNoLightmap3dBatchSetKey { + Opaque3dBinKey { + batch_set_key: Opaque3dBatchSetKey { draw_function: opaque_draw_deferred, pipeline: pipeline_id, material_bind_group_index: Some(material.binding.group.0), + vertex_slab: vertex_slab.unwrap_or_default(), + index_slab, + lightmap_slab: lightmap_slab_index + .map(|lightmap_slab_index| *lightmap_slab_index), }, asset_id: mesh_instance.mesh_asset_id.into(), }, diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 0ec344410c..dbc4f0037e 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -37,8 +37,8 @@ use bevy_render::{ renderer::{RenderAdapter, RenderDevice, RenderQueue}, texture::DefaultImageSampler, view::{ - prepare_view_targets, NoFrustumCulling, NoIndirectDrawing, RenderVisibilityRanges, - ViewTarget, ViewUniformOffset, ViewVisibility, VisibilityRange, + NoFrustumCulling, NoIndirectDrawing, RenderVisibilityRanges, ViewTarget, ViewUniformOffset, + ViewVisibility, VisibilityRange, }, Extract, }; @@ -221,8 +221,7 @@ impl Plugin for MeshRenderPlugin { gpu_preprocessing::write_batched_instance_buffers:: .in_set(RenderSet::PrepareResourcesFlush), gpu_preprocessing::delete_old_work_item_buffers:: - .in_set(RenderSet::ManageViews) - .after(prepare_view_targets), + .in_set(RenderSet::PrepareResources), collect_meshes_for_gpu_building .in_set(RenderSet::PrepareAssets) .after(allocator::allocate_and_free_meshes) diff --git a/examples/3d/lightmaps.rs b/examples/3d/lightmaps.rs index a6899cb368..0a2a7bcad2 100644 --- a/examples/3d/lightmaps.rs +++ b/examples/3d/lightmaps.rs @@ -1,25 +1,58 @@ //! Rendering a scene with baked lightmaps. -use bevy::{pbr::Lightmap, prelude::*}; +use argh::FromArgs; +use bevy::{ + core_pipeline::prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass}, + pbr::{DefaultOpaqueRendererMethod, Lightmap}, + prelude::*, +}; + +/// Demonstrates lightmaps +#[derive(FromArgs, Resource)] +struct Args { + /// enables deferred shading + #[argh(switch)] + deferred: bool, +} fn main() { - App::new() - .add_plugins(DefaultPlugins) - .insert_resource(AmbientLight::NONE) + #[cfg(not(target_arch = "wasm32"))] + let args: Args = argh::from_env(); + #[cfg(target_arch = "wasm32")] + let args: Args = Args::from_args(&[], &[]).unwrap(); + + let mut app = App::new(); + app.add_plugins(DefaultPlugins) + .insert_resource(AmbientLight::NONE); + + if args.deferred { + app.insert_resource(DefaultOpaqueRendererMethod::deferred()); + } + + app.insert_resource(args) .add_systems(Startup, setup) .add_systems(Update, add_lightmaps_to_meshes) .run(); } -fn setup(mut commands: Commands, asset_server: Res) { +fn setup(mut commands: Commands, asset_server: Res, args: Res) { commands.spawn(SceneRoot(asset_server.load( GltfAssetLabel::Scene(0).from_asset("models/CornellBox/CornellBox.glb"), ))); - commands.spawn(( + let mut camera = commands.spawn(( Camera3d::default(), Transform::from_xyz(-278.0, 273.0, 800.0), )); + + if args.deferred { + camera.insert(( + DepthPrepass, + MotionVectorPrepass, + DeferredPrepass, + Msaa::Off, + )); + } } fn add_lightmaps_to_meshes(