Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line thickness parameter breaks when lines are on the same x, y plane #2

Open
ramirezmike opened this issue Apr 14, 2021 · 10 comments
Open

Comments

@ramirezmike
Copy link

This is a little hard to describe and I might be misunderstanding some of it but I've written a little demo to show what I encountered.

Basically this code spawns a cube at (0.0, 0.0, 0.0) and then tries to draw 9 lines... four lines pointing up the Y axis, one line pointing up the X axis and four lines pointing up the Z axis.

This is what I get

Screenshot from 2021-04-13 22-22-11

with this code

    // vertical lines
    lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 5.0, 0.0),  0.01, Color::RED);
    lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.0, 5.0, 0.0),  0.01, Color::RED);
    lines.line_colored(Vec3::new(2.0, 0.0, 0.0), Vec3::new(2.0, 5.0, 0.0),  0.01, Color::RED);
    lines.line_colored(Vec3::new(3.0, 0.0, 0.0), Vec3::new(3.0, 5.0, 0.0),  0.01, Color::RED);

    // one line going up the x axis
    lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(5.0, 0.0, 0.0),  0.01, Color::RED);

    // four lines starting from different points on the 
    // x axis going from same x value but toward 5.0 z value
    lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 5.0),  0.01, Color::GREEN);
    lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 5.0),  0.01, Color::GREEN);
    lines.line_colored(Vec3::new(2.0, 0.0, 0.0), Vec3::new(2.1, 0.0, 5.0),  0.01, Color::GREEN);
    lines.line_colored(Vec3::new(3.0, 0.0, 0.0), Vec3::new(3.1, 0.0, 5.0),  0.01, Color::GREEN);

Note: the last two lines I could get to work by doing x values of 2.0 -> 2.1 and 3.0 -> 3.1. If I leave the X value the same (like in the first two green lines) then it doesn't show. And, I don't seem to get this issue with the other lines (the vertical lines and the X-axis line render fine despite only having the difference in one axis between start and end points)

If I change that part to this

    lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.1, 0.0, 5.0),  0.01, Color::GREEN);
    lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.1, 0.0, 5.0),  0.01, Color::GREEN);

then I get all four green lines

Screenshot from 2021-04-13 22-27-30

Here's the full code

use bevy::prelude::*;
use bevy_prototype_debug_lines::{ DebugLinesPlugin, DebugLines };

fn main() {
    App::build()
        .insert_resource(Msaa { samples: 4 })
        .add_plugins(DefaultPlugins)
        .add_plugin(DebugLinesPlugin)
        .add_startup_system(setup.system())
        .add_system(demo.system())
        .run();
}

fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
) {
    let mut transform = Transform::from_translation(Vec3::new(-2.4399414, 3.9506745, 5.9317107));
    transform.rotate(Quat::from_xyzw(-0.26216018, -0.36458296, -0.10775752, 0.88698345)); 

    commands.spawn_bundle(PerspectiveCameraBundle {
        transform,
        ..Default::default()
    });

    commands.spawn_bundle(PbrBundle {
        transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
        mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
        ..Default::default()
    });
}

fn demo(mut lines: ResMut<DebugLines>) {
    // vertical lines
    lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 5.0, 0.0),  0.01, Color::RED);
    lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.0, 5.0, 0.0),  0.01, Color::RED);
    lines.line_colored(Vec3::new(2.0, 0.0, 0.0), Vec3::new(2.0, 5.0, 0.0),  0.01, Color::RED);
    lines.line_colored(Vec3::new(3.0, 0.0, 0.0), Vec3::new(3.0, 5.0, 0.0),  0.01, Color::RED);

    // one line going up the x axis
    lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(5.0, 0.0, 0.0),  0.01, Color::RED);

    // four lines starting from different points on the 
    // x axis going from same x value but toward 5.0 z value
    lines.line_colored(Vec3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 5.0),  0.01, Color::GREEN);
    lines.line_colored(Vec3::new(1.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 5.0),  0.01, Color::GREEN);
    lines.line_colored(Vec3::new(2.0, 0.0, 0.0), Vec3::new(2.1, 0.0, 5.0),  0.01, Color::GREEN);
    lines.line_colored(Vec3::new(3.0, 0.0, 0.0), Vec3::new(3.1, 0.0, 5.0),  0.01, Color::GREEN);
}

@Toqozz
Copy link
Owner

Toqozz commented Apr 14, 2021

It looks like the culprit of a divide by zero in line.vert where we calculate the perpendicular vector:

vec2 dir = normalize(p2.xy - p1.xy);
vec2 perp = vec2(-dir.y, dir.x);

If p1 and p2 (line start and end) are on the same xy plane, then we'll get NaN from normalize(). This is a holdover from when I was just using this for 2d.

This line also has an implication that if you put the camera on the same xy plane as the line (looking at the line from the side), then you wont be able to see it.


