3

I am using MS visual studio 2019 and just learning opengl in c++. I started learning from https://learnopengl.com and it showed many ways to load textures . I just used stb image for loading textures and here's the function for loading a texture :

 
static unsigned int loadTexture(char const* path)
{
    unsigned int textureID;
    glGenTextures(1, &textureID);

    int width, height, nrComponents;
    unsigned char* data = stbi_load(path, &width, &height, &nrComponents, 0);
    if (data)
    {
        GLenum format;
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, textureID);
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

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

        stbi_image_free(data);
    }
    else
    {
        std::cout << "Texture failed to load at path: " << path << std::endl;
        stbi_image_free(data);
    }

    return textureID;
}

I tried loading it in a rectangle but somehow it doesn't seem to print properly on it. I'm stuck for a couple of hours and still couldn't find what mistake I've made. here's the code for initializing the VAO and VBO:

    inline void InitTextureBuffer(const char* img_filepath)
    {
        texture_shader.Bind();
        tex_img_id = loadTexture(img_filepath);
        glGenVertexArrays(1, &tex_VAO);
        glGenBuffers(1, &tex_VBO);
        glBindVertexArray(tex_VAO);
        glBindBuffer(GL_ARRAY_BUFFER, tex_VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
        texture_shader.Unbind();
    }

and function to draw the rect :

    inline void Draw_Rectangle_IMG(_Point _min, _Point _max)
    {
        glActiveTexture(GL_TEXTURE0);
        glBindVertexArray(tex_VAO);
        texture_shader.Bind();
        float vertices[] =
        {
             _min.x, _min.y,   0.0f, 0.0f ,
             _max.x, _min.y,   0.0f, 1.0f ,
             _max.x, _max.y,   1.0f, 1.0f ,

             _min.x, _min.y,   0.0f, 0.0f ,
             _max.x, _max.y,   1.0f, 1.0f ,
             _min.x, _max.y,   1.0f, 0.0f ,
        };
        glBindTexture(GL_TEXTURE_2D, tex_img_id);

        glBindBuffer(GL_ARRAY_BUFFER, tex_VBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glDrawArrays(GL_TRIANGLES, 0, 6);

        glBindVertexArray(0);
        glBindTexture(GL_TEXTURE_2D, 0);
        texture_shader.Unbind();
    }

the shaders I've used:

const std::string texture_shader_vs =
{
    "#version 330 core\n"
    "layout(location = 0) in vec2 aPos;\n"
    "layout(location = 1) in vec2 aTexCoord;\n"
    "\n"
    "out vec2 TexCoord;\n"
    "\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos,0.0f, 1.0f);\n"
    "   TexCoord = aTexCoord;\n"
    "}\n"
};
const std::string texture_shader_fs =
{
    "#version 330 core\n"
    "out vec4 FragColor;\n"
    "\n"
    "in vec2 TexCoord;\n"
    "\n"
    "// texture sampler\n"
    "uniform sampler2D texture1;\n"
    "\n"
    "void main()\n"
    "{\n"
    "   FragColor = texture(texture1, TexCoord);\n"
    "}\n"
};

And the function where I did the calls:

    _Point p1, p2;
    p1 = _Point(-0.5f, -0.25f);
    p2 = _Point(0.5f, 0.25f);

    ogl.InitTextureBuffer("resources/textures/1.png");
    while (!glfwWindowShouldClose(ogl.GetWindow()))
    {
        glClear(GL_COLOR_BUFFER_BIT);

        ogl.Draw_Rectangle_IMG(p1, p2);

        glfwSwapBuffers(ogl.GetWindow());
        glfwPollEvents();
    }

The texture i tried to print is :

this

but the result I get is

this

I can't seem to find the error .Any help would be appreciated. Thanks!

2
  • @AlexF I tried changing vertices and it resulted in an access violation error in glGenerateMipmap(GL_TEXTURE_2D); Commented Jun 16, 2021 at 7:27
  • I would assume that the alignment of the image rows doesn't match the alignment of the texture image. I know that certain image file formats (like e.g. BMP) requires row alignment to multiples of 4. FYI: Texture upload and pixel reads Commented Jun 16, 2021 at 7:38

1 Answer 1

4

The association of the texture coordinates to the vertices is wrong. Change to:

float vertices[] =
{
    _min.x, _min.y,   0.0f, 1.0f,
    _max.x, _min.y,   1.0f, 1.0f,
    _max.x, _max.y,   1.0f, 0.0f,

    _min.x, _min.y,   0.0f, 1.0f,
    _max.x, _max.y,   1.0f, 0.0f,
    _min.x, _max.y,   0.0f, 0.0f,
};

By default OpenGL assumes that the start of each row of an image is aligned to 4 bytes.
This is because the GL_UNPACK_ALIGNMENT parameter by default is 4. When a RGB image with 3 color channels is loaded to a texture object and 3*width is not divisible by 4 this may cause a misalignment.

Change the alignment by setting the GL_UNPACK_ALIGNMENT to 1, before specifying the texture image with glTexImage2D:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);

When you remove glGenerateMipmap(GL_TEXTURE_2D);, then you have to change the minifying function (GL_TEXTURE_MIN_FILTER) as well. Since the filter is GL_LINEAR_MIPMAP_LINEAR, the texture would be "Mipmap Incomplete" if you do not change the minimize function to GL_NEAREST or GL_LINEAR.

Sign up to request clarification or add additional context in comments.

1 Comment

@ShreeyashShrestha Do exactly what I've done in the answer. Use the texture coordinates (which I've changed right now) and glPixelStorei(GL_UNPACK_ALIGNMENT, 1);. (but change nothing else). I've tested the code and it works now fine for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.