LWJGL Antialiased lines

Hi, I am making a minimap for my game. (See top right corner of below image)

Everything is perfect, except for the jagged outline. I draw lines around the edges of the map, but they aren’t smooth.

I’ve played around with the following settings:
GL11.glEnable(GL11.GL_LINE_SMOOTH);
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);

and they just make the lines look worse. Searching on google, I came across something called multisampling, I’m not sure if this is what I want though.

Note, this is rendering to a seperate texture. I don’t want full-scene antialiasing, just for the lines that make up the background of the minimap.

Can anyone help me?
Thanks,
Roland

You are not using 3d here, so

GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);

is useless.

Try adding this:

GL11.glEnable(GL_BLEND);
GL11.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

@Mac70
Blending doesn’t help with geometry like lines.

@roland

when you only want to activate multisampling aka. anti-aliasing for some geometrie like your minimap, you can do it like this.

  1. create a multisamples RenderBuffer
  2. render to that buffer
  3. copy/blit the result to the screen or texture which you want to render

Code should look like this:


// creating a multisampled renderbuffer
int samples = 4;//you can query the max supported samples by glGetIntegerv(GL_MAX_SAMPLES, out, 0);

int[] id = new int[1];
glGenRenderbuffers(1, i, 0);
glBindRenderbuffer(GL2ES2.GL_RENDERBUFFER, id[0]);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, width, height);

//blitting the buffer to the screen or a texture
 //bind the renderbuffer as colorbuffer to a FBO
  glBindFramebuffer(GL_READ_FRAMEBUFFER, id);//bind this FBO as read buffer
  //now bind the default Framebuffer(0: the screen) or a FBO with the texture
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, id2);

  //and as a last step copy the content of the multisampled renderbuffer
  glBlitFramebuffer(0, 0, width, height, 0, 0, dstWidth, dstHeight,  GL_COLOR_BUFFER_BIT, GL_LINEAR);

In your case I would do the rendering like this.
Clear the multisampled renderbuffer to some semi transparent black(like in your screenshot)
Render the minimap into it
Copy the renderbuffer into a texture(this step is needed to resolve the multisampling)
render the texture into the top right corner of your screen.

The thing is if you wouldn’t need a transparent minimap background, you could directly copy the minimap onto the screen.

ps:
Some googling unearthed this nice trick: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter22.html

Anti-aliased lines is actually pretty challenging in OpenGL.

You could use GL_LINES and line smoothing. Unfortunately, it won’t look the same across all platforms. Some will use anti-aliasing, and others will not.

If you want truly consistent smooth lines in OpenGL, you have some options:

  1. Use software rendering to draw the lines to a texture. If you are only targeting desktop, you can make use of Java2D to do the rasterization for you. Basically the step is just to render your Graphics to a BufferedImage, and then copy the pixels to a ByteBuffer and upload them to a GL texture.

This is really slow, and not something you should be doing every frame.

  1. Use multi-sampling like Danny02 said.

  2. Use triangles and calculate the anti-aliasing in a shader. This sounds a little daunting, but it just requires a little bit of vector math and a decent grasp of shaders. It also produces really high-quality lines, and gives way to other effects like stippling patterns, outer glows, and smooth color interpolation.

You can also achieve this without a shader, just by using a lookup texture to create a blurry line edge. The problem with this is that the anti-aliasing isn’t as accurate and doesn’t scale.

Both approaches are discussed here:

(There is code at the end of the Swiper tutorial that should give you smooth lines.)

For each point in your line, you simply ‘extrude’ it along the perpendicular depending on the line thickness. Using triangle strips, you only need 2 vertices for every point in your line. A more complex approach would be to use a miter join, with one technique described here:
https://forum.libcinder.org/topic/smooth-thick-lines-using-geometry-shader#23286000001269127

More advanced still would be to support different types of joins.

  1. Another solution which might work for you case is to apply FXAA or another AA technique done in the fragment shader. Since you are rendering your mini-map to a small texture, the impact shouldn’t be too significant.

I made a Soldat CTF map once, called Crusade. :slight_smile:

LWJGL’s Display.create() has an overloaded version that takes a PixelFormat. One of the PixelFormat’s constructors allows you to turn on anti-aliasing and set how many samples you want.

Here is an example using 4 samples:


// parameters: 0 alpha bits, 8 depth bits, 0 stencil bits, 4 samples
Display.create(new PixelFormat(0, 8, 0, 4));

Thanks for the replies everyone!

:slight_smile:

Is there a way I can check support for this? GLContext etc. Doesn’t seem to work until the display is actually created.

Will creating a multisampled renderbuffer simply achieve the same effect as using full screen antialiasing overriding the default Display.create()? (apart from being faster due to only being applied to the minimap) If so, unfortunately the results aren’t too great. I will need to go for a more complicated technique.

Thanks, I’ll have a look :slight_smile:

Display.create creates a standard renderbuffer with or without anti-aliasing, your renderbuffer is totally independent from the default renderbuffer. If 4,8 or even 16 MSAA isn’t enough you could also do super-sampling. Let’s say your mini-map is 150x75 pixel, you could create a renderbuffer twice the size (300x150). The blitting operation will then scale down the image with linear interpolation, which would give you even more quality.

I would help if this wasn’t another stupid killing-shooting game.

Great attitude and valuable post. Thanks very much for your contribution.

If you have any shader experience it’s pretty easy to implement your own version of line smoothing by simply modifying alpha based on distance from the mathematical line.