Skip to content

Conversation

@Soulghost
Copy link
Contributor

@Soulghost Soulghost commented Aug 3, 2024

Objective

Solution

  • Thanks for the guidance from @DGriffin91, the current solution is to transmit the light_map through the emissive channel to avoid increasing the bandwidth of deferred shading.
  • Store lightmap sample result into G-Buffer and pass them into the Deferred Lighting Pipeline, therefore we can get the correct indirect lighting via the apply_pbr_lighting function.
  • The original G-Buffer lacks storage for lightmap data, therefore a new buffer is added. We can only use Rgba16Uint here due to the 32-byte limit on the render targets.

Testing

  • Need to test all the examples that contains a prepass, with both the forward and deferred rendering mode.
  • I have tested the ones below.
    • lightmaps (adjust the code based on the issue and check the rendering result)
    • transmission (it contains a prepass)
    • ssr (it also uses the G-Bufffer)
    • meshlet (forward and deferred)
    • pbr

Showcase

By updating the lightmaps example to use deferred rendering, this pull request enables correct rendering result of the Cornell Box.

diff --git a/examples/3d/lightmaps.rs b/examples/3d/lightmaps.rs
index 564a3162b..11a748fba 100644
--- a/examples/3d/lightmaps.rs
+++ b/examples/3d/lightmaps.rs
@@ -1,12 +1,14 @@
 //! Rendering a scene with baked lightmaps.
 
-use bevy::pbr::Lightmap;
+use bevy::core_pipeline::prepass::DeferredPrepass;
+use bevy::pbr::{DefaultOpaqueRendererMethod, Lightmap};
 use bevy::prelude::*;
 
 fn main() {
     App::new()
         .add_plugins(DefaultPlugins)
         .insert_resource(AmbientLight::NONE)
+        .insert_resource(DefaultOpaqueRendererMethod::deferred())
         .add_systems(Startup, setup)
         .add_systems(Update, add_lightmaps_to_meshes)
         .run();
@@ -19,10 +21,12 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
         ..default()
     });
 
