简体   繁体   中英

Drawing a perfect horizontal line at a specific position with a fragment shader

is it possible to draw a perfect horizontal line of a single pixel height at any chosen position on the vertical axis with a fragment shader applied to a screen aligned quad?

I have found many solutions with smoothstep or more complex functions but i am looking for an elegant and fast way of doing this.

A solution i have made is by using an exponential function and making it steeper but it have many shortcomings that i don't want (the line is not really one pixel height due to the exponential function and it is rather tricky to get one right), here is the GLSL code :

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;

    // a centered horizontal line
    float v = pow(uv.y - 0.5, 2.);

    // make it steeper
    v *= 100000.;

    // make it white on a black background
    v = clamp(1. - v, 0., 1.);

    fragColor = vec4(v);
}

Here is the shadertoy code which execute this: https://www.shadertoy.com/view/Ms2cWh

What i would like :

  • a perfect horizontal line drawn to a specific Y position in pixels units or normalized
  • its intensity limited to [0, 1] range without clamping
  • a fast way of doing it

If you just want to:

draw a perfect horizontal line of a single pixel height at any chosen position on the vertical axis with a fragment shader applied to a screen aligned quad

, then maybe:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    int iPosition = 250; // the y coord in pixels
    int iThickness = 10; // the thickness in pixels

    vec2 uv = fragCoord.xy / iResolution.xy;

    float v = float( iPosition ) / iResolution.y;
    float vHalfHeight = ( float( iThickness ) / ( iResolution.y ) ) / 2.;

    if ( uv.y > v - vHalfHeight && uv.y < v + vHalfHeight )
        fragColor = vec4(1.,1.,1.,1.); // or whatever color
}

Here is a neat solution without branching. I don't know if it is really faster than with branching though.

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;

    float py = iMouse.y/iResolution.y;

    float hh = 1./iResolution.y;

    // can also be replace with step(0., hh-abs(uv.y-py))
    float v = sign(hh-abs(uv.y-py));

    fragColor = vec4(v);
}

I know the question was answered properly before me, but in case someone is looking for a way to render a textured line in a pixel perfect way I wrote an article with some examples.

It's about pixel perfect UI in general, but using it for a line is just a matter of clamping/repeating texture sampling. Also I'm using Unity, but there is no reason the method would be exclusive to it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM