Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pixel perfect texture mapping with modern OpenGL

After deciding to try programming in modern OpenGL, I've left behind the fixed function pipeline and I'm not entirely sure about getting the same functionality I had before.

I'm trying to texture map quads with pixel perfect size, matching the texture size. For example, a 128x128 texture maps to a quad 128x128 in size.

This is my vertex shader.


    #version 110
    uniform float xpos;
    uniform float ypos;
    uniform float tw; // texture width in pixels
    uniform float th; // texture height in pixels
    attribute vec4 position;
    varying vec2 texcoord;        
void main()
    {
    mat4 projectionMatrix = mat4( 2.0/600.0, 0.0, 0.0, -1.0,
                                  0.0, 2.0/800.0, 0.0, -1.0,
                                  0.0, 0.0, -1.0, 0.0,
                                  0.0, 0.0, 0.0, 1.0); 

    gl_Position = position * projectionMatrix;
    texcoord = (gl_Position.xy);
    }

This is my fragment shader:


    #version 110
    uniform float fade_factor;    
    uniform sampler2D textures[1];
    varying vec2 texcoord;

    void main()
    {
        gl_FragColor = texture2D(textures[0], texcoord);
    }

My vertex data is as such, where w and h are the width and height of the texture.


    [
     0, 0,
     w, 0,
     w, h,
     0, h
    ]

I load a 128x128 texture and with these shaders I see the image repeated 4 times: http://i.stack.imgur.com/UY7Ts.jpg

Can anyone offer advice on the correct way to be able to translate and scale given the tw th, xpos, xpos uniforms?

like image 401
Lefty Avatar asked Apr 23 '11 13:04

Lefty


1 Answers

There's a problem with this:

mat4 projectionMatrix = mat4( 2.0/600.0, 0.0, 0.0, -1.0,
                                  0.0, 2.0/800.0, 0.0, -1.0,
                                  0.0, 0.0, -1.0, 0.0,
                                  0.0, 0.0, 0.0, 1.0); 

gl_Position = position * projectionMatrix;

Transformation matices are right associative, i.e. you should multiply the opposite order. Also you normally don't specify a projection matrix in the shader, you pass it as a uniform. OpenGL provides you ready to use uniforms for projection and modelview. In OpenGL-3 core you can reuse the uniform names to stay compatible.

// predefined by OpenGL version < 3 core:
#if __VERSION__ < 400
uniform mat4 gl_ProjectionMatrix;
uniform mat4 gl_ModelviewMatrx;
uniform mat4 gl_ModelviewProjectionMatrix; // premultiplied gl_ProjectionMatrix * gl_ModelviewMatrix
uniform mat4 gl_ModelviewInverseTranspose; // needed for transformin normals

attribute vec4 gl_Vertex;

varying vec4 gl_TexCoord[];
#endif 

void main()
{
     gl_Position = gl_ModelviewProjectionMatrix * gl_Vertex;
}

Next you must understand that texture coordinates don't address texture pixels (texels), but that the texture should be understood as a interpolating function with the given sampling points; texture coordinates 0 or 1 don't hit the texel's centers, but lie exactly between the wraparound, thus blurring. As long as your quad on screen size exactly matches the texture dimensions this is fine. But as soon as you want to show just a subimage things get interesting (I leave it as an exercise to the reader to figure out the exact mapping; hint: You'll have the terms 0.5/dimension and (dimension - 1)/dimension in the solution)

like image 166
datenwolf Avatar answered Nov 07 '22 05:11

datenwolf