Maxthecat Maxthecat - 2 months ago 12
C++ Question

Why am I failing to display a texture in OpenGL?

I'm trying to load a texture in OpenGL, but all I get is black. I've verified that the shaders are returning GL_TRUE when they compile. So, I don't think that is the issue...

Some things to note:

I have taken and modified code from https://open.gl/content/code/c3_multitexture.txt. This was a tutorial from https://open.gl/textures

The texture I am trying to load is from a 640 x 400 PGM file. You can assume the loader pgmImage correctly loads the file (I have verified it in GDB). PGM is 8-bit B&W data. Here I am trying to just use it as the red channel, although I'd like to be able to eventually display it as B&W, too.

Where am I going wrong?

Thanks!

Code compiled with: -lglut -lGLU -lGL -lm -lGLEW flags in g++ (some aren't necessary, I know).

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>

// Include GLEW
#include <GL/glew.h>

//Glut
#include <GL/glut.h>

#include "shader.hpp"
#include "PGM.hpp"

GLuint programID;
GLuint output_image;

// Shader sources
const GLchar* vertexSource =
"#version 450 core\n"
"in vec2 position;"
"in vec2 texcoord;"
"out vec2 Texcoord;"
"void main()"
"{"
" Texcoord = texcoord;"
" gl_Position = vec4(position, 0.0, 1.0);"
"}";
const GLchar* fragmentSource =
"#version 450 core\n"
"in vec2 Texcoord;"
"out vec4 outColor;"
"uniform sampler2D texData;"
"void main()"
"{"
" outColor = texture(texData, Texcoord);"
"}";



void display()
{

glClearColor(0.0f, 0.0f, 1.0f, 0.0f);

glClear(GL_COLOR_BUFFER_BIT);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

glFlush();
glutSwapBuffers();

}


void reshape(int width,int height)
{
double w2h = (height>0) ? (double)width/height : 1;
// Set viewport as entire window
glViewport(0,0, width,height);

}



int main(int argc, char** argv)
{
// Image setup

PGM pgmImage;
pgmImage.ReadFile("test.pgm");

// Window Setup

glutInitWindowSize(640, 400);
glutInitWindowPosition (140, 140);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInit(&argc, argv);

glutCreateWindow( "OpenGL Application" );
glutDisplayFunc(display);
glutReshapeFunc(reshape);

glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}

// Vertices & texture init

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

GLuint vbo;
glGenBuffers(1, &vbo);

GLfloat vertices[] = {
// X Y S T
-0.5f, 0.5f, 0.0f, 0.0f, // Top-left
0.5f, 0.5f, 1.0f, 0.0f, // Top-right
0.5f, -0.5f, 1.0f, 1.0f, // Bottom-right
-0.5f, -0.5f, 0.0f, 1.0f // Bottom-left
};

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

GLuint ebo;
glGenBuffers(1, &ebo);

GLuint elements[] = {
0, 1, 2,
2, 3, 0
};

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

// Create shaders

GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);


GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);

GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);

// Vertex data specification
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);

GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)(2 * sizeof(GLfloat)));

// Load Textures

//TODO: don't really need 2 textures, but just following along with example source code for now...
GLuint textures[2];
unsigned char* image;

int width, height;

width = pgmImage.GetWidth();
height = pgmImage.GetHeight();
image = (unsigned char *)pgmImage.GetData();

glGenTextures(2, textures);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, image);


glUniform1i(glGetUniformLocation(shaderProgram, "texData"), 0);

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

// Start program

glutMainLoop();

// Teardown

glDeleteTextures(2, textures);

glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);

glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);

glDeleteVertexArrays(1, &vao);

return 0;
}

Answer

As you had already found, the internalFormat and format of your glTexImage2D() call are incompatible:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, image);

GL_RED_INTEGER is for integer texture types. For 1-component texture data with normalized textures, the correct format is GL_RED:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, image);

For new code, I would always recommend to use sized internal types, even though unsized internal types like GL_RGB are still valid for backwards compatibility. So for a normalized texture with 3 8-bit components:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, image);

Your attempt at using GL_R8UI as the internal format failed because using integer textures requires additional changes, particularly in the shader code, where you would need to use usampler2D as the sampler type, and deal with getting integer values when you sample the textures. But in your case, that's not really what you wanted in the first place.

Comments