Struggling with textures in openGL

Started by
6 comments, last by CrazyCdn 6 years, 11 months ago

Hi,

I am trying to define my own texture but struggling to get even a simple test to work. I have been hitting my head against the wall all day unable to move past this issue (I am sure you remember the feeling) so any help would be gratefully appreciated.

-> I am just seeing a black box where the texture colour should be (in this simple test I am just expecting a white box in the middle of the screen)

->There is no error from glGetError() and the shader compiles and links without giving an error.

->In the fragment shader if I comment out the texture line and instead just return a vec4 then it will display a solid colour with no problem

I have posted the essential elements of the code below. Can anyone spot what I am missing?


//Position vertices and texture coordinates for a box
GLfloat screen2DVertices[] = 
{ //x, y, z                    //u, v
-0.8f, -0.8f, 0.0f,        0.0f, 0.0f, // bottom left corner
-0.8f,  0.8f, 0.0f,        0.0f, 1.0f, // top left corner
0.8f,  0.8f, 0.0f,         1.0f, 1.0f, // top right corner
0.8f, -0.8f, 0.0f,         1.0f, 0.0f, // bottom right corner
};

GLushort screen2DIndices[] = 
{ 
0,1,2, // first triangle (bottom left - top left - top right)
0,2,3  // second triangle (bottom left - top right - bottom right)
};

//Texture width in pixels
const int TEXTURE_WIDTH = 32;
const int TEXTURE_HEIGHT = 32;

//3 RGB values per pixel
float texturePixels[TEXTURE_WIDTH * TEXTURE_HEIGHT * 3];

//Test with all white r = g = b = 1.0f
for (int i = 0; i < TEXTURE_WIDTH * TEXTURE_HEIGHT * 3; i++)
{
texturePixels[i] = 1.0f;
}

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);


// Load texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, GL_RGB, GL_FLOAT, texturePixels);

GLuint vbo;
glGenBuffers(1, &vbo);

// Create an element array
GLuint ebo;
glGenBuffers(1, &ebo);

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(screen2DVertices), screen2DVertices, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(screen2DIndices), screen2DIndices, GL_STATIC_DRAW);


// Specify the layout of the vertex data
GLint posAttrib = glGetAttribLocation(screenShader.Program, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);

GLint texAttrib = glGetAttribLocation(screenShader.Program, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));

while (!glfwWindowShouldClose(window))
{
glfwPollEvents();

glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

screenShader.Use();
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)0);

glfwSwapBuffers(window);
}

Shaders:



//---------------------------Vertex Shader------------------------------------------
#version 330 core

in vec3 position;
in vec2 texcoord;

out vec2 Texcoord;

void main()
{
Texcoord = texcoord;
gl_Position = vec4(position, 1.0);
}

//---------------------------Fragment Shader------------------------------------------
#version 330 core

in vec2 Texcoord;
out vec4 outColour;
uniform sampler2D tex;

void main()
{
outColour = texture(tex, Texcoord) * vec4(1.0f);
}
Advertisement

The glDrawElements calls are in no way related to texture as one can draw untextured primitives. However, I am not seeing in the code you posted, how you are notifying the fragment shader as to which texture unit, the sampler's texture is in. Hate to be sarcastic here, but it does not magically appear in the shader because you created one and bind it. Usually, you use glUniform1i, specify the attribute location ( of the sampler ) retrieved from the compile program or specified in the shader along with the texture/sampler unit the texture was bound to.

Few hints:

If the rendering is all black, that generally means that the texture has not been correctly created or used (does glIsTexture gives the right result ?)

If the rendering has some color which looks like a color from the image (some kind of red if the image is redish for example), then the issue is most certainly related to texture coordinates.

Also try to change the underlying type the texture uses. Use GL_UNSIGNED_BYTE for start. Try also to use a different internal format. GL_RGB8 would do the thing.

Also a very common gotcha for this is mipmaps. If you upload the texture but don't create mipmaps, and it samples from the blank mipmaps you just get black.

Thank you all so much for the suggestions, it is REALLY appreciated! lawnjelly you are my saviour, I added mipmaps and immediately got a white square (they were not part of the tutorial that I was using as a reference so I didn't realise they were so important). cgrant I thought that you had found the problem but strangely it works even without sending the uniform location, not sure why.

Thanks again to everyone!

You want to make sure the first time you bind a texture at creation that you setup the glTexParameter calls that describe your sampling types for minification and magnification such as anisotropic filtering or simple point sampling.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

Also changing the value of glClearColor to anything but black lets you know if there is any rendering direction ahead of you at least.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This topic is closed to new replies.

Advertisement