7. Texturing in GLSL
Jump To:
main.cpp Source
shader.vert Source
shader.frag Source
Download
Woo, congrats for making it this far. By now, you should know how to use basic shaders for lighting an object. So the next logical step would be to add some textures to our shape.
But first, because we are introducing a new type of shader variable, calld a Uniform variable, let me first explain it. A Uniform variable is a variable that we write to in our OpenGL application, and can then send through to a shader program. The Uniform variable can be an integer, a float, a vector, and even a matrix.
Because a texture is stored by OpenGL using an integer for identification, we will be sending through an integer variable to our shader by using Uniforms.
Main.CPP File: The main.cpp is going to have some fairly minor changes. All of the texturing code itself is taken from previous tutorials, so I am going to jump to the stuff we haven’t seen before. If you want to just jump to the cube() method (which by now draws a teapot because I didn’t rename the method, naughty me), you will notice 4 lines of code are used to setup our textures. The first line is a call you should have seen from the multitexturing tutorial. We are going to tell OpenGL (and therefore GLSL0), that we are working with our texture unit 0. After deciding which texture we are going to use, we then need a variable that tells us the location of our texture variable in our shader. This is done with a call to glGetUniformLocation, and takes the paramters for the shader id, and the name of the variable inside the shader for our texture. Now that we know where our variable is inside the shader, we can then go ahead and set it. Because OpenGL uses numbers to identify the textures, we make a call to glUniform1i, which means we have a variable going into the shader (uniform), it is one value long (as opposed to a vec2 or vec3), and the value we are sending it is the first texture for our shader. The numbering for the textures in the shader, go from 0…n. And finally, we do what we always do when we are texturing, and we bind our texture that we want to use. This is fairly simple, but when dealing with multiple texture inputs to a shader, remember that you need to use the glActiveTexture calls in order, and then when you have finished with them, set the active textures in reverse order and disable texturing on each of the texture units to cleanup.
Feel free now to jump down to our shaders, and checkout the changes.
|
||||
Vertex Shader Source: In this tutorial, we are going to go back to our first shader that we ever made. So this shader will not be using lighting. Ontop of our base shader, all we need is one extra line in our vertex shader. This line will write to the variable gl_TexCoord[0], the texture coordinates for the current vertex. The variable gl_TexCoord[0] is simply a varying variable between the vertex shader and the fragment shader. This line is also where the calls to glActiveTexture start to make sense. When we feed our texture coordinates through to OpenGL, GLSL stores them in the appropriate gl_MultiTexCoord(n) call. This allows us to set multiple uv coordinates per vertex, which is useful when multitexturing. In the end, our one line needed in the vertex shader to enable texturing, is:
|
||||
Fragment Shader Source: Our Fragment shader is also going to introduce one new line of code, but we are also going to modify another. The line we want to add, will be used to setup the input location for our texture variable, and will give us a variable we can use to access the texture. uniform sampler2D color_texture; You may be wondering why the variable is of the type sampler2D, I honestly have no idea of the naming, I have never looked into it. But all you have to remember is that a sampler2D is code for a 2D texture. You can also get sampler1D’s and sampler3D’s, along with samplers for shadows and projections. But these are a little more advanced, and if all goes well, I’ll have some tutorials for them later. Now as you know, we need to set the gl_FragColor from our fragment shader, so that we get something on the screen. We are going to modify our original line to look like: This line means that we have a 2D texture that we are reading in, and this texture is associated with the color_texture variable, and finally we are calling the u,v coordinates for the current fragment. When we are calling gl_TexCoord[0].st, it is good to remember that this variable is actually a vec4 variable with the values s, t, p and q. But we only want to use the first two values, s and t. Theoretically you can replace st with xy or even rg, to pull out the first two values, as it is only a vec4 variable. But switching the naming aroung like this can be confusing. It is also good to keep in mind, that texture2D returns a vec4 variable, with the values for (red, green, blue and alpha). Which is perfect because gl_FragColor requires a vec4. And thats all there is to texturing in GLSL. It is quite simple, I have just gone to the effort to over explain it for everyone 😀 If you have any questions, please email me at swiftless@gmail.com
|
||||
Download: Download shader.h Source Code for this Tutorial Download shader.cpp Source Code for this Tutorial Download main.cpp Source Code for this Tutorial |
Why use centering for the code parts on this page? It is rather difficult to read!
Hey someone,
Apologies, I get a lot of comments about these older tutorials not being formatted correctly but I don’t have the time to update them.
One day I will try to get it fixed!
Thanks,
Swiftless
Dear Swifless,
Thanks for your help in shader but the problem is the last texturing file didnt work in my pc.I didnt get any error while I run this code but I didnt get any output of teturing.The output seems to be blank.I think I didnt idea of how to put the code of shader.vert and shader.frag in texturing file.Please do help me since I m new to shader.
With Regards,
pb
Dear swiftless,
when i run the code of texture.I didn`t get any output though there isn`t any error in the code.The output seems to be blank. I put the code of shader.vert and shader.frag as it is.(downloaded from texturing ).So, should there be any change in the code or should I have to add this code in previous lighting file??Please suggest me.
Regards,
PB
does it also work with other solid(other than teapot)? I tried but no result like teapot….??
It is due to size of loaded texture??
Hi Bikash.
It only works with the glutSolidTeapot because it is the only glutSolid shape which has texture coordinates assigned to it.
Thanks,
Swiftless
it works fine to me but when i change glutSolidTeapot(2.0); to glutSolidCube(2.0) or other solid glut image;
whole the cube seems green only(not as teapot or no texture).
Is this only work for glutSolidTeapot??
bugfix in shader.cpp:
initialize pointer:
static char* textFileRead(const char *fileName) {
char* text = NULL;
There’s no link to a texture file in the download list for this tutorial. I found one here though: http://www.swiftless.com/tutorials/opengl/cplusplus/texture.zip
Hey Swift!
I was wondering how you make the “raw” files? Like the texture.raw. I can’t find any program to convert any file into raw. It may sound like a stupid question but please I am new to this and I need your help : )
not sure if you notice this but your theme is cutting the text, take a look here:
http://i.imgur.com/fDh8z.png
look at: didn’t rename the method, naughty me
well “rename the method” gets cut/hidden so its not really possible to follow the text, please correct this. If you need help with that, I am wordpress theme developer and can help you probably with css/html, in that case drop me an email and I’ll be glad to help 🙂
Hi Swiftless,
I have a following question,
file = fopen( filename, “rb” );
if ( file == NULL ) return 0;
data = (unsigned char *)malloc( width * height * 3 );
fread( data, width * height * 3, 1, file );
fclose( file );
glGenTextures( 1, &texture ); //generate the texture with the loaded
data
glBindTexture( GL_TEXTURE_2D, texture ); //bind the texture to it’s
array
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
GL_MODULATE ); /
when you use the function, glGenTextures(),
How does the openGL understand to read the texture from the pointer “data”? I mean where have you passed ‘data ‘ to openGL.
Thank you for your effort! Keep up with your great tutorials!
…and takes the paramters for the shader id, and the name of the variable inside the shader for our texture.
int texture_location = glGetUniformLocation(shader.id(), “texture_color”);
and
uniform sampler2D color_texture;
dont seem to line up, is this intentional?
Hey Fonix,
That’s a typo, just rename either of the variables to match up with the other.
Cheers,
Swiftless
Hey Bloodust,
I’m surprised you got all the way to tutorial 7 before that 😛
I’ve mentioned that in the comments for the previous tutorials. The reason I don’t have it, is because I made these tutorials on OSX and on OSX that call isn’t needed.
Cheers,
Swiftless
Great but missing glew initialization and without it my shader couldnt be created because
“Unhandled exception at 0x00000000”
add this to main before init()
if(glewInit() != GLEW_OK)
return 0;
or just
glewInit();
@Swiftless:
actually my game using shader from yours tuts looks like this:
http://www.gamedev.pl/projects.php?x=view&id=1198
Great tutorial!
I forgot the line
gl_TexCoord[0] = gl_MultiTexCoord0;
in my vertex shader until i saw your tutorial, then it was suddenly working.
it can feel so great to see a simple 2d texture quad on the screen sometimes when you’re doing graphics programming.