web-dev-qa-db-fra.com

Comment passer plusieurs textures à un seul shader?

J'utilise freeglut, GLEW et DevIL to rendre une théière texturée en utilisant un vertex et un fragment shader. Tout fonctionne correctement dans OpenGL 2.0 et GLSL 1.2 sur Ubuntu 14.04.

Maintenant, je veux appliquer une carte de relief à la théière. Mon conférencier ne prépare évidemment pas son propre thé, et ne sait donc pas qu'ils sont censés être doux . Quoi qu'il en soit, j'ai trouvé n joli tutoriel sur la cartographie des bosses à l'ancienne qui comprend un shader de fragment qui commence:

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

Ce qu'ils ne mentionnent pas, c'est comment passer deux textures au shader en premier lieu.

Auparavant, je

//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);

alors maintenant je

//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

mais cela ne fonctionne pas. La texture disparaît complètement (effectivement la théière est blanche). J'ai essayé GL_TEXTURE_2D_ARRAY, glActiveTexture et quelques autres options apparemment mais infructueuses.

Après avoir passé au crible le sac mixte habituel de références à OpenGL et GLSL, nouvelles et anciennes, je suis arrivé à la conclusion que j'avais probablement besoin de glGetUniformLocation. Comment utiliser exactement cela dans le fichier cpp OpenGL pour passer les poignées de texture déjà remplies au shader de fragment?

(Il s'agit de devoirs, veuillez donc répondre avec un minimum de fragments de code (le cas échéant). Merci!)

À défaut, quelqu'un a-t-il une maille confortable pour le thé?

24
david.libremone

C'est très simple, vraiment. Tout ce dont vous avez besoin est de lier l'échantillonneur à une unité de texture avec glUniform1i . Donc, pour votre exemple de code, en supposant les deux échantillonneurs uniformes:

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)

Dans votre code d'initialisation:

// 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, ensemble d'uniformes de shader, maintenant nous rendons. Pour ce faire, vous aurez besoin de l'habituel 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.

Et dans le shader, vous utiliserez les échantillonneurs de textures comme vous le faites déjà:

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

Remarque: pour des techniques telles que le bump-mapping, vous n'avez besoin que d'un seul ensemble de coordonnées de texture, car les textures sont les mêmes, ne contenant que des données différentes. Vous devez donc probablement passer les coordonnées de texture sous la forme d'un attribut vertex .

42
glampert