-    commands.spawn(Camera3dBundle {
-        transform: Transform::from_xyz(-278.0, 273.0, 800.0),
-        ..default()
-    });
+    commands
+        .spawn(Camera3dBundle {
+            transform: Transform::from_xyz(-278.0, 273.0, 800.0),
+            ..default()
+        })
+        .insert(DeferredPrepass);
 }
 
 fn add_lightmaps_to_meshes(
image

Emissive Issue

The emissive light object appears incorrectly rendered because the alpha channel of emission is set to 1 in deferred rendering and 0 in forward rendering, leading to different emissive light result. Could this be a bug?

// pbr_deferred_functions.wgsl - pbr_input_from_deferred_gbuffer
let emissive = rgb9e5::rgb9e5_to_vec3_(gbuffer.g);
if ((pbr.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) != 0u) {
    pbr.material.base_color = vec4(emissive, 1.0);
    pbr.material.emissive = vec4(vec3(0.0), 1.0);
} else {
    pbr.material.base_color = vec4(pow(base_rough.rgb, vec3(2.2)), 1.0);
    pbr.material.emissive = vec4(emissive, 1.0);
}

// pbr_functions.wgsl - apply_pbr_lighting
emissive_light = emissive_light * mix(1.0, view_bindings::view.exposure, emissive.a);

@Olle-Lukowski Olle-Lukowski added C-Bug An unexpected or incorrect behavior A-Rendering Drawing game state to the screen S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Aug 3, 2024
@Olle-Lukowski
Copy link
Contributor

Btw, maybe we should open another issue for the emissive issue?

@JMS55 JMS55 added this to the 0.15 milestone Aug 3, 2024
@JMS55
Copy link
Contributor

JMS55 commented Aug 3, 2024

Related: #13871

@DGriffin91
Copy link
Contributor

The output of the deferred pass is already too large. We can't afford to include an additional attachment. I think the lightmap data should be stored in the emissive channel as it is essentially emissive.

@Soulghost
Copy link
Contributor Author

The output of the deferred pass is already too large. We can't afford to include an additional attachment. I think the lightmap data should be stored in the emissive channel as it is essentially emissive.

Good idea, the emissive object seems not need a lightmap, let me do some research and change the code.

@Soulghost
Copy link
Contributor Author

Soulghost commented Aug 15, 2024

If we use the deferred.y to store emissive or lightmap, we need to add an extra bit to distinguish between them. Therefore we can no longer use rgb9e5::vec3_to_rgb9e5_ to pack the emissive value, we need to pack it with the pack_unorm4x8_, there maybe loss of precision, is it affordable? Perhaps we should enable it only when a lightmap is included.

Note that the pack_unorm4x8_ can only store color values between 0.0 to 1.0. Therefore, if the emissive component's value exceeds one, as in the EDR rendering, this presents a problem.

Previous

let deferred = vec4(
    deferred_types::pack_unorm4x8_(vec4(base_color_srgb, in.material.perceptual_roughness)),
    rgb9e5::vec3_to_rgb9e5_(emissive),
    props,
    deferred_types::pack_24bit_normal_and_flags(octahedral_normal, flags),
);

New

let deferred = vec4(
    deferred_types::pack_unorm4x8_(vec4(base_color_srgb, in.material.perceptual_roughness)),
    deferred_types::pack_unorm4x8_(vec4(emissive_or_lightmap, has_lightmap)),
    props,
    deferred_types::pack_24bit_normal_and_flags(octahedral_normal, flags),
);

@DGriffin91
Copy link
Contributor

DGriffin91 commented Aug 15, 2024

Both the emissive and the light map need the extra precision and range from rgb9e5. My recommendation is actually to sum the emissive and light map into the emissive channel as light maps are essentially emissive.

You'd want to pre-multiply it by the diffuse color as seen here:

indirect_light += in.lightmap_light * diffuse_color;

@Soulghost Soulghost force-pushed the bugfix/lightmap_in_deferred_shading branch from 48340e5 to 2fedba4 Compare August 25, 2024 06:49
@Soulghost
Copy link
Contributor Author

Hi @DGriffin91 , I have used the emissive channel to transmit the lightmap data. Could you please review the code? Thank you.

@JMS55 JMS55 added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Sep 8, 2024
@Soulghost Soulghost force-pushed the bugfix/lightmap_in_deferred_shading branch from 055b9bc to 86d00ed Compare September 10, 2024 13:47
@Soulghost
Copy link
Contributor Author

Hi @JMS55 , I have synchronized my code with upstream and made necessary adaptations for the changes in the emissive's alpha channel. Now the lightmap works perfectly without the emissive issues we discussed earlier.
image

@JMS55 JMS55 added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Sep 11, 2024
@Soulghost
Copy link
Contributor Author

Hi @DGriffin91 , could you please help review these changes? Thank you.

Copy link
Contributor

@IceSentry IceSentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks fine, but can you answer me and @JMS55 about the LIGHTMAP shader_def that is still in the code instead of quietly resolving? I don't get why it's there.

@Soulghost
Copy link
Contributor Author

Hi @IceSentry and @JMS55 , we need to keep the LIGHTMAP shader definition because the fragment shader defined in pbr.wgsl is invoked by the Prepass Pipeline. The lightmap data is derived through the pbr_input_from_standard_material function. It is essential to use the LIGHTMAP keyword to ensure the lightmap_light is correctly fetched.

// Invoked from Prepass Pipeline
fn pbr_input_from_standard_material(
    in: VertexOutput,
    is_front: bool,
) -> pbr_types::PbrInput {
    // ...
    #ifdef LIGHTMAP
        pbr_input.lightmap_light = lightmap(
            in.uv_b,
            pbr_bindings::material.lightmap_exposure,
            in.instance_index);
    #endif
    // ...
}

@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Oct 18, 2024
@cart cart added this pull request to the merge queue Oct 18, 2024
Merged via the queue into bevyengine:main with commit 3a478ad Oct 18, 2024
1 check passed
pcwalton added a commit to pcwalton/bevy that referenced this pull request Dec 16, 2024
A previous PR, bevyengine#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.
github-merge-queue bot pushed a commit that referenced this pull request Dec 26, 2024
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.
ecoskey pushed a commit to ecoskey/bevy that referenced this pull request Jan 6, 2025
A previous PR, bevyengine#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.
mrchantey pushed a commit to mrchantey/bevy that referenced this pull request Feb 4, 2025
A previous PR, bevyengine#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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Lightmaps break when deferred rendering is enabled

8 participants