0
\$\begingroup\$

I am trying to render a 3D cube, and apply a single texture to all the faces of the cube. I feel like I am missing something critical here as it is applying to the front and back faces of the cube, but 'stretching' it across the other faces.

Example:

Cube with correct front face texture but stretched texture on the sides, top and bottom

Object is created via:

void Engine::CreateObjects()
{
    std::vector<unsigned int> indices;
    indices.push_back(0);
    indices.push_back(1);
    indices.push_back(2);
    indices.push_back(2);
    indices.push_back(3);
    indices.push_back(0);
    indices.push_back(1);
    indices.push_back(5);
    indices.push_back(6);
    indices.push_back(6);
    indices.push_back(2);
    indices.push_back(1);
    indices.push_back(7);
    indices.push_back(6);
    indices.push_back(5);
    indices.push_back(5);
    indices.push_back(4);
    indices.push_back(7);
    indices.push_back(4);
    indices.push_back(0);
    indices.push_back(3);
    indices.push_back(3);
    indices.push_back(7);
    indices.push_back(4);
    indices.push_back(4);
    indices.push_back(5);
    indices.push_back(1);
    indices.push_back(1);
    indices.push_back(0);
    indices.push_back(4);
    indices.push_back(3);
    indices.push_back(2);
    indices.push_back(6);
    indices.push_back(6);
    indices.push_back(7);
    indices.push_back(3);

    std::vector<Vertex> vertices;

    //                                   xPos   yPos   zPos             xTex    yTes                                        
    vertices.push_back(Vertex(glm::vec3(-1.0f, -1.0f, 1.0f), glm::vec2(1.0f, 1.0f)));
    vertices.push_back(Vertex(glm::vec3(1.0, -1.0, 1.0), glm::vec2(1.0f, 0.0f)));
    vertices.push_back(Vertex(glm::vec3(1.0, 1.0, 1.0), glm::vec2(0.0f, 0.0f)));
    vertices.push_back(Vertex(glm::vec3(-1.0, 1.0, 1.0), glm::vec2(0.0f, 1.0f)));

    vertices.push_back(Vertex(glm::vec3(-1.0, -1.0, -1.0), glm::vec2(1.0f, 1.0f)));
    vertices.push_back(Vertex(glm::vec3(1.0, -1.0, -1.0), glm::vec2(1.0f, 0.0f)));
    vertices.push_back(Vertex(glm::vec3(1.0, 1.0, -1.0), glm::vec2(0.0f, 0.0f)));
    vertices.push_back(Vertex(glm::vec3(-1.0, 1.0, -1.0), glm::vec2(0.0f, 1.0f)));

    std::vector<Texture> textures;
    Texture texture = Texture("src/Textures/wall.jpg");
    textures.push_back(texture);

    Mesh* obj1 = new Mesh(vertices, indices, textures);
    meshList.push_back(obj1);
}

Vertex Struct:

#pragma once

#include <glm/glm.hpp>

struct Vertex
{
    Vertex(glm::vec3 position, glm::vec2 texCoords) : Position(position), TexCoords(texCoords) {};

    glm::vec3 Position;
    glm::vec2 TexCoords;
};

Texture Struct:

#pragma once

#include "External/stb_image.h"
#include <string>
#include <iostream>

struct Texture
{
    Texture(std::string path) : Id(0), Type(""), Path(path), Width(0), Height(0), nrChannels(0)
    {
        LoadTexture();
    }

    unsigned int Id;
    int Width;
    int Height;
    int nrChannels;
    std::string Type;
    std::string Path;

private:
    void LoadTexture()
    {
        glGenTextures(1, &Id);
        glBindTexture(GL_TEXTURE_2D, Id);

        // Wrapping
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

        // Filtering
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        stbi_set_flip_vertically_on_load(true);
        unsigned char* data = stbi_load(Path.c_str(), &Width, &Height, &nrChannels, 0);

        if (!data)
        {
            std::cout << "Failed to load texture " << this->Path << std::endl;
        }

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, Width, Height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, 0);

        stbi_image_free(data);
    }
};

And the actual drawing of the Mesh is done via these two functions (Draw, Setup):

void Mesh::Draw(Shader shader)
{
    glBindTexture(GL_TEXTURE_2D, textures[0].Id);
    glActiveTexture(GL_TEXTURE0);
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
}

void Mesh::SetupMesh()
{
    glGenVertexArrays(1, &this->VAO);
    glGenBuffers(1, &this->VBO);
    glGenBuffers(1, &this->EBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    auto size = vertices.size() * sizeof(Vertex);
    glBufferData(GL_ARRAY_BUFFER,size, &vertices[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);

    // vertex Positions
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    // vertex texture coords
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));

    glBindVertexArray(0);
}

I understand this code is not ideal and am extremely open to different ways of constructing this cube, especially when it comes to listing the indices, but the primary issue is the texture stretching.

To me, it seems like the program is doing exactly what i'm telling it to do, however, I seem to have a knowledge gap on where to go from here to have the texture apply across the entire cube.

\$\endgroup\$
2
\$\begingroup\$

So the problem you've got is that you have 8 vertices total and re-use them for the different faces. With the way you specify the UV's for the vertices, the faces that look stretched actually have the same UV values for two of the corners on either side of the face.

I think you're best option is to have 4 unique vertices for each face if you plan to try and have the whole texture on each face. If/when you want normals for the faces you'll need to have different vertices for the faces anyway.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.