Anti-Aliased Lines

So I have an application with a wireframe type draw and I was wondering if anyone has any useful tips/hints on doing really good line Anti-Aliasing with basic OpenGL?

Currently I…

  1. Enable GL_MULTISAMPLE.
  2. Enable GL_LINE_SMOOTH.
  3. Set glLineWidth() to 0.5
  4. Enable GL_BLEND (with standard blend function)
  5. Set glDepthMask to FALSE
  6. Set glHint to GL_NICEST

That is the basic stuff you can find in the RedBook. Anyone else have any suggestions for improving things?

If you enable GL_MULTISAMPLE (and you created a context such that when you query the value of GL_SAMPLE_BUFFERS, it returns 1),
GL_LINE_SMOOTH is ignored and multisampling rasterization is used.

ref: spec 2.1 page 107, section 3.4.4 Line Multisample Rasterization.

http://www.opengl.org/registry/doc/glspec21.20061201.pdf

so 2) and 4) are useless in this case.

For multisampling, I’m not sure that you want to set depth mask to FALSE.

Did not know that, thanks for the reply.

  1. Enable GL_LINE_SMOOTH.
  2. Set glLineWidth() to 0.5
  3. Enable GL_BLEND (with standard blend function)
  4. Set glDepthMask to FALSE
  5. Set glHint to GL_NICEST

…is be enough for just anti-aliased lines.

GL_MULTISAMPLE is for full anti-aliasing including solid triangles, and you must set up a multisampled framebuffer before it works.

Yes and no. The line are anti-aliased but the quality is not all that good, especially when you start drawing lines over other lines (you get bleeding and bluring).

Yep, I have the framebuffer set up. I have it working, I was just wondering if there were things I could do to improve the quality.

Right now, it looks “ok” but not “great”

Draw wide lines (2px or 4px) with a shader, that uses gl_FragCoord.xy and writes an opacity value in gl_FragColor.a

How do I use gl_FragCoord.xy?

How does the x,y window relative coordinates of a given fragment help me determine if I am near the edge of a line (which I assume I nned to know to set the alpha value?)?

search this board for it. There are two implementations, one by me that uses gl_FragCoord, and one that uses geometry shaders.

but note, that there are still issues with ATI and gl_FragCoord and FBOs…

So I found the following vertex shader and fragment shader on the forums but they don’t seem to work?

 
varying vec4 posix;
void main(){
	posix = ftransform();
	gl_Position=posix + vec4(0,0,0,0.001);
}

 
varying vec4 posix;
void main(){
	vec4 FinalColor = vec4(0.0,0.0,0.0,1.0);

	vec2 ScreenSizeHalf = vec2(1680/2,1050/2);
	vec2 posix1= ((posix.xy/posix.w)+1.0)*ScreenSizeHalf;
	vec2 fpos = gl_FragCoord.xy;
	float dist = distance(fpos,posix1);
	FinalColor.w = 1.0-dist;
	gl_FragColor = FinalColor;
}

I messed around with the code a little and it appears that the distance is always larger than 2.0? (I switched the second last line to “FinalColor.r = dist-2.0;” and the lines were still always red).

What am I doing wrong?

p.s. I am running a Nvidia Quadro FX570.
p.p.s My monitor is a Dell widescreen running at 1680x1050.

Well… at a first glance the code should work.
As for me, it seems strange, that NDC point got shifted by epsilon in W direction. In such a case you wouldn’t get exact coincidence between pipeline-calculated and self-calculated points. But I don’t think that’s the case. Cause the worst we could get - all the lines become “more closer” that they actually are.
Then, just for the case… Are you sure you have called glViewport() with these 1680,1050 numbers??
Then, if you say you always getting oversaturated distance - try visualizing, say, “distance*0.001” and look for it’s distribution. If you see radial gradient from upper-left corner - then you have troubles with “posix” varying.

if your viewport is really 1680x1050, then the code should work (have dist<=1.0). Hmm, try changing that vec4(0,0,0,0.001) to vec4(0,0,0.001,0)

no troubles, in the GLSL forum there’s a solution for it - how to manually calculate gl_FragCoord.

Good call guys, my viewport was not really 1680x1050, I have an 11 pixel border that I wasn’t considering when I hardcoded those values.

Have it working, now I just need to find that thread on how to manually calculate gl_FragCoord.

So far so good, thanks guys.

An improvement on the lines’ quality could be to gamma-correct the alpha value, I think. A 1D texture LUT for the gamma curve may be necessary, as all procedural functions I tried did not produce nice results.

So I have the code working (everything but the gamma LUT) and I am wondering if anyone has a suggestion for overlapping lines?

I currently draw lines in blue and white over a grey background. Not a problem until a white line is drawn over a blue line (or vice versa) and the two blend to a near grey color which blends right into the background making the line(s) almost invisible.

I realize it is a direct result of using the alpha for anti-aliasing but I can’t have lines just disappearing into the background.

I tried using the smoothstep() function on the dist value (to make the center of the line more opaque) but it does not work very well. I can get the line to appear clearer but I lose almost all of the anti-aliasing effect (well duh… saw that coming… but had to try).

Any other suggestions?

I have a hard time understanding how blending blue and white produces grey.
Can you post a screenshot (png if possible, to avoid jpeg artifacts) of your current method, with a number of white and blue lines crossing each other at various angles ?

I might suspect, PickleWorld means, that when he got blue (0,0,1)and white (1,1,1) blended to some sort of (0.5,0.5,1), this color looks almost like gray. And that’s the problem for him.
But screenshots are highly desirable. I may be totally wrong.

If you’re not going to antialias triangle edges with those AA lines, then draw those lines with a different blending func (i.e additive blending or multiplicative, etc).

So after some further investigation, I am not sure my code is working 100% correctly. Take a look at this image, the square on the left is drawn without my AA shader, the square on the right is drawn with the shader. In both cases you can see alias artifacts, just on the right it is blended.

That does not seem correct?

Ignoring that issue, here is another example image (it is a jpg but you can see what I was talking about above), on the left I have two squares drawn in blue, on the right are the same two squares but one is drawn in white. Where the two overlap you can see how the line is very hard to pick out from the background.

So yes, Jackis was correct, when I mix blue (0,0,1) with white (1,1,1) you get something close to grey (.5,.5,1) (Lines crossing one another at various angles are not a problem).

Drawing with different blending functions is an interesting thought, I might play with that a little.