Reputation: 2279
I'm trying to draw pixel-perfect lines in OpenGL using a fragment shader. I have the following fragment shader which I got from this question. However the result is 2-pixels in size rather than 1 pixel.
#version 330
layout(location=0) out vec4 frag_colour;
in vec4 color;
uniform vec2 positionA;
uniform vec2 positionB;
uniform int thickness;
float lineSegment(vec2 p, vec2 a, vec2 b, float thickness)
{
vec2 pa = p - a;
vec2 ba = b - a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
float k = length(pa - ba*h);
return smoothstep(0.0, thickness, k);
}
void main()
{
vec2 uv = gl_FragCoord.xy;
frag_colour = mix(color,vec4(0),lineSegment(uv,positionA,positionB,thickness));
}
As I understand it, this is because wherever the "line" is, the pixels to either side are technically the same distance away, so if I try to remove any kind of anti-aliasing, they are both "on the line" and so my 1-pixel wide line ends up being 2 pixels.
You can see how the yellow horizontal line is 2-pixels wide (compare it to the individual pixels in the text).
I've tried some other fragment code here and there from the internet and they all feature this same problem.
How can I draw a pixel-perfect, aliased (not anti-aliased), line in GLSL?
EDIT 1
After adjusting the positions and thickness by 0.5f
, so move to the centre of the pixels, the diagonal lines have anti-aliasing on each sort of "step".
Diagonal Line:
Upvotes: 2
Views: 2830
Reputation: 11
Perhaps this would be helpful (tested in shadertoy):
bool lineSegment(vec2 p, vec2 a, vec2 b, float thickness)
{
vec2 pa = p - a;
vec2 ba = b - a;
float len = length(ba);
vec2 dir = ba / len;
float t = dot(pa, dir);
vec2 n = vec2(-dir.y, dir.x);
float factor = max(abs(n.x), abs(n.y));
float distThreshold = (thickness - 1.0 + factor)*0.5;
float proj = dot(n, pa);
return (t > 0.0) && (t < len) && (proj <= distThreshold) && (proj > -distThreshold);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
vec2 positionA = iResolution.xy * 0.5;
vec2 positionB = iMouse.xy;
float thickness = 1.0;
fragColor = mix(vec4(0), vec4(1), float(lineSegment(fragCoord,positionA,positionB,thickness)));
}
Just in case, here's a related question on math.stackexchange.
Upvotes: 1