PDA

View Full Version : Basic texturing w/ core (GLSL) problem



ElFuego
04-28-2011, 11:48 AM
Hi! I need to port some deprecated code to Core and I have troubles with texturing. I simply can't find a good tutorial for texturing with GLSL (tried the NeHe, Oranges, Superbible...).

I have a 2D puzzle-like image that consists of a few dozen quadratic tiles that should be textured. Think of it as a chessboard, or a quad 2D mesh. Following some examples I found, I've managed to get the things working for a single triangle, but I cannot port the solution to the 'real thing'. Can anyone point me in the right direction, either in form of a tutorial or at least with a hint at what am I missing?
Thanks!

The code looks like this -

Vertex is a simple structure, the coordinates and indexes of the mesh are 100% ok.


typedef struct
{
GLfloat loc[2]; //2 coordinates are enough for 2D
GLfloat tex[2];//same here
} Vertex;

The whole thing works correctly without shaders in this way:

In the pre-loop function setupRC() :


glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numberOfVertices, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * numberOfVertices, myVertices);

glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(8));
glVertexPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));

glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numberOfIndexes * sizeof(GLushort), myIndexes, GL_STATIC_DRAW);

and then in the paintGL:


glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, myTextureId );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);

glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(8));
glVertexPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));

glDrawElements(GL_TRIANGLES, numberOfIndexes, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

glDisable( GL_TEXTURE_2D );


However, if I use the vertex array object and shaders instead like this: (setupRC function):


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


glGenBuffers(2, bufferObjects); //2 buffers, vertex + texture interleaved and indexes
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[0]);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numberOfVertices, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * numberOfVertices, myVertices);

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(8));

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort)*numberOfIndexes, myIndexes, GL_STATIC_DRAW);


glBindVertexArray(0);

myShader = loadShaderWithAttribs( 2, 0, "vVertex", 1, "vTexCoords"); //2 attributes, in index 0 comes 'vVertex' and in index 1 'vTexCoords'


with the shaders and the loadShaderWithAttribs function defined as:


GLuint loadShaderWithAttribs(int nAttribs, ...)
{
GLuint vs;
GLuint fs;
GLuint shader = 0;

//Vertex shader:
static std::string source_vs =
"#version 330\n"
"in vec4 vVertex;\n"
"in vec2 vTexCoords;\n"
"smooth out vec2 vVaryingTexCoords;\n"
"void main(void) \n"
" { \n"
" vVaryingTexCoords = vTexCoords;\n"
" gl_Position = vVertex;\n"
" }\0";

//Fragment shader:
static std::string source_fs =
"#version 330\n"
"uniform sampler2D colorMap;\n"
"out vec4 vFragColor;\n"
"smooth in vec2 vVaryingTexCoords;\n"
"void main(void)\n"
" { \n"
" vFragColor = texture(colorMap, vVaryingTexCoords.st);\n"
" }\0";

const char * vsSource = source_vs.c_str();
const char * fsSource = source_fs.c_str();

vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vsSource, NULL);
glCompileShader(vs);

fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fsSource, NULL);
glCompileShader(fs);

shader = glCreateProgram();
glAttachShader(shader, vs);
glAttachShader(shader, fs);

//Binding the attributes...
va_list attributeList;
va_start(attributeList, nAttribs);

char *nextArg;
int iArgCount = va_arg(attributeList, int);
for(int i = 0; i < iArgCount; i++)
{
int index = va_arg(attributeList, int);
nextArg = va_arg(attributeList, char*);
glBindAttribLocation(shader, index, nextArg);
}
va_end(attributeList);

glLinkProgram(shader);

glDeleteShader(vs);
glDeleteShader(fs);

return shader;
}


... now I suppose this is the part where I fail - painGL():


glUseProgram(myShader);
glBindTexture(GL_TEXTURE_2D, myTextureId);
GLint iTextureUniform = glGetUniformLocation(myShader, "colorMap");
glUniform1i(iTextureUniform, 0);

glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, numberOfIndexes, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

Dan Bartlett
04-28-2011, 12:07 PM
One thing I can spot is that you have:

glDrawElements(GL_TRIANGLES, numberTriangles, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
It should probably be:

glDrawElements(GL_TRIANGLES, numberTriangles * 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));// or numberOfIndexes?

