Opengl Pixel Perfect 2D Drawing

Я работаю над 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;
    }
30
задан scippie 6 April 2012 в 08:25
поделиться