Nilirad / bevy_prototype_lyon

Draw 2D shapes in Bevy
Apache License 2.0
702 stars 87 forks source link

Shapes do not respect Z index in 2D #144

Open tqwewe opened 2 years ago

tqwewe commented 2 years ago

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.

lordbenedikt commented 2 years ago

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.

wrnrlr commented 2 years ago

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.

andrewexton373 commented 2 years ago

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()
                }
            ))
wrnrlr commented 2 years ago

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.

andrewexton373 commented 2 years ago

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

andrewexton373 commented 2 years ago

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.

andrewexton373 commented 2 years ago

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?

andrewexton373 commented 2 years ago

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;
        }
    }
seivan commented 5 months ago

There's probably some plugin system running that alters the z before rendering. That's why your hack is working.