Skip to content

Conversation

@ashivaram23
Copy link
Contributor

@ashivaram23 ashivaram23 commented Nov 9, 2025

Objective

When Bevy splits mip generation for environment maps into two passes due to limits, the second pass binds a view to the the original texture when it's supposed to be the 6th mip level of an intermediate one. This causes an error on WebGPU in browsers if that original texture doesn't already have mipmaps.

This affects the atmosphere example on WebGPU, but there are other issues there too so it still won't work after this.

Solution

Create texture view from the texture in the IntermediateTextures component instead of in RenderEnvironmentMap

Testing

Example that doesn't work on WebGPU before this (replace square.png with any power of 2 square image that doesn't store mipmaps)
use bevy::prelude::*;

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

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(0.0, 0.0, 5.0),
        GeneratedEnvironmentMapLight {
            environment_map: asset_server.load("square.png"),
            intensity: 1000.0,
            ..Default::default()
        },
    ));

    commands.spawn((
        Mesh3d(meshes.add(Sphere::new(1.0).mesh().build())),
        MeshMaterial3d(materials.add(StandardMaterial {
            perceptual_roughness: 0.1,
            metallic: 1.0,
            ..Default::default()
        })),
    ));
}

@github-actions
Copy link
Contributor

github-actions bot commented Nov 9, 2025

Welcome, new contributor!

Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨

@alice-i-cecile alice-i-cecile added C-Bug An unexpected or incorrect behavior A-Rendering Drawing game state to the screen O-WebGPU Specific to the WebGPU render API S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Nov 9, 2025
@alice-i-cecile alice-i-cecile added this to the 0.17.3 milestone Nov 9, 2025
Copy link
Contributor

@mate-h mate-h left a comment

Choose a reason for hiding this comment

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

Related issue #21700. I can confirm that this fixes the original issue in the browser console for the mip chain, however the example still remains broken due to deferred rendering and SSR.
I tested your branch with the bevy CLI. Leaving these set of commands for other reviewers.

git remote add ashivaram23 https://github.com/ashivaram23/bevy.git
git checkout -b envmap-mip-binding-fix ashivaram23/envmap-mip-binding-fix
bevy run --example atmosphere --features=debug,webgpu web

I noticed that if I disable deferred rendering and SSR the atmosphere example works on web again. So there will need to be another PR for addressing the issue I mentioned. Code change looks good to me!

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Nov 9, 2025
Merged via the queue into bevyengine:main with commit 2facb25 Nov 9, 2025
45 checks passed
@github-project-automation github-project-automation bot moved this to Done in Rendering Nov 9, 2025
mockersf pushed a commit that referenced this pull request Nov 17, 2025
# Objective

When Bevy splits mip generation for environment maps into two passes due
to limits, the second pass binds a view to the the original texture when
it's supposed to be the 6th mip level of an intermediate one. This
causes an error on WebGPU in browsers if that original texture doesn't
already have mipmaps.

This affects the atmosphere example on WebGPU, but there are other
issues there too so it still won't work after this.

## Solution

Create texture view from the texture in the `IntermediateTextures`
component instead of in `RenderEnvironmentMap`

## Testing

<details>

<summary>Example that doesn't work on WebGPU before this (replace
square.png with any power of 2 square image that doesn't store
mipmaps)</summary>

```rust
use bevy::prelude::*;

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

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(0.0, 0.0, 5.0),
        GeneratedEnvironmentMapLight {
            environment_map: asset_server.load("square.png"),
            intensity: 1000.0,
            ..Default::default()
        },
    ));

    commands.spawn((
        Mesh3d(meshes.add(Sphere::new(1.0).mesh().build())),
        MeshMaterial3d(materials.add(StandardMaterial {
            perceptual_roughness: 0.1,
            metallic: 1.0,
            ..Default::default()
        })),
    ));
}
```

</details>
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 O-WebGPU Specific to the WebGPU render API S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants