代码:

#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;
}


问题描述:


上面的代码会将窗口客户区域的整个底部行像素设置为白色。
如果我从glVertex3d(0.5, 0.999, 0.0f);glVertex3d(499.501, 0.999, 0.0f);glVertex3d(499.501, 0.999, 0.0f);glVertex3d(0.5, 0.999, 0.0f);交换命令顺序,则仅不会绘制左下像素。

我的理解:


两个顶点最终将转换为2D像素中心坐标,分别是(0.0,0.499)和(499.001,0.499)。
画线算法仅接受像素中心整数点作为输入。
所以这两个顶点顶点将使用int(x + 0.5),分别为(0,0)和(499,0)。这符合第一个结果,但与输入顺序更改时的结果相矛盾。为什么?


#1 楼

根据顶点顺序覆盖像素的差异与光栅化规则有关。它们是GPU硬件用来确切确定基本像素覆盖哪些像素的规则。

栅格化规则有些微妙。他们的目标之一是确保每当绘制多个水密连接的图元时,栅格化都不会在它们之间产生任何裂纹,也不会覆盖任何像素两次(这对于混合很重要)。为此,规则有一些非常具体的边角情况。从字面上看...它们与原始边和角有关。 :)

对于行,它的工作方式如下。每个像素中心周围都有一个菱形区域,如上面链接的MSDN文章中的该图的片段所示。



规则是像素是从行的起点到终点跟踪时,如果线退出菱形,则覆盖。请注意,如果线条进入但不退出菱形,则像素不会被覆盖。这样可以确保如果有两个线段首尾相连,则它们共享端点处的像素仅属于其中一个线段,因此不会被两次光栅化。

您还可以在上图显示了更改顶点顺序如何影响覆盖哪些像素(三角形不会发生这种情况,BTW)。该图显示了两个线段,除了交换端点顺序外,它们是相同的,您可以看到它对覆盖哪个像素有所不同。

您的线段与此类似。左端(0.5,0.999)在(0,0)像素的菱形内部,因此当它是第一个顶点时(线开始于菱形内部,然后退出它),而不是第二个顶点时,它被覆盖顶点(线进入菱形,并在菱形内结束,因此它永远不会退出)。实际上,在栅格化之前,将顶点用8个子像素位捕捉到固定点,因此该顶点最终舍入为(0.5,1.0),恰好在菱形的顶角。根据光栅化规则,在钻石内部可能会考虑这一点,也可能不会考虑。好像在您的GPU上考虑了它一样,但这在不同的实现中可能会有所不同,因为GL规范并未完全确定规则。