bevyengine / bevyengine/bevy

Artifact in sprite rendering

Open
#16,918 7 comments 1 reaction 0 assignees View on GitHub
A-Rendering C-Bug S-Needs-Investigation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version

0.15.0

## \[Optional\] Relevant system information
```ignore
`AdapterInfo { name: "AMD Radeon Graphics (RADV RENOIR)", vendor: 4098, device: 5686, device_type: IntegratedGpu, driver: "radv", driver_info: "Mesa 24.2.6", backend: Vulkan }`
```

## What you did

Example code, using this CC0 tilemap texture [Image](https://github.com/user-attachments/assets/8442c06e-7443-4190-b70b-eda7023269be)

```rust
use bevy::prelude::*;
use std::collections::HashMap;

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

fn startup(
mut commands: Commands,
assets: ResMut,
mut texture_atlas_layouts: ResMut>,
) {
let texture_handle = assets.load_with_settings(
"kenney_tiny-dungeon/Tilemap/tilemap_packed.png",
|settings: &mut bevy::image::ImageLoaderSettings| {
// Use `nearest` image sampling to preserve the pixel art style.
settings.sampler = bevy::image::ImageSampler::nearest();
},
);
let texture_atlas_layout =
TextureAtlasLayout::from_grid(UVec2::new(16, 16), 12, 11, None, None);
let texture_atlas_layout = texture_atlas_layouts.add(texture_atlas_layout);
commands.spawn(Camera2d);

let mut out = HashMap::new();

{ // generation, not super important, it just is easier to see the bug with some variety
for x in -2..=2 {
for y in -2..=2 {
out.insert(IVec2::new(x, y), 48);
}
}

for y in -2..=2 {
out.insert(IVec2::new(-3, y), 13);
out.insert(IVec2::new(3, y), 15);
}

for x in -2..=2 {
out.insert(IVec2::new(x, -3), 26);
out.insert(IVec2::new(x, 3), 2);
}

out.insert(IVec2::new(-3, -3), 25);
out.insert(IVec2::new(3, -3), 27);
out.insert(IVec2::new(-3, 3), 1);
out.insert(IVec2::new(3, 3), 3);
}

for (place, kind) in out {
let mut s = Sprite::from_atlas_image(texture_handle.clone(), TextureAtlas {
layout: texture_atlas_layout.clone(),
index: kind,
});
s.custom_size = Some(Vec2::new(1.0, 1.0));

let scale = 6.0;
commands.spawn((
s,
Transform::from_scale(Vec2::splat(16.0 * scale).extend(1.0))
* Transform::from_translation(place.as_vec2().extend(0.0)),
));
}
}
```

## What went wrong

There is misalignment ![Image](https://github.com/user-attachments/assets/b7121a9a-eabd-4f34-8c8c-a6ee508d4497)
It seems the bottom-left triangle of each quad has incorrect texturing, seemingly the wrong UVs, leading to it not matching the neighbouring triangle, and also bleeding over the edge of the atlas by 1 pixel

## Additional information
Maybe its something to do with rounding?!

Contributor guide

Open the contributing guide

Research direction

Start by running the provided reproduction with Bevy 0.15.0, the tilemap image, ImagePlugin::default_nearest(), Sprite::from_atlas_image(), and TextureAtlasLayout::from_grid(). Inspect the sprite atlas rendering path around the generated UVs and compare the bottom-left triangle with its neighboring triangle. Done means the reproduced atlas sprites are aligned without edge bleeding.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
computer-graphics, game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.