bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Gizmos always draw on 2d sprites, z value and depth_bias neither works

Open gloridifice opened this issue 10 months ago • 4 comments

Bevy version

0.13.2

Content

I want gizmos lines draw behind 2d sprites. I tried Gizmos#line() with big negative z value and tried to change GizmosConfig#depth_bias to -1.0. Neither works. And I tried Gizmos#line_2d() with -1.0 GizmosConfig#depth_bias, it not works too.

Snipaste_2024-04-19_15-30-41
fn setup_gizmo_config(mut config_store: ResMut<GizmoConfigStore>) {
    for (_, config, _) in config_store.iter_mut() {
        config.depth_bias = -1.0;
        config.line_width = 1.0;
    }
}
gizmos.line(start1, end1, color);
gizmos.line(start2, end2, color);

gloridifice avatar Apr 19 '24 07:04 gloridifice

I took a little peek at this.

I ran into the same issue originally, but then noticed Gizmos.line_2d exists, which takes the start and end points as a Vec2 (eg. no z value).

I also noted that the docs for depth_bias state:

In 2D this setting has no effect and is effectively always -1.

Which leads me to believe that neither a z-value or depth bias will allow you to draw a gizmo behind a sprite.


After a bit of digging, I found out that you can draw a gizmo behind a sprite if you setup render_layers appropriately in the GizmoConfig and camera entities.

Here's a quick example:

use bevy::{prelude::*, render::view::RenderLayers};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_systems(Update, (set_config, gizmos).chain())
        .run();
}

fn setup(mut commands: Commands) {
    // "Bottom" camera
    let mut camera1 = Camera2dBundle::default();
    camera1.camera.order = 1;
    camera1.projection.scale = 0.1;
    commands.spawn((camera1, RenderLayers::layer(1)));

    // "Top" camera
    let mut camera2 = Camera2dBundle::default();
    camera2.camera.order = 2;
    camera2.projection.scale = 0.1;
    commands.spawn((camera2, RenderLayers::layer(2)));

    commands.spawn((
        SpriteBundle {
            sprite: Sprite {
                custom_size: Some(Vec2::splat(100.0)),
                ..default()
            },
            transform: Transform::from_xyz(0.0, 0.0, 10.0),
            ..default()
        },
        RenderLayers::layer(2),
    ));
}

fn gizmos(mut gizmos: Gizmos) {
    gizmos.line_2d(Vec2::new(-25.0, 25.0), Vec2::new(25.0, 25.0), Color::RED);
    gizmos.line_2d(Vec2::new(0.0, 0.0), Vec2::new(0.0, 50.0), Color::YELLOW);
}

fn set_config(mut config_store: ResMut<GizmoConfigStore>) {
    let (config, _) = config_store.config_mut::<DefaultGizmoConfigGroup>();
    // Use the render layer of the "bottom" camera
    config.render_layers = RenderLayers::layer(1);
}

Here, the gizmos are rendered behind the sprite. If you tweak the line in set_config, you can move the gizmos back in front of the sprite by using the render layer that is "on top".

config.render_layers = RenderLayers::layer(2);

jgayfer avatar Apr 26 '24 03:04 jgayfer

Some of the confusion might possibly come from the fact that 2D Gizmo methods are named as such, while most of the 3D methods don't have the _3d suffix?

jgayfer avatar Apr 26 '24 03:04 jgayfer

It works, thank you! Snipaste_2024-04-26_19-50-27

gloridifice avatar Apr 26 '24 11:04 gloridifice

Do we need a better method to do that? I think using z axis value to decide 2d gizmos' occlusion relationship is more intuitive.

gloridifice avatar Apr 26 '24 11:04 gloridifice