如何使用OpenGL在2D模式下渲染完美的线框矩形?

Roo*_*kie 15 c++ opengl

编辑:只是让你知道:我还没有完全解决这个问题,目前我正在使用0.5px偏移,它似乎工作,但正如其他人所说,它不是"适当的"解决方案.所以我正在寻找真正的交易,钻石退出规则解决方案根本不起作用.

我相信它可能是显卡中的一个错误,但如果是这样,那么任何专业程序员都应该为此提供防弹解决方案,对吧?

编辑:我现在买了一张新的nvidia卡(以前有ATI卡),我仍然遇到这个问题.在很多很多游戏中我也看到了同样的错误.所以我想这是不可能以一种干净的方式修复?

这是错误的图像:

在此输入图像描述

你是如何克服这个问题的?如果可能的话,最好是非着色器解决方案.当我自己绘制4条单独的线而不是使用线框模式时,我尝试设置第一条线的偏移量,但是效果不是很好:如果矩形大小改变了,它有时看起来很完美,但有时甚至比修复之前更糟糕.

这就是我渲染四边形的方式:

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_QUADS);
    glVertex2f(...);
    glVertex2f(...);
    glVertex2f(...);
    glVertex2f(...);
glEnd();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
Run Code Online (Sandbox Code Playgroud)

是的,我知道我可以使用顶点数组或VBO,但这不是重点.

我也尝试过GL_LINE_LOOP,但它没有解决这个问题.

编辑:一个解决方案是,到目前为止:Lie Ryan的Opengl像素完美2D绘图:

请注意,OpenGL坐标空间没有整数概念,一切都是浮点数,OpenGL像素的"中心"实际上是0.5,0.5而不是左上角.因此,如果你想要从0,0到10,10(含)的1px宽线,你真的必须画一条从0.5,0.5到10.5,10.5的线.

如果你打开抗锯齿,这将是特别明显的,如果你有抗锯齿,并且你尝试从50,0到50,100绘制,你可能会看到模糊的2px宽线,因为线条落在两个像素之间.

dat*_*olf 10

这不是错误,这完全遵循规范.不绘制线的最后一个像素以防止使用以下线段过度绘制,这会导致混合问题.解决方案:发送最后一个顶点两次.

代码更新

// don't use glPolygonMode, it doesn't
// do what you think it does
glBegin(GL_LINE_STRIP);
    glVertex2f(a);
    glVertex2f(b);
    glVertex2f(c);
    glVertex2f(d);
    glVertex2f(a);
    glVertex2f(a); // resend last vertex another time, to close the loop
glEnd();
Run Code Online (Sandbox Code Playgroud)

顺便说一句:你应该学习如何使用顶点数组.立即模式(glBegin,glEnd,glVertex调用)已从OpenGL-3.x内核中移除.


Tro*_*our 9

虽然您已经发现将点数移动0.5会使问题消失,但这并不是您认为的原因.

答案确实存在于钻石退出规则中,这也是对Opengl像素完美2D绘图的正确接受答案的核心.

下图显示了四个片段/像素,每个片段/像素都刻有一颗钻石.四个彩色斑点代表四边形/线环的可能起点,即第一个顶点的窗口坐标.

片段钻石外可能的顶点

你没有说你在绘制四边形的方式,但没关系.为了论证的缘故,我会假设你正在顺时针绘制它.问题是所显示的四个片段的左上角是否会通过栅格化你的第一行或最后一行产生(它不能同时存在).

  1. 如果从黄色顶点开始,则第一条线穿过菱形并在水平向右移动时退出.因此,片段将由于第一行的光栅化而产生.

  2. 如果你从绿色顶点开始,那么第一行退出片段而不通过钻石,因此永远不会退出钻石.然而,最后一行将垂直穿过它,并在它上升回绿色顶点时退出.因此,片段将由于最后一行的光栅化而产生.

  3. 如果从蓝色顶点开始,则第一条线穿过菱形并在水平向右移动时退出.因此,片段将由于第一行的光栅化而产生.

  4. 如果你从红色顶点开始,那么第一行退出片段而不通过钻石,因此永远不会退出钻石.最后一条线也不会穿过钻石,因此当它上升回红色顶点时不会退出钻石.因此,不会因为任一行的光栅化而产生片段.

请注意,钻石内部的任何顶点都会自动生成碎片,因为第一条线必须退出钻石(假设您的四边形实际上足够大,可以留下钻石).