9
$\begingroup$

Code:

#include <math.h>
#include <GL/glut.h>
#pragma comment(lib, "opengl32")
#include <gl/gl.h>
#include <gl/glu.h>

//Initialize OpenGL 
void init(void) {
    glClearColor(0, 0, 0, 0);

    glViewport(0, 0, 500, 500);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(0, 500, 0, 500, 1, -1);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
} 

void drawLines(void) {
    glClear(GL_COLOR_BUFFER_BIT);  
    glColor3f(1.0,1.0,1.0); 

    glBegin(GL_LINES);

    glVertex3d(0.5,         0.999,  0.0f);
    glVertex3d(499.501,     0.999,  0.0f);

    glEnd();

    glFlush();
} 


int _tmain(int argc, _TCHAR* argv[])
{
    glutInit(&argc, argv);  
    glutInitWindowPosition(10,10); 
    glutInitWindowSize(500,500); 
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); 

    glutCreateWindow("Example"); 
    init(); 
    glutDisplayFunc(drawLines); 
    glutMainLoop();

    return 0;
}

Problem description:

  • Above code will put the entire bottom row pixels of the window client area to white.
  • If I swap the command order, from glVertex3d(0.5, 0.999, 0.0f);glVertex3d(499.501, 0.999, 0.0f); to glVertex3d(499.501, 0.999, 0.0f);glVertex3d(0.5, 0.999, 0.0f);, then only the left bottom pixel will not draw.

My understandings:

  • The two vertices will be finally transformed to 2D pixel center coordinate which are (0.0, 0.499) and (499.001, 0.499).
  • The line drawing algorithm only accept pixel center integer points as input.
  • So the two vertices will using int(x + 0.5) and will be (0, 0) and (499 , 0). This conforms to first result but contradict to the result when input order changed. Why?
$\endgroup$

1 Answer 1

10
$\begingroup$

The difference in which pixels are covered depending on the vertex order is related to rasterization rules. They're the rules that the GPU hardware uses to determine exactly which pixels are covered by a primitive.

Rasterization rules are a bit subtle. One of their goals is to ensure that whenever you draw multiple primitives that are connected water-tightly, the rasterization never produces any cracks between them, nor are any pixels covered twice (that's important for blending). To achieve that, the rules have some very specific edge and corner cases. Literally...they're cases having to do with primitive edges and corners. :)

In the case of lines, it works as follows. There's a diamond-shaped region around each pixel center, as shown in this snippet of the diagram from the MSDN article linked above.

diamond rule for line rasterization

The rule is that a pixel is covered if the line exits the diamond, when tracing from the start to the end of the line. Note that a pixel doesn't get covered if the line enters, but doesn't exit, the diamond. This ensures that if you have two line segments connected end to end, that the pixel at their shared endpoint only belongs to one of the segments and thus doesn't get rasterized twice.

You can also see in the above diagram how changing the order of the vertices can affect which pixels are covered (which doesn't happen with triangles, BTW). The diagram shows two line segments that are identical except for swapping the endpoint order, and you can see it makes a difference which pixel gets covered.

Your line segment is somewhat analogous to this. The left end, at (0.5, 0.999) is inside the diamond of the (0, 0) pixel, so it gets covered when it's the first vertex (the line starts inside the diamond, then exits it) and not when it's the second vertex (the line enters the diamond, and ends inside it, so it never exits). Actually, the vertices are snapped to fixed-point with 8 subpixel bits before rasterization, so this one ends up rounded to (0.5, 1.0), which is exactly on the top corner of the diamond. Depending on the rasterization rules, this might or might not be considered inside the diamond; it seems as if on your GPU it's considered inside, but this can vary between implementations, as the GL spec doesn't nail down the rules entirely.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.