Opengl pixel perfect 2D dibujo


Estoy trabajando en un motor 2d. Ya funciona bastante bien, pero sigo recibiendo errores de píxeles.

Por ejemplo, mi ventana es de 960x540 píxeles, dibujo una línea de (0, 0) a (959, 0). Esperaría que cada píxel en la línea de escaneo 0 se establezca en un color, pero no: el píxel más correcto no se dibuja. El mismo problema cuando dibujo verticalmente al píxel 539. Realmente necesito dibujar a (960, 0) o (0, 540) para tenerlo dibujado.

Como nací en la era de los píxeles, estoy convencido de que este no es el resultado correcto. Cuando mi pantalla era de 320x200 píxeles grande, podía sacar de 0 a 319 y de 0 a 199, y mi pantalla sería completa. Ahora termino con una pantalla con un píxel derecho/inferior no dibujado.

Esto puede deberse a diferentes cosas: donde espero que la línea primitiva de opengl se dibuje de un píxel a un píxel inclusive, ¿ese último píxel es realmente exclusivo? ¿Es eso? mi matriz de proyección es incorrecta? Estoy bajo una falsa suposición de que cuando tengo un backbuffer de 960x540, que es ¿realmente tiene un píxel más? Algo más?

¿Puede alguien ayudarme? He estado investigando este problema durante mucho tiempo, y cada vez que pensé que estaba bien, vi después de un tiempo que en realidad no lo estaba.

Aquí hay algo de mi código, traté de quitarlo todo lo posible. Cuando llamo a mi función de línea, cada coordenada se agrega con 0.375, 0.375 para que sea correcta tanto en adaptadores ATI como 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;
    }
Author: scippie, 2012-04-06

2 answers

En OpenGL, las líneas se rasterizan usando la regla "Diamond Exit". Esto es casi lo mismo que decir que la coordenada final es exclusiva, pero no del todo...

Esto es lo que la especificación de OpenGL tiene que decir: http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html

También echa un vistazo a las FAQ de OpenGL, http://www.opengl.org/archives/resources/faq/technical/rasterization.htm , item " 14.090 ¿Cómo obtengo la pixelización exacta de las líneas?". Dice: "La especificación OpenGL permite una amplia gama de hardware de renderizado de líneas, por lo que la pixelización exacta puede no ser posible en absoluto."

Muchos argumentarán que no debe usar líneas en OpenGL en absoluto. Su comportamiento se basa en cómo funcionaba el antiguo hardware SGI, no en lo que tiene sentido. (Y las líneas con anchuras > 1 son casi imposibles de usar de una manera que se vea bien!)

 15
Author: lurker number 5,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-06 09:29:50

Tenga en cuenta que el espacio de coordenadas de OpenGL no tiene noción de enteros, todo es un flotador y el "centro" de un píxel de OpenGL está realmente en el 0.5,0.5 en lugar de su esquina superior izquierda. Por lo tanto, si desea una línea ancha de 1px de 0,0 a 10,10 inclusive,realmente tuvo que dibujar una línea de 0.5,0.5 a 10.5, 10.5.

Esto será especialmente evidente si activa anti-aliasing, si tiene anti-aliasing y trata de dibujar de 50,0 a 50,100, puede ver una línea borrosa de 2px porque el la línea cayó entre dos píxeles.

 6
Author: Lie Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-06 08:42:27