2D: Changes to Z-ordering of entities with custom materials (not sprites) not reflected properly in rendering
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## Bevy version and features
This bug appears on `0.19`, and on `main` (`306aaed`), but does not appear on `0.18.1`.
Using default features.
## Relevant system information
Hardware info:
```ignore
AdapterInfo { name: "AMD Radeon RX 9070 (RADV GFX1201)", vendor: 4098, device: 30032, device_type: DiscreteGpu, driver: "radv", driver_info: "Mesa 26.1.1", backend: Vulkan }
```
## What you did / what went wrong
I originally noticed this bug due to some entities in my game not being rendered in certain situations. While comparing render world and main world, I noticed that the z-ordering values seemed to be off-sync.
To reproduce, I set up two entities with a `ColorMaterial` that uses `AlphaMode2d::Blend`. Using `AlphaMode2d::Opaque` will not run into this bug. I couldn't reproduce this bug using `Sprite` directly, even if I gave it an `color` with an alpha. However, in my game I used neither `ColorMaterial` nor `Sprite` but a custom material, so this bug doesn't seem specific to `ColorMaterial`.
I set the `Transform` of one of the entities below the other, then after some frames, I update it to be above the other. I expect that change to be visible in the world because the moved entity should now be visible above the other. However, nothing changes visually, until I manually mark the `ColorMaterial` of the moved entity as changed (There is probably a cleaner way to trigger the necessary recomputation, but I don't understand the rendering internals well enough).
Here is a minimal-ish reproduction, this example moves the blue square above the green one after 100 frames but nothing happens, then after 300 frames, it marks the `ColorMaterial` of the blue square as changed and the change becomes visible.
```rust
use std::ops::DerefMut;
use bevy::prelude::*;
#[derive(Component)]
struct BlueSquare;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, update)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut>,
mut materials: ResMut>,
) {
commands.spawn(Camera2d);
let square_mesh = meshes.add(Rectangle::new(200.0, 200.0));
commands.spawn((
BlueSquare,
Mesh2d(square_mesh.clone()),
MeshMaterial2d(materials.add(Color::srgba(0.0, 0.25, 1.0, 0.9))),
Transform::from_xyz(0.0, 0.0, 0.05),
));
commands.spawn((
Mesh2d(square_mesh),
MeshMaterial2d(materials.add(Color::srgba(0.0, 1.0, 0.0, 0.9))),
Transform::from_xyz(50.0, 0.0, 1.0),
));
}
fn update(
mut frame: Local,
mut materials: ResMut>,
mut blue_transform_query: Query<&mut Transform, With>,
blue_material_query: Query<&MeshMaterial2d, With>,
) {
*frame += 1;
if *frame == 100 {
for mut transform in &mut blue_transform_query {
transform.translation.z = 2.05;
}
println!("Blue square was moved up, but we see no visual change.");
}
if *frame == 300 {
for handle in &blue_material_query {
// Mark as changed, don't actually change anything
let _ = materials.get_mut(handle).unwrap().deref_mut();
println!("Marked blue square material as changed, now we see a change.");
}
}
}
```
## Additional information
While googling I found #24628 - might be related, since its also referring to 0.19 and says that it's related to z-ordering, but I am not sure
Contributor guide
Research direction
Start with the minimal Rust reproduction in the issue and compare its behavior on 0.18.1, 0.19, and main. Trace the rendering path for Transform z-order changes on blended ColorMaterial and custom materials, especially the update that occurs only after the material is marked changed. Done means changing an entity's z position updates its visible ordering without mutating its material.
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
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100