2
votes

What I am doing is a pick program. There are many triangles and I want select the front and visible ones by a rectangular region. The main method is described below.

  1. there are a lot of triangles and each triangle has its own color.
  2. draw all the triangles to a frame buffer.
  3. read the color of pixel in frame buffer and based on the color, we know which triangles are selected.

enter image description here

The problem is that there are some tiny triangles can not be displayed in the final frame buffer. Just like the green triangle in the picture. I think the triangle is too tiny and ignored by the graphic card.

My question is how to display the tiny triangles in the final frame buffer? or how to know which triangles are ignored by the graphic card?

2
If a triangle if of a sub-pixel size, how do you expect it to be selected?Amadan
@Amadan any method to know which triangles are ignored?wan
Sorry, no idea, OpenGL is not my forte. I'm just asking conceptually, to clarify your question. If by "select" you mean click, mouse resolution is one pixel, same as display resolution.Amadan
simple UX rule: if you can't expect the user to select on screen than provide a list on the side and allow filtering based on bounding boxesratchet freak
The tiny triangles are not ignored, they just don't cover a pixel while rasterisation.dari

2 Answers

4
votes

Triangles are not skipped based on their size, but if a pixel center does not fall inside or lie on the top or left edge (this is referred to as coverage testing) they do not generate any fragments during rasterization.

That does mean that certain really small triangles are never rasterized, but it is not entirely because of their size, just that their position is such that they do not satisfy pixel coverage.

Take a moment to examine the following diagram from the DirectX API documentation. Because of the size and position of the the triangle I have circled in red, this triangle does not satisfy coverage for any pixels (I have illustrated the left edge of the triangle in green) and thus never shows up on screen despite having a tangible surface area.

  enter image description here

If the triangle highlighted were moved about a half-pixel in any direction it would cover at least one pixel. You still would not know it was a triangle, because it would show up as a single pixel, but it would at least be pickable.


Solving this problem will require you to ditch color picking altogether. Multisample rasterization can fix the coverage issue for small triangles, but it will compute pixel colors as the average of all samples and that will break color picking.

Your only viable solution is to do point inside triangle testing instead of relying on rasterization. In fact, the typical alternative to color picking is to cast a ray from your eye position through the far clipping plane and test for intersection against all objects in the scene.

1
votes

The usability aspect of what you seem to be doing seems somewhat questionable to me. I doubt that most users would expect a triangle to be pickable if it's so small that they can't even see it. The most obvious solution is that you let the user zoom in if they really need to selectively pick such small details.

On the part that can actually be answered on a technical level: To find out if triangles produced any visible pixels/fragments/samples, you can use queries. If you want to count the pixels for n "objects" (which can be triangles), you would first generate the necessary query object names:

GLuint queryIds[n];  // probably dynamically allocated in real code
glGenQueries(n, queryIds);

Then bracket the rendering of each object with glBeginQuery()/glEndQuery():

loop over objects
    glBeginQuery(GL_SAMPLES_PASSED, queryIds[i]);
    // draw object
    glEndQuery(GL_SAMPLES_PASSED);

Then at the end, you can get all the results:

loop over objects
    GLint pixelCount = 0;
    glGetQueryObjectiv(queryIds[i], GL_QUERY_RESULT, &pixelCount);
    if (pixelCount > 0) {
        // object produced visible pixels
    }

A couple more points to be aware of:

  • If you only want to know if any pixels were rendered, but don't care how many, you can use GL_ANY_SAMPLES_PASSED instead of GL_SAMPLES_PASSED.
  • The query counts samples that pass the depth test, as the rendering happens. So there is an order dependency. A triangle could have visible samples when it is rendered, but they could later be hidden by another triangle that is drawn in front of it. If you only want to count the pixels that are actually visible at the end of the rendering, you'll need a two-pass approach.