1

I am trying to render a texture with OpenGL. The texture I am using as a test is a bunch of black rectangles on a white background, as follows:

Some black rectangles on a white background

However, when rendering, the texture seem to be duplicated and overlayed multiple times on top of itself:

A rendered frame with a distorted version of the texture

I set the scene up using:

std::string vertexSource = ShaderLoader::load("vertexSource.vert");
const char* vsource = vertexSource.c_str();
std::string fragmentSource = ShaderLoader::load("fragmentSource.frag");
const char* fsource = fragmentSource.c_str();

int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vsource, NULL);
glCompileShader(vertexShader);
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fsource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

float vertices[] = {
            0.5f,  0.5f, 0.0f,
            0.5f, -0.5f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            -0.5f,  0.5f, 0.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 0.0f,
            0.0f, 1.0f,
};
unsigned int indices[] = {
            0, 1, 3,
            1, 2, 3
};

glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1,2,GL_FLOAT, GL_FALSE, 2* sizeof(float), (void*)(sizeof(float)*12));
glEnableVertexAttribArray(1);

glBindBuffer(GL_ARRAY_BUFFER, 0);

glBindVertexArray(0);

unsigned char* data = stbi_load("image.png", &width, &height,&nrOfChannels, 0);
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free((void *) data);

My render code is:

glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, textureId);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

My vertex shader is:

#version 330 core
layout (location = 0) in vec3 inVertex;
layout (location = 1) in vec2 inTexture;

out vec2 TextureCoordinate;

void main()
{
    gl_Position = vec4( inVertex, 1 );
    TextureCoordinate = inTexture;
}

and my fragment shader is:

#version 330 core
out vec4 FragColor;

in vec2 TextureCoordinate;

uniform sampler2D Texture;

void main() {
    FragColor = texture(Texture,TextureCoordinate);
}
1
  • 1
    Are you sure that the image has 3 channels (RGB), not 4 (RGBA)? Commented Jan 17, 2021 at 9:30

1 Answer 1

4

When an image with 3 channels (GL_RGB) is loaded to a texture object, GL_UNPACK_ALIGNMENT needs to be set to 1. By default GL_UNPACK_ALIGNMENT is 4, so each line of an image is assumed to be aligned to 4 bytes. The pixels in the buffer have a size of 3 bytes and are tightly packed, this would cause a misalignment.

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // default

Since the image format is PNG, it is very likely that the image has 4 channels (GL_RGBA). Evaluate nrOfChannels before specifying the texture image:

unsigned char* data = stbi_load("image.png", &width, &height, &nrOfChannels, 0);
// [...]

unsigned int format = nrOfChannels == 4 ? GL_RGBA : GL_RGB; 
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);

It is also possible to force stbi_load to generate an image with 4 channels, by explicitly pass 4 to the last parameter:

int reqChannels= 4; 
unsigned char* data = stbi_load("image.png", &width, &height, &nrOfChannels, reqChannels);
// [...]

glTexImage2D(GL_TEXTURE_2D, GL_RGBA, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
Sign up to request clarification or add additional context in comments.

Comments

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.