Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass multiple textures to a single shader?

I am using freeglut, GLEW and DevIL to render a textured teapot using a vertex and fragment shader. This is all working fine in OpenGL 2.0 and GLSL 1.2 on Ubuntu 14.04.

Now, I want to apply a bump map to the teapot. My lecturer evidently doesn't brew his own tea, and so doesn't know they're supposed to be smooth. Anyway, I found a nice-looking tutorial on old-school bump mapping that includes a fragment shader that begins:

uniform sampler2D DecalTex; //The texture uniform sampler2D BumpTex; //The bump-map  

What they don't mention is how to pass two textures to the shader in the first place.

Previously I

//OpenGL cpp file glBindTexture(GL_TEXTURE_2D, textureHandle);  //Vertex shader gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;  //Fragment shader gl_FragColor = color * texture2D(DecalTex,gl_TexCoord[0].xy); 

so now I

//OpenGL cpp file glBindTexture(GL_TEXTURE_2D, textureHandle); glBindTexture(GL_TEXTURE_2D, bumpHandle);  //Vertex shader gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;  //Fragment shader gl_FragColor = color * texture2D(BumpTex,gl_TexCoord[0].xy); //no bump logic yet, just testing I can use texture 1 instead of texture 0 

but this doesn't work. The texture disappears completely (effectively the teapot is white). I've tried GL_TEXTURE_2D_ARRAY, glActiveTexture and few other likely-seeming but fruitless options.

After sifting through the usual mixed bag of references to OpenGL and GLSL new and old, I've come to the conclusion that I probably need glGetUniformLocation. How exactly do I use this in the OpenGL cpp file to pass the already-populated texture handles to the fragment shader?

  • How to pass an array of textures with different sizes to GLSL?
  • Passing Multiple Textures from OpenGL to GLSL shader
  • Multiple textures in GLSL - only one works

(This is homework so please answer with minimal code fragments (if at all). Thanks!)

Failing that, does anyone have a tea cosy mesh?

like image 233
lofidevops Avatar asked Aug 11 '14 21:08

lofidevops


People also ask

Can you use multiple shaders OpenGL?

However, even in OpenGL, using multiple shaders of the same type does not work they way you outline it in your question. Only one of the shaders can have a main() . The other shaders typically only contain functions. So your idea of chaining multiple shaders of the same type into a pipeline will not work in this form.

How do I pass data to shaders?

Data is passed from shader to shader by using the in and out keywords. You create an output shader variable by using the out keyword. The out variable in one shader provides the input data to the next shader declared as an in variable. The only condition is that both of these variables must have the same name.


1 Answers

It is very simple, really. All you need is to bind the sampler to some texture unit with glUniform1i. So for your code sample, assuming the two uniform samplers:

uniform sampler2D DecalTex;  // The texture  (we'll bind to texture unit 0) uniform sampler2D BumpTex;   // The bump-map (we'll bind to texture unit 1) 

In your initialization code:

// Get the uniform variables location. You've probably already done that before... decalTexLocation = glGetUniformLocation(shader_program, "DecalTex"); bumpTexLocation  = glGetUniformLocation(shader_program, "BumpTex");  // Then bind the uniform samplers to texture units: glUseProgram(shader_program); glUniform1i(decalTexLocation, 0); glUniform1i(bumpTexLocation,  1); 

OK, shader uniforms set, now we render. To do so, you will need the usual glBindTexture plus glActiveTexture:

glActiveTexture(GL_TEXTURE0 + 0); // Texture unit 0 glBindTexture(GL_TEXTURE_2D, decalTexHandle);  glActiveTexture(GL_TEXTURE0 + 1); // Texture unit 1 glBindTexture(GL_TEXTURE_2D, bumpHandle);  // Done! Now you render normally. 

And in the shader, you will use the textures samplers just like you already do:

vec4 a = texture2D(DecalTex, tc); vec4 b = texture2D(BumpTex,  tc); 

Note: For techniques like bump-mapping, you only need one set of texture coordinates, since the textures are the same, only containing different data. So you should probably pass texture coordinates as a vertex attribute.

like image 166
glampert Avatar answered Sep 21 '22 22:09

glampert