Nilirad/bevy_prototype_lyon

Shapes do not respect Z index in 2D

tqwewe opened this issue · 9 comments

Typically with sprites in bevy, you can draw on top of other things by using the Z translation as ordering.

Shapes drawn with this crate don't seem to respect the Z ordering provided in the translation.

I have the same issue. I found that Z ordering is arbitrary with these shapes. I ran the same program several times without any changes and the ordering changed.

In my experience this is not true. With this little system I can always make sure the orange line is drawn over the blue line.

fn setup_paint(mut cmd: Commands) {
  cmd.spawn_bundle(Camera2dBundle::default());
  let options = StrokeOptions::default().with_line_width(LINE_WIDTH);
  let mut path_builder = PathBuilder::new();
  path_builder.move_to(Vec2::ZERO);
  path_builder.line_to(100.0 * Vec2::ONE);
  let line = path_builder.build();
  cmd.spawn_bundle(GeometryBuilder::build_as(&line, DrawMode::Stroke(StrokeMode{color:Color::BLUE, options}), Transform::from_translation(Vec3::new(0.0, 0.0, 1.0))));
  cmd.spawn_bundle(GeometryBuilder::build_as(&line, DrawMode::Stroke(StrokeMode{color:Color::ORANGE, options}), Transform::from_translation(Vec3::new(0.0, 0.0, 4.0))));
}

Also from reading the code in src/rendering/mod.rs it states that it does:

  transparent_phase.add(Transparent2d {
      entity: *visible_entity,
      draw_function: draw_shape,
      pipeline: pipeline_id,
      // The 2d render items are sorted according to their z value before rendering,
      // in order to get correct transparency
      sort_key: FloatOrd(mesh_z),
      // This material is not batched
      batch_range: None,
  });

and the vertex shader just uses the z position of the clip_position.

I was confused myself about this because I was trying negative values for z which don't show at all. I think this is confusion between how z buffer and depth buffer work.

Please feel free to create an example if you see other behaviour.

I've also got this same problem. In the game I'm working on I've got 2 entities, one for the player and another for the base station (spawn point essentially). The ordering of these being drawn is non deterministic and the z-index seems to be disregarded. My repository https://github.com/andrewexton373/geometry-wars is an example of this problem occurring, and the gif in the README shows the non deterministic ordering results when the player is over the base.

let base_station = commands.spawn()
            .insert_bundle(lyon::GeometryBuilder::build_as(
                &base_shape,
                lyon::DrawMode::Outlined {
                    fill_mode: lyon::FillMode::color(Color::MIDNIGHT_BLUE),
                    outline_mode: lyon::StrokeMode::new(Color::WHITE, 5.0),
                },
                Transform { translation: Vec3::new(0.0, 0.0, -100.0), ..Default::default() }
            ))

 let player = commands.spawn()
            .insert(Player::new())
            .insert_bundle(lyon::GeometryBuilder::build_as(
                &player_shape,
                lyon::DrawMode::Outlined {
                    fill_mode: lyon::FillMode::color(Color::CYAN),
                    outline_mode: lyon::StrokeMode::new(Color::WHITE, 2.0),
                },
                Transform {
                    translation: Vec3::new(0.0, 0.0, 100.0),
                    ..Default::default()
                }
            ))

Interesting, I remember playing around with the depth/z value and I found/(remember) that negative values don't work.
Could you try with only positive values.

Just tried it with 10.0 for the player and 100.0 for the base. Still have the issue with these z values.

I saw this snippet in the code, so it seems like the z-index should already be taken into account for rendering:

transparent_phase.add(Transparent2d {
                    entity: *visible_entity,
                    draw_function: draw_shape,
                    pipeline: pipeline_id,
                    // The 2d render items are sorted according to their z value before rendering,
                    // in order to get correct transparency
                    sort_key: FloatOrd(mesh_z),
                    // This material is not batched
                    batch_range: None,
                });

I'm not sure if there's a bug here or somewhere related. I'll try and reproduce the issue in a simpler project.

I wasn't able to reproduce the issue by modifying your dynamic shape example to have 2 overlapping shapes, so now I'm beginning to think it might have something to do with my use of rapier2d in conjunction with this project that's introducing the issue?

I'm not entirely sure here, but I was able to solve this in a hacky way by making a system to force set the player Transform's Z to be above the shape I was clipping with. I think rapier2d may have been setting the Transform's Z unknowingly and I discovered that with the bevy_inspector_egui. Here's the system I used:

    // FIXME: is this really the only way? I feel like rapier2d is messing with the z-value...
    fn keep_player_on_top(
        mut player_query: Query<(&mut Player, &mut Transform), (With<Player>, Without<Crosshair>)>
    ) {
        for (player, mut transform) in player_query.iter_mut() {
            transform.translation.z = 100.0;
        }
    }