Skip to content

Rendering artifacts visible when rendering "pixel art" style sprites with transparency #20027

Open
@cgonyeo

Description

@cgonyeo

Bevy version

0.16.1

Relevant system information

This is with:

  • cargo 1.87.0 (99624be96 2025-05-06)
  • Debian 12 (bookworm)
  • x86_64
  • some intel integrated graphics thing as my GPU

If your bug is rendering-related, copy the adapter info that appears when you run Bevy.

AdapterInfo { name: "Intel(R) HD Graphics 520 (SKL GT2)", vendor: 32902, device: 6422, device_type: IntegratedGpu, driver: "Intel open-source Mesa driver", driver_info: "Mesa 22.3.6", backend: Vulkan }

You should also consider testing the examples of our upstream dependencies to help isolate any setup-specific issue:

  • wgpu for rendering problems
  • winit for input and window management
  • gilrs for gamepad inputs

I can go try to put together a repro and file an issue with wgpu if you all here think that's a good next step for me

What you did

I'm attempting to put together a 2d game with "pixel art" style graphics, and I've noticed weird artifacts that bevy seems to be creating in fully transparent pixels that immediately border fully opaque pixels. I've put together a tiny demo of the issue here. The repro attempts to load in a sprite of a black circle with a transparent background and display it with a 2d camera on a gray background.

Here's the code:

use bevy::prelude::*;

const BACKGROUND_COLOR: Color = Color::srgb(0.5, 0.5, 0.5);

fn main() {
    App::new()
        .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
        .add_systems(Startup, setup)
        .insert_resource(ClearColor(BACKGROUND_COLOR))
        .run();
}

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
) {
    // Camera
    commands.spawn((
        Name::new("Camera"),
        Camera2d::default(),
        Projection::from(OrthographicProjection {
            scaling_mode: bevy::render::camera::ScalingMode::AutoMax {
                max_width: 100.0,
                max_height: 100.0,
            },
            scale: 1.,
            ..OrthographicProjection::default_2d()
        }),
    ));
    commands.spawn((
        Sprite::from_image(asset_server.load("circle.png")),
        Transform {
            translation: Vec3::new(0.0, 0.0, 0.0),
            ..default()
        },
    ));
}

What went wrong

When run, the output looks like this:

Image

Whereas I'm expecting the output to look like this:

Image

Note the lighter pixels bordering the black circle in the first image that are not present in the second image.

Additional information

I don't know if there are knobs available to me that I can turn to get rid of this rendering artifact. I tried playing with different values in the fields of ImagePlugin but that didn't help. I asked on discord and got a suggestion to add this snippet:

app.sub_app_mut(RenderApp)
    .insert_resource(GpuPreprocessingSupport {
        max_supported_mode: GpuPreprocessingMode::None,
    });

This also did not have a visible impact.

If anyone knows how to get the fully transparent pixels in the sprite to be rendered as fully transparent in bevy, that would be greatly appreciated, and thanks everyone for the awesome game engine!

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-BugAn unexpected or incorrect behaviorS-Needs-TriageThis issue needs to be labelled

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions