Texturing using shaders

I’m trying to upgrade my code to modern OpenGL, so far I’ve successfully got a rectangular VBO drawn on the screen and was able to get it textured without shaders. But now I’m having trouble getting the texture displayed when using shaders.

As said before, I have gotten the texture to be drawn on the VBO without using shaders, so texture loading is not the issue here, I have also checked that the shaders are successfully compiled and binded to a program object, so you can rule that out too.

Here is my code, I hope this is all that is needed since I’ve done the error checking stated above however if you do, just ask.

main.c (slighlty simplified):

GLuint titleTexture;
loadTexture(binary_title_jpg_start, (size_t)binary_title_jpg_size, &titleTexture, SOIL_FLAG_COMPRESS_TO_DXT);
short titleShader = compileShaders(binary_testVertex_glsl_start, (size_t)binary_testVertex_glsl_size, binary_testFragment_glsl_start, (size_t)binary_testFragment_glsl_size);

while(1) {
	glUseProgram(titleShader);
	glEnable(GL_TEXTURE_2D);
	glActiveTexture(GL_TEXTURE0_ARB);
	int textureSampler = glGetUniformLocation(titleShader, "textureS");
	glUniform1i(textureSampler, titleTexture);
	glBindTexture(GL_TEXTURE_2D, titleTexture);
	drawVBO(&menuBackground);
	glDisable(GL_TEXTURE_2D);
	glUseProgram(0);
}

testVertex.glsl:

void main() {
	gl_TexCoord[0] = gl_MultiTexCoord0;
	gl_Position = gl_Vertex * gl_ModelViewProjectionMatrix;
}

testFragment.glsl:

uniform sampler2D textureS;

void main(void) {
	gl_FragColor = texture2D(textureS, gl_TexCoord[0].st);
}

The VBO rendered is just plain black, what’s up with that?


glUniform1i(textureSampler, titleTexture);

You are setting the sampler uniform to the id of the texture object, you should set it to the texture unit (0 in your case) you want to sample from.

Thanks for your help, now the whole rectangle is one solid color which appears to be the first color in the image; so what else is wrong? Do I need to glEnable anything else perhaps?

Hello,

sounds like your texture coordinates are wrong. Maybe seeing how they are defined would help. One additional note: If you really want to upgrade to modern OpenGL, you also want to get rid of the build-in variables gl_TexCoord, gl_MultiTexCoord0, gl_ModelViewProjectionMatrix, gl_FragColor, gl_Vertex, gl_ModelViewProjectionMatrix etc (basically everything except gl_Position). Enabling and disabling Texture_2D is also not used in modern GL anymore. As textures are not an extension anymore, I would also change GL_TEXTURE0_ARB to GL_TEXTURE0.

Thanks for your answer, I have made slight adaptations to my loopMenu function, as well as updating testVertex.glsl; my drawing code which shows how my texture coords are set up is also here.

I know it’s a lot of code so thanks again for taking the time to look through it all.

My OpenGL version is 3.1.0, so it should be high enough to do this, no?

relevant parts of draw.c and draw.h:

typedef struct {
	float s;
	float t;
} textureCoord;

typedef struct {
	float x;
	float y;
	float z;
} vertexLocation;

typedef struct {
	vertexLocation vertLo;
	textureCoord textCo;
} vertex;

typedef struct {
	GLuint VBOIndex;
	vertex *vertices;
	int vertexCount;
} VBO;

short createRectangeVBO(VBO *object, int width, int height) {
	object->vertices = NULL;
	object->vertices = malloc(4 * sizeof(vertex));
	if(object->vertices == NULL) return 0;
	
	object->vertexCount = 4;
	
	if(!generateRectangleVerts(object, width, height)) return 0;
	if(!generateRectangleTextureCoords(object)) return 0;
	storeVBO(object);
	
	return 1;
}

short generateRectangleVerts(VBO *object, int width, int height) {
	if(object->vertexCount != 4) return 0;
	
	object->vertices[0].vertLo.x = 0.0f;
	object->vertices[0].vertLo.y = 0.0f;
	object->vertices[0].vertLo.z = 0.0f;
	
	object->vertices[1].vertLo.x = width;
	object->vertices[1].vertLo.y = 0.0f;
	object->vertices[1].vertLo.z = 0.0f;
	
	object->vertices[2].vertLo.x = width;
	object->vertices[2].vertLo.y = height;
	object->vertices[2].vertLo.z = 0.0f;
	
	object->vertices[3].vertLo.x = 0.0f;
	object->vertices[3].vertLo.y = height;
	object->vertices[3].vertLo.z = 0.0f;
	
	return 1;
}

short generateRectangleTextureCoords(VBO *object) {
	object->vertices[0].textCo.s = 0;
	object->vertices[0].textCo.t = 0;
	
	object->vertices[1].textCo.s = 1;
	object->vertices[1].textCo.t = 0;
	
	object->vertices[2].textCo.s = 1;
	object->vertices[2].textCo.t = 1;
	
	object->vertices[3].textCo.s = 0;
	object->vertices[3].textCo.t = 1;
	
	return 1;
}

void storeVBO(VBO *object) {
	glGenBuffers(1, &object->VBOIndex);
	glBindBuffer(GL_ARRAY_BUFFER, object->VBOIndex);
	glBufferData(GL_ARRAY_BUFFER, object->vertexCount * sizeof(vertex), object->vertices, GL_STATIC_DRAW);
}

void drawVBO(VBO *object) {
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	
	glBindBuffer(GL_ARRAY_BUFFER, object->VBOIndex);
	glVertexPointer(3, GL_FLOAT, sizeof(vertex), NULL);
	glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (void *)(3 * sizeof(float)));
	glDrawArrays(GL_QUADS, 0, object->vertexCount);
	
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}

void freeVBO(VBO *object) {
	object->vertexCount = 0;
	free(object->vertices);
}

testVertex.glsl:

void main() {
	gl_TexCoord[0] = gl_MultiTexCoord0;
	gl_Position = gl_Vertex;
}

testFragment.glsl:

uniform sampler2D textureS;

void main(void) {
	gl_FragColor = texture2D(textureS, gl_TexCoord[0].st);
	//gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}

menu.c:

VBO menuBackground;

short titleShader = 0;

short initMenu(void) {
	if(!loadTexture(binary_title_jpg_start, (size_t)binary_title_jpg_size, &titleTexture, SOIL_FLAG_COMPRESS_TO_DXT)) {
		return 0;
	}
	if(!createRectangeVBO(&menuBackground, getWidth(), getHeight())) {
		return 0;
	}
	titleShader = compileShaders(binary_testVertex_glsl_start, (size_t)binary_testVertex_glsl_size, binary_testFragment_glsl_start, (size_t)binary_testFragment_glsl_size);
	if(!titleShader) {
		return 0;
	}
	return 1;
}

void loopMenu(void) {
	glUseProgram(titleShader);
	glActiveTexture(GL_TEXTURE0);
	int textureSampler = glGetUniformLocation(titleShader, "textureS");
	glUniform1i(textureSampler, 0);
	glBindTexture(GL_TEXTURE_2D, titleTexture);
	drawVBO(&menuBackground);
	glUseProgram(0);
}

void deinitMenu(void) {
	freeVBO(&menuBackground);
}

Your vertex coordinates are derived from integers width and height, but you’re storing them in gl_Position (which is in clip coordinates) without any transformation (the projection and model-view matrices aren’t being used). If GetWidth() and GetHeight() are returning integers much larger than 1, your quad will be much larger than the viewport, resulting in only a small portion of it being visible.

The projection and model-view matrices are available to the shader via the compatibility variables gl_ModelViewMatrix and gl_ProjectionMatrix (and their concatenation is available via gl_ModelViewProjectionMatrix), but the shader has to use them explicitly, e.g.:


    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

Thanks very much!