Other than that, what problem do you have exactly? I can't see anything else obviously wrong, but it might be easier to figure out what is wrong if the error message by glGetError() or unexpected result was mentioned.

If possible, I also wouldn't use glGetUniformLocation(myShader, "colorMap"); every time you want to adjust the colorMap uniform, but instead would determine the location just once after linking.

ElFuego
04-28-2011, 01:04 PM
One thing I can spot is that you have:

glDrawElements(GL_TRIANGLES, numberTriangles, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
It should probably be:

glDrawElements(GL_TRIANGLES, numberTriangles * 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));// or numberOfIndexes?

Other than that, what problem do you have exactly? I can't see anything else obviously wrong, but it might be easier to figure out what is wrong if the error message by glGetError() or unexpected result was mentioned.

If possible, I also wouldn't use glGetUniformLocation(myShader, "colorMap"); every time you want to adjust the colorMap uniform, but instead would determine the location just once after linking.

Of course - my bad, it was a copy paste error. I've edited it.
Well, compiler reports no errors and no warnings, no segmentation faults, nothing. But instead of one centered (textured) image I get only a curious (non-textured) quad in the upper right corner of the image viewer window. If I comment out this:


glUseProgram(myShader);
glBindTexture(GL_TEXTURE_2D, myTextureId);
GLint iTextureUniform = glGetUniformLocation(myShader, "colorMap");
glUniform1i(iTextureUniform, 0);

and leave the glDrawElements I get the correct mesh grid, but no textures so I guess the vao/vbo/ibo are fine, but something else is rotten.

Do you suggest I put the above in the setupRC() instead of paintGL? I'll try it immediately.

To be honest, I am not perfectly sure I understand how exactly does the getUniformLocation works. Any examples or tutorials would be great!

Edit: Moving the above code out of paintGL() produces exactly the same result

Alfonse Reinheart
04-28-2011, 01:16 PM
Do you suggest I put the above in the setupRC() instead of paintGL? I'll try it immediately.

I would suggest that you change your shader to turn off texturing and see what happens. Just write a color to the output.


To be honest, I am not perfectly sure I understand how exactly does the getUniformLocation works. Any examples or tutorials would be great!

Why do you keep asking for "examples or tutorials" for how a function works? What you want is documentation. Copy-and-pasting from examples is precisely the reason you don't know how the function works, yet you're still using it.

For the record: uniforms have names. However, accessing data based on string names can take lots of time. Therefore, OpenGL programs assign a uniform location (a number) to every uniform in a program. glGetUniformLocation is how you get the uniform location from a uniform name. All of the glUniform* functions take uniform locations.

ElFuego
04-29-2011, 02:11 AM
Thanks Alfonse! I will try it right away. Btw, I prefer a tutorial to documentation exactly because your explanation is much more understandable then: "glGetUniformLocation Returns the location of a uniform variable" from
http://www.opengl.org/sdk/docs/man/xhtml/glGetUniformLocation.xml

Please dont get me wrong, but I find the documentation pretty lousy, and a fine tutorial on GLSL texturing is hard to find :(

Edit: changing the fragment shader:


--vFragColor = texture(colorMap, vVaryingTexCoords.st);"
++vFragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);

Makes the quad red (but the quad still has different coordinates then the original one).

Alfonse Reinheart
04-29-2011, 02:43 AM
That's reference documentation. I was talking about documentation (http://www.opengl.org/wiki/GLSL_Uniform).

ElFuego
04-29-2011, 02:52 AM
That's reference documentation. I was talking about documentation (http://www.opengl.org/wiki/GLSL_Uniform).
Now thats something else! Thanks for the link, its bookmarked. You were right, that was exactly what I was looking for, my bad. :) I'll see what I can work out now.

P.S. This (http://www.opengl.org/wiki/GLSL_Samplers) is even better :)

ElFuego
04-29-2011, 04:11 AM
I think I found out why the program doesnt work correctly, at least the texturing. The deprecated program uses the texture combiner

glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );

Which need to be ported correctly into shaders as stated here: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&amp;Number=295011

ElFuego
05-05-2011, 05:46 AM
Got the issue fixed - there was a transformation in deprecated code that I oversaw (very stupid of me), so everything worked after I fixed the vertex shader.

Thanks for all suggestions and links, I learned a lot! :)