Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emissive materials not displayed properly when imported from gltf files #13133

Closed
Overblob opened this issue Apr 29, 2024 · 8 comments · Fixed by #13350
Closed

Emissive materials not displayed properly when imported from gltf files #13133

Overblob opened this issue Apr 29, 2024 · 8 comments · Fixed by #13350
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior

Comments

@Overblob
Copy link

Overblob commented Apr 29, 2024

Bevy version

0.13

Relevant system information

`AdapterInfo { name: "NVIDIA GeForce GTX 970", vendor: 4318, device: 5058, device_type: DiscreteGpu, driver: "NVIDIA", driver_info: "550.67", backend: Vulkan }`

What you did

Load a gltf (glb) scene using materials for bloom effect, and using KHR_materials_emissive_strength extension (supported since 0.12: #9553 )
Specifically the glb file used for this test:
https://github.com/KhronosGroup/glTF-Sample-Models/tree/main/2.0/EmissiveStrengthTest

What went wrong

  • what were you expecting?
    Bloom shall be displayed properly, as showed in the previous link

  • what actually happened?
    No bloom at all

Additional information

Seems to be a regression since 0.12 as it worked properly initially:

From v0.12.0
image

From v0.13.0
image

Edit : if the background seems brighter for v0.13 it's because the code uses the default exposure, which changed for this version, but as far as I can tell, this as no direct relation with the bloom issue (I tested the different const exposure values from the API)

Edit 2: minimal code to reproduce the issue:

use bevy::{core_pipeline::bloom::BloomSettings, prelude::*};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn((
        Camera3dBundle {
            camera: Camera {
                hdr: true,
                ..default()
            },
            transform: Transform::from_xyz(0.0, 6., 12.0)
                .looking_at(Vec3::new(0., 1., 0.), Vec3::Y),
            ..default()
        },
        BloomSettings::default(),
    ));

    commands.spawn((SceneBundle {
        scene: asset_server.load("EmissiveStrengthTest.glb#Scene0"),
        ..default()
    },));
}
@Overblob Overblob added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Apr 29, 2024
@IDEDARY
Copy link
Contributor

IDEDARY commented Apr 29, 2024

I encountered this issue too while exporting a GLTF from Blender.
What might be happening is that during the conversion process the value is somehow super scaled down.

  • Blender: 5.0 Emission strength - Should be quite emissive, it shines brightly in Blender and other GLTF viewers, in Bevy you cannot see any glow.

  • Blender: 200_000.0 Emission strength - The emission radius is several times the size of the object in Blender and other GLTF viewers are broken, in Bevy you can finally see a bit of glow.

@NthTensor
Copy link
Contributor

No exact causes, but here's some info: Gltf emission map is in candela per square meter. Emission strength is a unit-less quantity which scales the emission map (so that the final output also has units of candela per square meter). This issue means we probably are messing up the units somewhere.

@NthTensor NthTensor added A-Rendering Drawing game state to the screen and removed S-Needs-Triage This issue needs to be labelled labels Apr 29, 2024
@Overblob
Copy link
Author

I just bisected between v0.12 and v0.13 to find the responsible commit: fcd7c0f and associated PR: #11347

(Despite what I said, it finally may be related to exposure...)

@Overblob
Copy link
Author

Overblob commented Apr 29, 2024

// Total light
output_color = vec4<f32>(
view_bindings::view.exposure * (transmitted_light + direct_light + indirect_light + emissive_light),
output_color.a
);

Here we can see that the emissive_light gets multiplied by the exposure.

I tested after having moved out this variable from the parenthesis and boom, bloom worked again!

Still I'm not sure about this solution, as I don't master the exposure semantics.

As a side note, I 'd like to mention that as of #11347 examples for 2d and 3d bloom are not homogeneous when defining color values: not the same function, nor the same value ranges at all:

// Sprite
commands.spawn(SpriteBundle {
texture: asset_server.load("branding/bevy_bird_dark.png"),
sprite: Sprite {
color: Color::srgb(5.0, 5.0, 5.0), // 4. Put something bright in a dark environment to see the effect
custom_size: Some(Vec2::splat(160.0)),
..default()
},
..default()
});

let material_emissive1 = materials.add(StandardMaterial {
emissive: Color::linear_rgb(23000.0, 9000.0, 3000.0), // 4. Put something bright in a dark environment to see the effect
..default()
});

@fintelia
Copy link
Contributor

fintelia commented May 3, 2024

