0
\$\begingroup\$

I'm learning OpenGL and I don't understand why my texture is flipped if I give as UVs the "matching" vec2 of the mesh's vertex (vec3).

Example:

vert -256 -256
uv   0    0

vert 256 256
uv   1    1

I've had to try a different order for the UVs to be able to get the correct result...

Can someone explain why is that so? Thanks.

Screenshots:
http://imgur.com/a/49ZVp

This are the snippets of code I use:

// Create texture
GLuint texDebugId;

// RGBA Texture:
// R G
// B A

unsigned char texDebugBuf[] = {
    255, 0, 0, 255,
    0, 255, 0, 255,
    0, 0, 255, 255,
    0, 0, 0, 0,
};
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texDebugId);
glBindTexture(GL_TEXTURE_2D, texDebugId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDebugBuf);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);


//------------------------------


// Prepare VBOs
static const GLfloat verts[] = {
    -256.0f, -256.0f, 0.0f,
    256.0f, -256.0f, 0.0f,
    -256.0f, 256.0f, 0.0f,
    256.0f, 256.0f, 0.0f
};

/*
// FLIPPED (but why?)
static const GLfloat uvs[] = {
    0.0f, 0.0f,
    1.0f, 0.0f,
    0.0f, 1.0f,
    1.0f, 1.0f,
};
*/

// OK
static const GLfloat uvs[] = {
    0.0f, 1.0f,
    1.0f, 1.0f,
    0.0f, 0.0f,
    1.0f, 0.0f,
};

// Upload vertices
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

// Upload UVs
glBindBuffer(GL_ARRAY_BUFFER, vbo_tex_id);
glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);


//------------------------------


// Render
glBindTexture(GL_TEXTURE_2D, texId);

glEnableVertexAttribArray((GLuint) pd.vertex_a);
glEnableVertexAttribArray((GLuint) pd.uv_a);

// Vertices
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glVertexAttribPointer(
    (GLuint) pd.vertex_a,  // attribute id
    3,                     // size
    GL_FLOAT,              // type
    GL_FALSE,              // normalized?
    0,                     // stride
    (void *)0              // array buffer offset
);

// UVs
glBindBuffer(GL_ARRAY_BUFFER, vbo_tex_id);
glVertexAttribPointer(
    (GLuint) pd.uv_a,      // attribute id
    2,                     // size
    GL_FLOAT,              // type
    GL_FALSE,              // normalized?
    0,                     // stride
    (void *)0              // array buffer offset
);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableVertexAttribArray((GLuint) pd.uv_a);
glDisableVertexAttribArray((GLuint) pd.vertex_a);

glBindTexture(GL_TEXTURE_2D, 0);

Note:

proj matrix: 
proj = glm::ortho(-320, 320, -240, 240, -1.0f, 100.0f); // 640x480 with 0,0 at center

camera matrix:
cam_target = glm::vec3();
cam_up = glm::vec3(0.0, 1.0f, 0.0f);
cam_pos = glm::vec3(0.0f, 0.0f, 5.0f);
camera = glm::lookAt(cam_pos, cam_target, cam_up);

MVP matrix:
glm::mat4 mvp = proj * camera;
\$\endgroup\$
1
  • 1
    \$\begingroup\$ i would guess it's because opengl uses coordinate system in which y increases in the up direction \$\endgroup\$
    – Sopel
    Mar 3, 2017 at 11:27

1 Answer 1

2
\$\begingroup\$

This is because OpenGL actually expect the pixels ordered from the bottom-left.

So, when you give (0, 0) then what you meant is not the upper-left but bottom-left instead. In your case, you want it to be blue, but it shows you red instead.

Take a look at this, scroll down to number 12.

12. OpenGL's Lower Left Origin

Given a sheet of paper, people write from the top of the page to the bottom. The origin for writing text is at the upper left-hand margin of the page (at least in European languages). However, if you were to ask any decent math student to plot a few points on an X-Y graph, the origin would certainly be at the lower left-hand corner of the graph. Most 2D rendering APIs mimic writers and use a 2D coordinate system where the origin is in the upper left-hand corner of the screen or window (at least by default). On the other hand, 3D rendering APIs adopt the mathematically minded convention and assume a lower left-hand origin for their 3D coordinate systems.

. . .

Another common pitfall related to 2D rendering APIs having an upper left-hand coordinate system is that 2D image file formats start the image at the top scan line, not the bottom scan line. OpenGL assumes images start at the bottom scan line by default.

\$\endgroup\$
5
  • \$\begingroup\$ Mmmh, I used pixels from bottom-left... In glm::ortho I specified that -1 is at left, and 1 is at right with 0 at center (to replicate this: opengl-tutorial.org/assets/images/tuto-2-first-triangle/…) \$\endgroup\$
    – TesX
    Mar 3, 2017 at 11:38
  • \$\begingroup\$ @TesX That picture is to describe the screen coordinates, which would be true. But, in your case you're dealing with texture UVs which a little bit different where the coordinates only range from 0 to 1. \$\endgroup\$
    – Greffin28
    Mar 3, 2017 at 11:43
  • \$\begingroup\$ "OpenGL assumes images start at the bottom scan line by default." Ahhh, that's why... Ok thanks :) \$\endgroup\$
    – TesX
    Mar 3, 2017 at 13:35
  • \$\begingroup\$ I've flipped the texture in the fragment shader and it works :) \$\endgroup\$
    – TesX
    Mar 3, 2017 at 13:59
  • \$\begingroup\$ @TesX that's one way to do it :p glad it worked out for you \$\endgroup\$
    – Greffin28
    Mar 3, 2017 at 16:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .