Opengl像素完美2D绘图

时间:2012-04-06 08:25:15

标签: opengl drawing pixel-perfect

我正在研发2d引擎。它已经运行良好,但我不断遇到像素错误。

例如,我的窗口是960x540像素,我从(0,0)到(959,0)画一条线。我希望扫描线0上的每个像素都会被设置为一种颜色,但是没有:最右边的像素没有被绘制。当我垂直绘制到像素539时,同样的问题。我真的需要绘制到(960,0)或(0,540)来绘制它。

当我出生在像素时代时,我确信这不是正确的结果。当我的屏幕大于320x200像素时,我可以从0到319从0到199画出,我的屏幕就会满了。现在我最终得到一个没有绘制右/底像素的屏幕。

这可能是由于不同的原因: 我期望将opengl线基元从像素绘制到包含像素,最后一个像素实际上是否排他?是吗? 我的投影矩阵不正确? 我有一个错误的假设,当我有一个960x540的后备缓冲区时,实际上有一个像素更多? 还有别的吗?

有人可以帮帮我吗?我一直在研究这个问题很长一段时间,每当我认为它没问题的时候,我看了一会儿它实际上没有。

这是我的一些代码,我试图尽可能地删除它。当我调用我的线函数时,每个坐标都加上0.375,0.375,以使它在ATI和nvidia适配器上都正确。

int width = resX();
int height = resY();

for (int i = 0; i < height; i += 2)
    rm->line(0, i, width - 1, i, vec4f(1, 0, 0, 1));
for (int i = 1; i < height; i += 2)
    rm->line(0, i, width - 1, i, vec4f(0, 1, 0, 1));

// when I do this, one pixel to the right remains undrawn

void rendermachine::line(int x1, int y1, int x2, int y2, const vec4f &color)
{
    ... some code to decide what std::vector the coordinates should be pushed into
    // m_z is a z-coordinate, I use z-buffering to preserve correct drawing orders
    // vec2f(0, 0) is a texture-coordinate, the line is drawn without texturing
    target->push_back(vertex(vec3f((float)x1 + 0.375f, (float)y1 + 0.375f, m_z), color, vec2f(0, 0)));
    target->push_back(vertex(vec3f((float)x2 + 0.375f, (float)y2 + 0.375f, m_z), color, vec2f(0, 0)));
}

void rendermachine::update(...)
{
    ... render target object is queried for width and height, in my test it is just the back buffer so the window client resolution is returned
    mat4f mP;
    mP.setOrthographic(0, (float)width, (float)height, 0, 0, 8000000);

    ... all vertices are copied to video memory

    ... drawing
    if (there are lines to draw)
        glDrawArrays(GL_LINES, (int)offset, (int)lines.size());

    ...
}

// And the (very simple) shader to draw these lines

// Vertex shader
    #version 120
    attribute vec3 aVertexPosition;
    attribute vec4 aVertexColor;
    uniform mat4 mP;
    varying vec4 vColor;
    void main(void) {
        gl_Position = mP * vec4(aVertexPosition, 1.0);
        vColor = aVertexColor;
    }

// Fragment shader
    #version 120
    #ifdef GL_ES
    precision highp float;
    #endif
    varying vec4 vColor;
    void main(void) {
        gl_FragColor = vColor.rgb;
    }

2 个答案:

答案 0 :(得分:15)

在OpenGL中,使用“Diamond Exit”规则对行进行栅格化。这几乎与说结束坐标是独占的相同,但不完全......

这是OpenGL规范所说的: http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html

另请参阅OpenGL常见问题解答,http://www.opengl.org/archives/resources/faq/technical/rasterization.htm,项目“14.090如何获得线条的精确像素化?”。它说“OpenGL规范允许使用各种线性渲染硬件,因此根本不可能进行精确的像素化。”

许多人认为你根本不应该在OpenGL中使用行。他们的行为是基于古老的SGI硬件的工作原理,而不是基于什么是有意义的。 (宽度> 1的线几乎不可能以看起来很好的方式使用!)

答案 1 :(得分:6)

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

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