No exact causes, but here's some info: Gltf emission map is in candela per square meter. Emission strength is a unit-less quantity which scales the emission map (so that the final output also has units of candela per square meter). This issue means we probably are messing up the units somewhere.

Does that mean the tested value corresponds to 5 cd/m^2? Since that's is pretty low considering an LCD computer monitor is 200-300 cd/m^2 and Bevy's default exposure corresponds to a very bright indoor space / a heavily overcast outdoor scene. In those conditions, there's no way something 40x dimmer is going look like it is glowing...

@NthTensor
Copy link
Contributor

The issue is that, as I understand it, the default exposure is tuned to match blender. So one would expect a gltf exported from blender to have visually similar emission. That's not the case.

@fintelia
Copy link
Contributor

fintelia commented May 3, 2024

The default exposure is tuned so that point lights and directional lights match Blender. Everyone assumes that Blender got the math right, but I'm personally not very convinced.

One possible explanation is that blender is multiplying the values of lights by 683 before exporting, but is leaving the emissive materials with their original scale. Thus when imported into Bevy emissives are 683x dimmer than they appear in Blender.

@IDEDARY
Copy link
Contributor

IDEDARY commented May 3, 2024

The default exposure is tuned so that point lights and directional lights match Blender. Everyone assumes that Blender got the math right, but I'm personally not very convinced.

One possible explanation is that blender is multiplying the values of lights by 683 before exporting, but is leaving the emissive materials with their original scale. Thus when imported into Bevy emissives are 683x dimmer than they appear in Blender.

This simple multiplication doesn't really match my observed values, either the problem is more complex, or a different number is used :P

Blender: 5.0 Emission strength - Should be quite emissive, it shines brightly in Blender and other GLTF viewers, in Bevy you cannot see any glow.
Blender: 200_000.0 Emission strength - The emission radius is several times the size of the object in Blender and other GLTF viewers are broken, in Bevy you can finally see a bit of glow.

github-merge-queue bot pushed a commit that referenced this issue May 13, 2024
# Objective

- The StandardMaterial always uses ATTRIBUTE_UV_0 for each texture
except lightmap. This is not flexible enough for a lot of gltf Files.
- Fixes #12496
- Fixes #13086
- Fixes #13122
- Closes #13153

## Solution

- The StandardMaterial gets extended for each texture by an UvChannel
enum. It defaults to Uv0 but can also be set to Uv1.
- The gltf loader now handles the texcoord information. If the texcoord
is not supported it creates a warning.
- It uses StandardMaterial shader defs to define which attribute to use.

## Testing

This fixes #12496 for example:

![wall_fixed](https://github.com/bevyengine/bevy/assets/688816/bc37c9e1-72ba-4e59-b092-5ee10dade603)

For testing of all kind of textures I used the TextureTransformMultiTest
from
https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/TextureTransformMultiTest
Its purpose is to test multiple texture transfroms but it is also a good
test for different texcoords.
It also shows the issue with emission #13133.

Before:

![TextureTransformMultiTest_main](https://github.com/bevyengine/bevy/assets/688816/aa701d04-5a3f-4df1-a65f-fc770ab6f4ab)

After:

![TextureTransformMultiTest_texcoord](https://github.com/bevyengine/bevy/assets/688816/c3f91943-b830-4068-990f-e4f2c97771ee)
github-merge-queue bot pushed a commit that referenced this issue May 17, 2024
# Objective

- The emissive color gets multiplied by the camera exposure value. But
this cancels out almost any emissive effect.
- Fixes #13133
- Closes PR #13337 

## Solution
- Add emissive_exposure_weight to the StandardMaterial
- In the shader this value is stored in the alpha channel of the
emissive color.
- This value defines how much the exposure influences the emissive
color.
- It's equal to Google's Filament:
https://google.github.io/filament/Materials.html#emissive

https://github.com/google/filament/blob/4f021583f1c721486baaa9291be5943216c244ec/shaders/src/shading_lit.fs#L287

## Testing

- The result of
[EmissiveStrengthTest](https://github.com/KhronosGroup/glTF-Sample-Models/tree/main/2.0/EmissiveStrengthTest)
with the default value of 0.0:

without bloom:

![emissive_fix](https://github.com/bevyengine/bevy/assets/688816/8f8c131a-464a-4d7b-a9e4-4e28d679ee5d)

with bloom:

![emissive_fix_bloom](https://github.com/bevyengine/bevy/assets/688816/89f200ee-3bd5-4daa-bf64-8999b56df3fa)
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
Projects
None yet
4 participants