Skip to content

Commit 11c4339

Browse files
authored
Get lightmaps working in deferred rendering. (#16836)
A previous PR, #14599, attempted to enable lightmaps in deferred mode, but it still used the `OpaqueNoLightmap3dBinKey`, which meant that it would be broken if multiple lightmaps were used. This commit fixes that issue, and allows bindless lightmaps to work with deferred rendering as well.
1 parent 78d2149 commit 11c4339

File tree

4 files changed

+78
-25
lines changed

4 files changed

+78
-25
lines changed

crates/bevy_core_pipeline/src/deferred/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod node;
33

44
use core::ops::Range;
55

6+
use crate::core_3d::Opaque3dBinKey;
67
use crate::prepass::OpaqueNoLightmap3dBinKey;
78
use bevy_ecs::prelude::*;
89
use bevy_render::sync_world::MainEntity;
@@ -25,7 +26,7 @@ pub const DEFERRED_LIGHTING_PASS_ID_DEPTH_FORMAT: TextureFormat = TextureFormat:
2526
/// Used to render all 3D meshes with materials that have no transparency.
2627
#[derive(PartialEq, Eq, Hash)]
2728
pub struct Opaque3dDeferred {
28-
pub key: OpaqueNoLightmap3dBinKey,
29+
pub key: Opaque3dBinKey,
2930
pub representative_entity: (Entity, MainEntity),
3031
pub batch_range: Range<u32>,
3132
pub extra_index: PhaseItemExtraIndex,
@@ -68,7 +69,7 @@ impl PhaseItem for Opaque3dDeferred {
6869
}
6970

7071
impl BinnedPhaseItem for Opaque3dDeferred {
71-
type BinKey = OpaqueNoLightmap3dBinKey;
72+
type BinKey = Opaque3dBinKey;
7273

7374
#[inline]
7475
fn new(

crates/bevy_pbr/src/prepass/mod.rs

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@ mod prepass_bindings;
22

33
use crate::material_bind_groups::MaterialBindGroupAllocator;
44
use bevy_render::{
5-
mesh::{Mesh3d, MeshVertexBufferLayoutRef, RenderMesh},
5+
mesh::{allocator::MeshAllocator, Mesh3d, MeshVertexBufferLayoutRef, RenderMesh},
66
render_resource::binding_types::uniform_buffer,
7+
renderer::RenderAdapter,
78
sync_world::RenderEntity,
89
view::{RenderVisibilityRanges, VISIBILITY_RANGES_STORAGE_BUFFER_COUNT},
910
};
1011
pub use prepass_bindings::*;
1112

1213
use bevy_asset::{load_internal_asset, AssetServer};
1314
use bevy_core_pipeline::{
14-
core_3d::CORE_3D_DEPTH_FORMAT, deferred::*, prelude::Camera3d, prepass::*,
15+
core_3d::{Opaque3dBatchSetKey, Opaque3dBinKey, CORE_3D_DEPTH_FORMAT},
16+
deferred::*,
17+
prelude::Camera3d,
18+
prepass::*,
1519
};
1620
use bevy_ecs::{
1721
prelude::*,
@@ -259,12 +263,18 @@ pub struct PrepassPipeline<M: Material> {
259263
pub skins_use_uniform_buffers: bool,
260264

261265
pub depth_clip_control_supported: bool,
266+
267+
/// Whether binding arrays (a.k.a. bindless textures) are usable on the
268+
/// current render device.
269+
pub binding_arrays_are_usable: bool,
270+
262271
_marker: PhantomData<M>,
263272
}
264273

265274
impl<M: Material> FromWorld for PrepassPipeline<M> {
266275
fn from_world(world: &mut World) -> Self {
267276
let render_device = world.resource::<RenderDevice>();
277+
let render_adapter = world.resource::<RenderAdapter>();
268278
let asset_server = world.resource::<AssetServer>();
269279

270280
let visibility_ranges_buffer_binding_type = render_device
@@ -352,6 +362,7 @@ impl<M: Material> FromWorld for PrepassPipeline<M> {
352362
material_pipeline: world.resource::<MaterialPipeline<M>>().clone(),
353363
skins_use_uniform_buffers: skin::skins_use_uniform_buffers(render_device),
354364
depth_clip_control_supported,
365+
binding_arrays_are_usable: binding_arrays_are_usable(render_device, render_adapter),
355366
_marker: PhantomData,
356367
}
357368
}
@@ -505,6 +516,10 @@ where
505516
shader_defs.push("BINDLESS".into());
506517
}
507518

519+
if self.binding_arrays_are_usable {
520+
shader_defs.push("MULTIPLE_LIGHTMAPS_IN_ARRAY".into());
521+
}
522+
508523
if key
509524
.mesh_key
510525
.contains(MeshPipelineKey::VISIBILITY_RANGE_DITHER)
@@ -764,7 +779,10 @@ pub fn queue_prepass_material_meshes<M: Material>(
764779
render_material_instances: Res<RenderMaterialInstances<M>>,
765780
render_lightmaps: Res<RenderLightmaps>,
766781
render_visibility_ranges: Res<RenderVisibilityRanges>,
767-
material_bind_group_allocator: Res<MaterialBindGroupAllocator<M>>,
782+
(mesh_allocator, material_bind_group_allocator): (
783+
Res<MeshAllocator>,
784+
Res<MaterialBindGroupAllocator<M>>,
785+
),
768786
mut opaque_prepass_render_phases: ResMut<ViewBinnedRenderPhases<Opaque3dPrepass>>,
769787
mut alpha_mask_prepass_render_phases: ResMut<ViewBinnedRenderPhases<AlphaMask3dPrepass>>,
770788
mut opaque_deferred_render_phases: ResMut<ViewBinnedRenderPhases<Opaque3dDeferred>>,
@@ -893,15 +911,11 @@ pub fn queue_prepass_material_meshes<M: Material>(
893911
mesh_key |= MeshPipelineKey::DEFERRED_PREPASS;
894912
}
895913

896-
// Even though we don't use the lightmap in the prepass, the
897-
// `SetMeshBindGroup` render command will bind the data for it. So
898-
// we need to include the appropriate flag in the mesh pipeline key
899-
// to ensure that the necessary bind group layout entries are
900-
// present.
901-
if render_lightmaps
914+
let lightmap_slab_index = render_lightmaps
902915
.render_lightmaps
903-
.contains_key(visible_entity)
904-
{
916+
.get(visible_entity)
917+
.map(|lightmap| lightmap.slab_index);
918+
if lightmap_slab_index.is_some() {
905919
mesh_key |= MeshPipelineKey::LIGHTMAPPED;
906920
}
907921

@@ -949,12 +963,18 @@ pub fn queue_prepass_material_meshes<M: Material>(
949963
{
950964
MeshPipelineKey::BLEND_OPAQUE | MeshPipelineKey::BLEND_ALPHA_TO_COVERAGE => {
951965
if deferred {
966+
let (vertex_slab, index_slab) =
967+
mesh_allocator.mesh_slabs(&mesh_instance.mesh_asset_id);
952968
opaque_deferred_phase.as_mut().unwrap().add(
953-
OpaqueNoLightmap3dBinKey {
954-
batch_set_key: OpaqueNoLightmap3dBatchSetKey {
969+
Opaque3dBinKey {
970+
batch_set_key: Opaque3dBatchSetKey {
955971
draw_function: opaque_draw_deferred,
956972
pipeline: pipeline_id,
957973
material_bind_group_index: Some(material.binding.group.0),
974+
vertex_slab: vertex_slab.unwrap_or_default(),
975+
index_slab,
976+
lightmap_slab: lightmap_slab_index
977+
.map(|lightmap_slab_index| *lightmap_slab_index),
958978
},
959979
asset_id: mesh_instance.mesh_asset_id.into(),
960980
},

crates/bevy_pbr/src/render/mesh.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ use bevy_render::{
3737
renderer::{RenderAdapter, RenderDevice, RenderQueue},
3838
texture::DefaultImageSampler,
3939
view::{
40-
prepare_view_targets, NoFrustumCulling, NoIndirectDrawing, RenderVisibilityRanges,
41-
ViewTarget, ViewUniformOffset, ViewVisibility, VisibilityRange,
40+
NoFrustumCulling, NoIndirectDrawing, RenderVisibilityRanges, ViewTarget, ViewUniformOffset,
41+
ViewVisibility, VisibilityRange,
4242
},
4343
Extract,
4444
};
@@ -221,8 +221,7 @@ impl Plugin for MeshRenderPlugin {
221221
gpu_preprocessing::write_batched_instance_buffers::<MeshPipeline>
222222
.in_set(RenderSet::PrepareResourcesFlush),
223223
gpu_preprocessing::delete_old_work_item_buffers::<MeshPipeline>
224-
.in_set(RenderSet::ManageViews)
225-
.after(prepare_view_targets),
224+
.in_set(RenderSet::PrepareResources),
226225
collect_meshes_for_gpu_building
227226
.in_set(RenderSet::PrepareAssets)
228227
.after(allocator::allocate_and_free_meshes)

examples/3d/lightmaps.rs

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,58 @@
11
//! Rendering a scene with baked lightmaps.
22
3-
use bevy::{pbr::Lightmap, prelude::*};
3+
use argh::FromArgs;
4+
use bevy::{
5+
core_pipeline::prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass},
6+
pbr::{DefaultOpaqueRendererMethod, Lightmap},
7+
prelude::*,
8+
};
9+
10+
/// Demonstrates lightmaps
11+
#[derive(FromArgs, Resource)]
12+
struct Args {
13+
/// enables deferred shading
14+
#[argh(switch)]
15+
deferred: bool,
16+
}
417

518
fn main() {
6-
App::new()
7-
.add_plugins(DefaultPlugins)
8-
.insert_resource(AmbientLight::NONE)
19+
#[cfg(not(target_arch = "wasm32"))]
20+
let args: Args = argh::from_env();
21+
#[cfg(target_arch = "wasm32")]
22+
let args: Args = Args::from_args(&[], &[]).unwrap();
23+
24+
let mut app = App::new();
25+
app.add_plugins(DefaultPlugins)
26+
.insert_resource(AmbientLight::NONE);
27+
28+
if args.deferred {
29+
app.insert_resource(DefaultOpaqueRendererMethod::deferred());
30+
}
31+
32+
app.insert_resource(args)
933
.add_systems(Startup, setup)
1034
.add_systems(Update, add_lightmaps_to_meshes)
1135
.run();
1236
}
1337

14-
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
38+
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, args: Res<Args>) {
1539
commands.spawn(SceneRoot(asset_server.load(
1640
GltfAssetLabel::Scene(0).from_asset("models/CornellBox/CornellBox.glb"),
1741
)));
1842

19-
commands.spawn((
43+
let mut camera = commands.spawn((
2044
Camera3d::default(),
2145
Transform::from_xyz(-278.0, 273.0, 800.0),
2246
));
47+
48+
if args.deferred {
49+
camera.insert((
50+
DepthPrepass,
51+
MotionVectorPrepass,
52+
DeferredPrepass,
53+
Msaa::Off,
54+
));
55+
}
2356
}
2457

2558
fn add_lightmaps_to_meshes(

0 commit comments

Comments
 (0)