OpenGL: Drawing very thin triangles with TriangleList turn into points

3k Views Asked by At

I'm using TriangleList to output my primitives. Most all of the time I need to draw rectangles, triangles, circles. From time to time I need to draw very thin triangles (width=2px for example). I thought it should look like a line (almost a line) but it looks like separate points :)

Following picture shows what I'm talking about:

enter image description here

First picture at the left side shows how do I draw a rectangle (counter clockwise, from top right corner). And then you can see the "width" of the rectangle which I call "dx".

How to avoid this behavior? I would it looks like a straight (almost straight) line, not as points :)

5

There are 5 best solutions below

1
On BEST ANSWER

This is the problem of skinny triangles in general. For example, in adaptive subdivision when you have skinny T-junctions, it happens all the time. One solution is to draw the edges (you can use GL_LINE_STRIP) with having antialiasing effect on You can have:

Gl.glShadeModel(Gl.GL_SMOOTH);
Gl.glEnable(Gl.GL_LINE_SMOOTH);
Gl.glEnable(Gl.GL_BLEND);
Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
Gl.glHint(Gl.GL_LINE_SMOOTH_HINT, Gl.GL_DONT_CARE);

before drawing the lines so you get lines when your triangle is very small...

0
On

As @BrettHale mentions, this is an aliasing problem. For example,

enter image description here

Without super/multisampling, the triangle only covers the centre of the bottom right pixel and only it will receive colour. Real pixels have area and in a perfect situation, would receive a portion of the colour equal to the area covered. "Antialiasing" techniques reduce aliasing effects caused by not integrating colour across pixels.

enter image description here

Getting it to look right without being incredibly slow is hard. OpenGL provides GL_POLYGON_SMOOTH, which conservatively rasterizes triangles and draws the correct percentages of colour to each pixel using blending. This works well until you have overlapping triangles and you hit the problem of transparency sorting where order-independent transparency is needed. A simple and more brute force solution is to render to a much bigger texture and then downsample. This is essentially what supersampling does, except the samples can be "anisotropic" (irregular) which gives a nicer result. Multisampling techniques are adaptive and a bit more efficient, e.g. supersample pixels only at triangle edges. It is fairly straightforward to set this up with OpenGL.

However, as the triangle area approaches zero the area will too and it'll still disappear entirely even with antialiasing (although will fade out rather than become pixelated). Although not physically correct, you may instead be after a minimum 1-pixel width triangle so you get the lines you want even if it's a really thin triangle. This is where doing your own conservative rasterization may be of interest.

enter image description here

0
On

This is called a subpixel feature, when geometry gets smaller than a single pixel. If you animated the very thin triangle, you would see the pixels pop in and out.

Try turning multi-sampling on. Most GL windowing libraries support multisampled back buffer. You can also force it on in your graphics driver settings.

0
On

If the triangle is generated by geometry shader, then you can make the triangle area dynamic.
For example, you can make the triangle width always greater than 1px.

// ndc coord is range from -1.0 to 1.0 and the screen width is 1920.
float pixel_unit = 2.0 / 1920.0;
vec2 center = 0.5 * (triangle[0].xy + triangle[1].xy );

// Remember to divide the w component.
float triangle_width = (triangle[0].xy - center)/triangle[0].w;
float scale_ratio = pixel_unit / triangle_width;
if (scale_ratio > 1.0){
triagle[0].xy = (triangle[0].xy - center)  * scale_ratio + center;
triagle[1].xy = (triangle[1].xy - center)  * scale_ratio + center;
}
0
On

This issue can also be addressed via conservative rasterisation. The following summary is reproduced from the documentation for the NV_conservative_raster OpenGL extension:

This extension adds a "conservative" rasterization mode where any pixel that is partially covered, even if no sample location is covered, is treated as fully covered and a corresponding fragment will be shaded.

Similar extensions exist for the other major graphics APIs.