copenglglslstb-image

Texture stretching over sides of cube but not on front and back sides


My cube:

#define _CRT_SECURE_NO_WARNINGS
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include "stb/stb_image.h"
#include <cglm/cglm.h>

typedef struct WindowData {
    GLFWwindow* window;
    int status;
} WindowData;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
unsigned int setUpShader(const char* vertSource, const char* fragSource);
WindowData buildWindow();
unsigned int setUpTexture();

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

//shaders
const char* vertexShaderSource3 = "#version 330 core\n" // vert // projection shader
                                  "layout(location = 0) in vec3 aPos;\n"
                                  "layout (location = 1) in vec3 aColor;\n"
                                  "layout(location = 2) in vec2 aTexCoord;\n"
                                  "out vec3 vertexColor;\n"
                                  "out vec2 TexCoord;\n"
                                  "out vec3 vertexPos;\n"
                                  "uniform mat4 model;\n"
                                  "uniform mat4 view;\n"
                                  "uniform mat4 projection;\n"
                                  "void main()\n"
                                  "{\n"
                                  "   vertexColor = aColor; \n"
                                  "   vertexPos = aPos;\n"
                                  "   gl_Position = projection * view * model * vec4(aPos, 1.0);\n"
                                  "   TexCoord = aTexCoord;\n"
                                  "}\n";

const char* fragmentShaderSource4 = "#version 330 core\n" //frag // texture RGB shader
                                    "out vec4 FragColor;\n"
                                    "in vec3 vertexColor;\n"
                                    "in vec2 TexCoord;\n"
                                    "uniform sampler2D ourTexture;\n"
                                    "void main()\n"
                                    "{\n"
                                    "   FragColor = texture(ourTexture, TexCoord) * vec4(vertexColor, 1.0);\n"
                                    "}\n\0";

int main(int argc, char* argv[])
{
    // SETUP WINDOW
    WindowData windowBuildResult = buildWindow();

    if(windowBuildResult.status == -1) {
        return -1;
    }

    GLFWwindow* window = windowBuildResult.window;

    // GLAD: LOAD ALL OpenGL FUNCTION POINTERS
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        printf("Failed to initialize GLAD\n");
        return -1;
    }

    // SET UP SHADERS AND TEXTURES
   unsigned int modelShader = setUpShader(vertexShaderSource3, fragmentShaderSource4);

   glEnable(GL_DEPTH_TEST);

   // SET UP VERTEX DATA AND VBOs/VAOs/EBO
   float cube1verts[] = {
       //---position---// //----color----// // texture coordinates
       0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 0 
       0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 1 
      -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 2 
      -0.5f,  0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 3 

      -0.5f, -0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 4
       0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 5
       0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 6
      -0.5f,  0.5f,  0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 7

      -0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 7
      -0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 3
      -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 2
      -0.5f, -0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 4

       0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 6
       0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 0
       0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 1
       0.5f, -0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 5

      -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 2
       0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 1
       0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 5
      -0.5f, -0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 4

      -0.5f,  0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 3
       0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 0
       0.5f,  0.5f,  0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 6
      -0.5f,  0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 7
   };

    unsigned int indices[] = {
        0, 1, 3, // 1st triangle
        1, 2, 3, // 2nd triangle

        4, 5, 6, // 3rd triangle
        6, 7, 4, // 4th triangle

        7, 3, 2, // 5th triangle
        2, 4, 7, // 6th triangle

        6, 0, 1, // 7th triangle
        1, 5, 6, // 8th triangle

        2, 1, 5, // 9th triangle
        5, 4, 2, // 10th triangle

        3, 0, 6, // 11th triangle
        6, 7, 3, // 12th triangle
    };

    unsigned int VBOs[1], VAOs[1], EBOs[1];
    glGenVertexArrays(1, VAOs);
    glGenBuffers(1, VBOs);
    glGenBuffers(1, EBOs);

    // SETUP TEXTURES
    unsigned int texture = setUpTexture();
    

    // SETUP RENDERING
    // CUBE
    glBindVertexArray(VAOs[0]);
    glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cube1verts), quad2verts, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[0]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // RENDER LOOP
    while (!glfwWindowShouldClose(window))
    {
        processInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // DRAW TEXTURED CUBE IN PERSPECTIVE
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[0]);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);

        glUseProgram(modelShader);

        mat4 model = GLM_MAT4_IDENTITY_INIT;
        mat4 view = GLM_MAT4_IDENTITY_INIT;
        mat4 projection = GLM_MAT4_IDENTITY_INIT;
        glm_rotate(model, (float)glfwGetTime(), (vec3){ 0.5f, 1.0f, 0.0f });
        glm_translate(view, (vec3){0.0f, 0.0f, -3.0f});
        glm_perspective(glm_rad(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f, projection);

        unsigned int modelLoc = glGetUniformLocation(modelShader, "model");
        unsigned int viewLoc = glGetUniformLocation(modelShader, "view");
        unsigned int projectionLoc = glGetUniformLocation(modelShader, "projection");
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, (const GLfloat*) model);
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, (const GLfloat*) view);
        glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, (const GLfloat*) projection);

        glBindVertexArray(VAOs[0]);
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);

        // SWAP BUFFERS AND CHECK FOR USER INPUTS
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // DE-ALLOCATE RESOURCES
    glDeleteVertexArrays(1, VAOs);
    glDeleteBuffers(1, VBOs);
    glDeleteBuffers(1, EBOs);
    glDeleteProgram(modelShader);

    // CLEAR ALL RESOURCES AND STOP OpenGL
    glfwTerminate();
    return 0;
}

// CHANGE WINDOW SIZE AND VIEWPORT
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow* window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, 1);
    }
}

unsigned int setUpShader(const char* vertSource, const char* fragSource) {
    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertSource, NULL);
    glCompileShader(vertexShader);

    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
    }

    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragSource, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
    }

    unsigned int shaderProgram;
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        printf("ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return shaderProgram;
}

WindowData buildWindow() {

    // INIT GLFW
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // CHANGE SETTINGS BASED ON OS
#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    // BUILD WINDOW
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    WindowData windowData = { window, 0 };
    if (window == NULL)
    {
        printf("Failed to create GLFW window\n");
        glfwTerminate();
        windowData.status = -1;
        return windowData;
    }

    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    return windowData;
}

unsigned int setUpTexture(){
    unsigned int texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(1);
    unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
    if (data) {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else {
        printf("ERROR::TEXTURE::LOAD::FAILED\n");
    }
    stbi_image_free(data);
    return texture;
}

...doesn't render the texture correctly on all sides, only on the front facing side and back facing side, but the left/right/top/bottom sides have the textures stretched:

This is what my cube looks like currently

I've tried changing the texture setup properties from GL_LINEAR to GL_REPEAT to no luck. I've changed the texture coordinates hoping that might fix it, but also no luck. I'm pretty sure I have the EBO setup properly but I could be wrong.

I am using version 3.3 of OpenGL.

The only two things I can think of that might be an issue are:


Solution

  • indices was not properly set up. The new indices array looks like this:

        unsigned int indices[] = {
            //front face
             0,  1,  3, // 1st triangle
             1,  2,  3, // 2nd triangle
    
            //back face
             4,  5,  6, // 3rd triangle
             6,  7,  4, // 4th triangle
    
            //left face
             8,  9, 11, // 5th triangle
             9, 10, 11, // 6th triangle
    
            //right face
            12, 13, 15, // 7th triangle
            13, 14, 15, // 8th triangle
    
            //bottom face
            16, 17, 19, // 9th triangle
            17, 18, 19, // 10th triangle
    
            //top face
            20, 21, 23, // 11th triangle
            21, 22, 23, // 12th triangle
        };
    

    When properly setting up how you want the cube to render, make sure that you are using the index of a specific set of vertex data and not just a vertex order. Make sure you are also putting the indexes in the correct order or else the triangles will be drawn incorrectly. This is not explicitly mentioned in the learnopengl.com tutorials when it goes over EBOs so be aware of it.