GLSL plotting a line, 2 ways.

Firstly, to plot a "function".. 


float plot(vec2 uv, float pct){
    return step(pct-0.01,uv.y)-
        step(pct+0.01,uv.y);
}

void main(void)
{
    vec2 uv = v_texcoord;
    vec3 col=vec3(0);
    
    float y = smoothstep(0.,1.,uv.x);
    y=(sin(uv.x*6.28)+1)*0.5;
    float pct=plot(uv,y);
    col+=pct*vec3(0.0,1.0,0.0);
    
    gl_FragColor = vec4(col,
        1.0);
}

 

In the main function, I've made a float value "y", which I intialise with a boring smoothstep function between the values 0 and 1. However we're not plotting that. I immediately overwrite y with what is essentially a sin(x) function. The numbers added and multiplied are just there to fit one cycle into the UV space of 0-1. (6.28 is a bad approximation of 2*PI - ie 360 degrees, +1 is to shift everything up by one on the y axis. and *0.5 to get it within the 0-1 range again.

The plot function takes the uv coordinate and  the curve we want to draw as arguments.

What we're doing is filling everything above the sin(x) line and then subtracting the same shape again, with a bit of an offset, thus making the line. Comment out the last line of the plot and alter the code accordingly to see this in action. The same is in action if you were to draw an outline of a circle.. You'd fill in a whole circle, then subtract a smaller one.


The next way is drawing a straight line between 2 points - it is using SDFs... signed distance fields.


float distLine(vec2 p,vec2 a,vec2 b){
vec2 pa=p-a;
vec2 ba=b-a;
float t=clamp(dot(pa,ba)/dot(ba,ba),0.0,1.0);
return length(pa-ba*t);

}

void main(void)
{
    vec2 uv =(v_texcoord-0.5)*2;
    vec3 col=vec3(0);
    float d=distLine(uv, vec2(cos(time),sin(time)),vec2(0));
    float m= smoothstep(0.1,0.05,d);
    col+=vec3(m);
     
    gl_FragColor = vec4(col,
        1.0);
}

The distLine function takes a position p (which we'll feed our uv coords into), and 2 points a and b, which are the two ends of the line. First we calculate the offset vectors from p to a and then the distance from a to b. We then project pa onto ba using the dot product. For this new value to be useful, we actually need it as a proportion of the full line ba, so we divide it by the value that projecting ba onto itself gives us. We then clamp the proportion between 0 and 1.
Finally, we subtract the proportion of the full line from pa and get the length of our line segment in this way.
In the main function I've setup the 2 points to be one that circles the other. The smoothstep is being used to define the thickness of the line. Note that the larger value is used first, then the smaller. This reverses the result, saving us from using a 1-x later.

 I think this guy explains what is happening a lot better -https://www.youtube.com/watch?v=3CycKKJiwis&t=395s

The gist is that vector BA actually describes an infinite line in that direction, and our maths is just chopping out the bit we really want.

Comments

Popular posts from this blog

setting VFX graph properties using C#