There's a difficult question of what I want to do here. If we rotate lines to always face the camera, then they can look weird and I feel like it defeats the purpose of having a line thickness in the first place.

Here's an example where I get the perpendicular line vector from crossing the line direction and camera, so it faces the camera. This probably isn't a perfect implementation but you can get the idea:

output.mp4

It looks better with smaller lines, but I still don't love it.

The only other options that I can think of are:

  • Have the user tell us which way the line should "face" (ugh).
  • Try to do some kind of screen space thickness (line will have constant thickness at different z values, unless we do some complicated stuff).

All this has gotten me thinking though, does anybody really care about line thickness? We could just remove it, make lines have a constant 1px width, and make the plugin both dramatically simpler, more performant, and remove all these issues in one go.

I'm kind of inclined to just do that. Maybe we could keep thickness for 2d? Although even in 2d people may want to rotate the camera to use different planes.

Anyway, sorry for the wall of text, just kind of documenting thoughts here. I think it's best if I maybe make the default line have 1px thickness, and then later if people want thick lines we can think about bringing it back in a separate function, where they can also specify which way they want them to face.

Let me know if you have any thoughts or ideas, or if not, that's fine too.

@Toqozz Toqozz closed this as completed in cc86533 Apr 14, 2021
@Toqozz Toqozz reopened this Apr 14, 2021
@Toqozz Toqozz changed the title Lines don't display if they have the same X,Y values but different Z value Line thickness parameter breaks when lines are on the same x, y plane. Apr 14, 2021
@Toqozz Toqozz changed the title Line thickness parameter breaks when lines are on the same x, y plane. Line thickness parameter breaks when lines are on the same x, y plane Apr 14, 2021
@ramirezmike
Copy link
Author

If I get time, I might look into this more, but my initial thought when I read this...

If p1 and p2 (line start and end) are on the same xy plane, then we'll get NaN from normalize().

was to just add something that offsets it slightly. It may not be the pixel-perfect solution, but it would effectively work the same.

As a user, I guess I'm not expecting it to draw perfectly. When I ran into this, I was super confused, but, as you can see in that image I posted above, it's difficult to tell the difference between the two correct lines and the two offset lines.

@Toqozz
Copy link
Owner

Toqozz commented Apr 15, 2021

That's something I considered. The problem I have is that people are going to get lines that look buggy if they're not looking at them from the "correct" angle.

Here's the 3d example with the camera positioned to the left of the lines, and rotated right (clockwise) to look at them:

2021-04-15.12-15-52.mp4

I don't like that the angle of the camera affects visibility so much. I can imagine someone trying to draw lines and getting nothing because they're looking at it side on, and then thinking the crate doesn't work. You should be able to draw visible lines from anywhere, no matter where the camera is looking!

@CleanCut
Copy link
Contributor

I'm only using this plugin for 2D line rendering. It would be convenient for me if there were a way to specify a line width!

This isn't really a dealbreaker for me, though. I don't use debug lines much, and if I really find a strong need, I can dig into the git history and pull out the bits into my own custom code if I need. I mention it because you asked for thoughts!

The lines can seem quite thin, especially on hi-res screens:
Screen Shot 2021-12-26 at 7 46 19 PM

@zaycev
Copy link

zaycev commented Jun 19, 2022

+1, I'm only using 2d feature and 1 pixel lines are looking a bit too thin on high-resolution screens.

@zicklag
Copy link

zicklag commented Sep 30, 2022

👍 I ended up using Egui and epaint to draw lines in 2D and it definitely helped visibility for my collision shape rendering when the lines were thicker. Right now the line thickness is the only reason I'm not using this plugin instead.

@CleanCut
Copy link
Contributor

Interesting! I ended up using bevy_prototype_lyon, but since I want to switch to using bevy_rapier2d for collisions, I'm hoping I'll be able to take advantage of their debug rendering instead of rendering my own debug lines.

@zicklag
Copy link

zicklag commented Sep 30, 2022

Oh, actually lyon might be a better option for me, I forgot about that one. I'm not super happy how difficult it is to get things from world space to screen space for egui, and then I might make things even harder for myself by using a custom camera viewport setting, so lyon might fix that issue for me.

BTW, bevy_rapier2d uses a vendored copy of this debug lines plugin to draw it's lines, so you probably won't gain anything there! Oh, unless they use an older version of this crate that has the thickness setting.

You can setup a custom line renderer for bevy_rapier2d, though ( I actually did that for egui here ), and that's not difficult, so you can hook rapier up to render it's debug lines with lyon, which might be what I end up doing.

@CleanCut
Copy link
Contributor

Cool! I didn't know you could set up custom line rendering for bevy_rapier2d.

@hakolao
Copy link

hakolao commented Nov 17, 2022

  • 1 for thickness option

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants