Home > Blockchain >  Texture mapping on cube only shows two sides correctly
Texture mapping on cube only shows two sides correctly

Time:01-11

I tried to make a cube in openGL and render a default texture on each side. I've been messing around with it for days but I cant get it to work. I really don't know what the problem is as I am convinced that my vertices and texture coordinates are right. What am I doing wrong?

These are my vertices, uv's and indices:

vertices = {
    // front face
    0.0f, 0.0f, 0.0f,
    length, 0.0f, 0.0f,
    length, height, 0.0f,
    0.0f, height, 0.0f,
    // back face
    0.0f, 0.0f, width,
    length, 0.0f, width,
    length, height, width,
    0.0f, height, width,
    // left face
    0.0f, 0.0f, 0.0f,
    0.0f, 0.0f, width,
    0.0f, height, width,
    0.0f, height, 0.0f,
    // right face
    length, 0.0f, 0.0f,
    length, 0.0f, width,
    length, height, width,
    length, height, 0.0f,
    // top face
    0.0f, height, 0.0f,
    length, height, 0.0f,
    length, height, width,
    0.0f, height, width,
    // bottom face
    0.0f, 0.0f, 0.0f,
    length, 0.0f, 0.0f,
    length, 0.0f, width,
    0.0f, 0.0f, width
};
uvs = {
    // front face
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    0.0f, 1.0f,
    // back face
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    0.0f, 1.0f,
    // left face
    0.0f, 0.0f,
    0.0f, 0.0f,
    0.0f, 1.0f,
    0.0f, 1.0f,
    // right face
    1.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    1.0f, 1.0f,
    // top face
    0.0f, 1.0f,
    1.0f, 1.0f,
    1.0f, 1.0f,
    0.0f, 1.0f,
    // bottom face
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 0.0f,
    0.0f, 0.0f
};
indices = {
    // front face
     0, 1, 2,
     2, 3, 0,
     // right face
     1, 5, 6,
     6, 2, 1,
     // back face
     7, 6, 5,
     5, 4, 7,
     // left face
     4, 0, 3,
     3, 7, 4,
     // bottom face
     4, 5, 1,
     1, 0, 4,
     // top face
     3, 2, 6,
     6, 7, 3
};

This is my render method:

void Mesh::render() {
// Render the pyramid using OpenGL
view = glm::lookAt(Camera::getInstance().cameraPos, Camera::getInstance().cameraPos   Camera::getInstance().cameraFront, Camera::getInstance().cameraUp);
mvp = projection * view * model;

// Attach to program_id
glUseProgram(programId);

// Send mvp
glUniformMatrix4fv(uniformMvp, 1, GL_FALSE, glm::value_ptr(mvp));

// Send vao
glBindVertexArray(vao);

glBindTexture(GL_TEXTURE_2D, textureId);

glDrawElements(GL_TRIANGLES, indices.size() * sizeof(GLushort),
    GL_UNSIGNED_SHORT, 0);

glBindVertexArray(0);
}

Vertexshader:

#version 430 core

in vec2 UV;
uniform sampler2D texsampler;

layout(location = 0) out vec4 gl_FragColor;

void main()
{
// Compute the diffuse and specular components for each fragment
vec3 test = texture2D(texsampler, UV).rgb;

// Write final color to the framebuffer
gl_FragColor = vec4(test, 1.0);
}

and the fragmentshader:

#version 430 core

// Uniform matrices
uniform mat4 mv;
uniform mat4 projection;

// Per-vertex inputs
in vec3 position;

// UV
in vec2 uv;
out vec2 UV;

void main()
{
// Calculate view-space coordinate
vec4 P = mv * vec4(position, 1.0);

// Calculate the clip-space position of each vertex
gl_Position = projection * P;

UV = uv;
}

Image of the cube:

Image of the cube

I think this is enough information. Only the front and the back are textured normally and the rest is just like on the image.

CodePudding user response:

Looking at OPs vertices, I noticed that there are 24 of them although a cube has 8 corners only. That's not surprising as coordinates for the same corner may correspond to distinct vertex coordinates depending on which face it belongs to.

Hence, it makes sense to define coordinates and corresponding texture coordinates per face, i.e. 6 faces with 4 corners each face -> 24 coordinates.

I enriched OPs code with enumeration:

vertices = {
    // front face
    0.0f, 0.0f, 0.0f,      //  0
    length, 0.0f, 0.0f,    //  1
    length, height, 0.0f,  //  2
    0.0f, height, 0.0f,    //  3
    // back face
    0.0f, 0.0f, width,     //  4
    length, 0.0f, width,   //  5
    length, height, width, //  6
    0.0f, height, width,   //  7
    // left face
    0.0f, 0.0f, 0.0f,      //  8
    0.0f, 0.0f, width,     //  9
    0.0f, height, width,   // 10
    0.0f, height, 0.0f,    // 11
    // right face
    length, 0.0f, 0.0f,    // 12
    length, 0.0f, width,   // 13
    length, height, width, // 14
    length, height, 0.0f,  // 15
    // top face
    0.0f, height, 0.0f,    // 16
    length, height, 0.0f,  // 17
    length, height, width, // 18
    0.0f, height, width,   // 29
    // bottom face
    0.0f, 0.0f, 0.0f,      // 20
    length, 0.0f, 0.0f,    // 21
    length, 0.0f, width,   // 22
    0.0f, 0.0f, width      // 23
};
uvs = {
    // front face
    0.0f, 0.0f,    //  0
    1.0f, 0.0f,    //  1
    1.0f, 1.0f,    //  2
    0.0f, 1.0f,    //  3
    // back face  
    0.0f, 0.0f,    //  4
    1.0f, 0.0f,    //  5
    1.0f, 1.0f,    //  6
    0.0f, 1.0f,    //  7
    // left face  
    0.0f, 0.0f,    //  8
    0.0f, 0.0f,    //  9
    0.0f, 1.0f,    // 10
    0.0f, 1.0f,    // 11
    // right face 
    1.0f, 0.0f,    // 12
    1.0f, 0.0f,    // 13
    1.0f, 1.0f,    // 14
    1.0f, 1.0f,    // 15
    // top face   
    0.0f, 1.0f,    // 16
    1.0f, 1.0f,    // 17
    1.0f, 1.0f,    // 18
    0.0f, 1.0f,    // 29
    // bottom face
    0.0f, 0.0f,    // 20
    1.0f, 0.0f,    // 21
    1.0f, 0.0f,    // 22
    0.0f, 0.0f     // 23
};

But then I took a closer look what the indices look-up:

indices = {
  // ...
  // right face
  1, 5, 6, // -> UV: { 1.0f, 0.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f }
  6, 2, 1, // -> UV: { 1.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }
  // ...
}

There are only two distinct values of texture coordinates but there should be four of them. Hence, it's not a surprise if the texture projection of that right face looks strange.

OP noted the wrong indices. This doesn't manifest in the geometry as the wrong indices address coordinates (vertices) with identical values. However, concerning the texture coordinates (uvs) these indices are just wrong.

According to the added index values, I corrected the indices for the right face:

indices = {
  // ...
  // right face
  12, 13, 14,
  14, 15, 12,
  // ...
}

The indices of the top face are defined correctly but the other faces have to be checked as well. (I leave this as "homework" to OP. Or, like a colleague of mine used to say: Not to punish just to practice.) ;-)


On the second glance, I realized that OP's texture coordinates are wrong as well.

To understand how texture coordinates work:
There is a uv coordinate system applied to the image with

  • (0, 0) … the lower left corner
  • (1, 0) … the lower right corner
  • (0, 1) … the upper left corner

of the image.

texture coordinates
taken from enter image description here

  • Related