OpenGL的像素完美的2D绘图(Opengl pixel perfect 2D drawing)

2019-06-23 10:44发布

我工作的一个2D引擎。 它已经工作得很好,但我不断收到像素的错误。

例如,我的窗口是960×540个像素,我绘制从线(0,0)到(959,0)。 我预计在扫描线0每个像素将被设置为一种颜色,但没有:最右边的像素不绘制。 当我画垂直像素539.我真的需要提请同样的问题(960,0)或(0,540)将它绘制。

由于我出生在像素时代,我相信,这是不正确的结果。 当我的屏幕为320×200像素的大,我可以得出从0到319,并从0到199,和我的屏幕将是满的。 现在,我结束了与未绘制的右边/底部像素的屏幕。

这可能是由于不同的东西:在这里我想到了OpenGL线基本是从像素绘制包括一个像素,即最后一个像素只是实际上是排斥? 是不是这样? 我的投影矩阵是不正确的? 我是一个错误的假设,当我有960×540一个后备缓冲,也就是实际上有一个以上像素下? 别的东西?

有人可以帮帮我吗? 我一直在寻找这个问题很长一段时间,现在,每当我觉得还好的时候,我一会,它实际上并没有看到后。

下面是我的一些代码,我试图剥离下来,尽可能多地。 当我把我的线功能,每一个坐标与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;
    }

Answer 1:

在OpenGL中,线所使用的“钻石退出”规则光栅化。 这是几乎相同的话说,结束坐标为排他性的,但不是很...

这是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是几乎不可能的,看起来不错的方式来使用!)



Answer 2:

需要注意的是OpenGL的坐标空间没有整数概念,一切都是浮子和一个OpenGL像素的“中心”是真正在0.5,0.5,而不是它的左上角。 因此,如果你想有一个1px的宽线从0,0到10,10包容,你真的不得不画一条线,从0.5,0.5到10.5,10.5。

如果打开抗锯齿,如果你有抗锯齿和尝试借鉴50,0至50,100,你可能会看到一个模糊2px的宽线,因为线之间下降了两个像素这将尤为明显。



文章来源: Opengl pixel perfect 2D drawing