Как передать несколько текстур в один шейдер?
Я использую freeglut, GLEW и DevIL для визуализировать текстурированный чайник, используя вершинный и фрагментарный шейдер, Все это отлично работает в OpenGL 2.0 и GLSL 1.2 на Ubuntu 14.04.
Теперь я хочу применить карту рельефа к чайнику. Мой лектор, очевидно, не brew собственного чая, и поэтому не знает, что они должны быть гладкими. Во всяком случае, я нашел красиво выглядящий учебник по сопоставлению башен старой школы, который включает в себя фрагментарный шейдер, который начинается:
uniform sampler2D DecalTex; //The texture
uniform sampler2D BumpTex; //The bump-map
То, что они не упоминают, - это как передать две текстуры шейдеру в первую очередь.
Раньше я
//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);
так что теперь 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
но это не работает. Текстура полностью исчезает (фактически, чайник белый). Я пробовал GL_TEXTURE_2D_ARRAY, glActiveTexture и несколько других, вероятно, кажущихся, но бесплодных вариантов.
После просеивания обычного смешанного пакета ссылок на OpenGL и GLSL новые и старые, я пришел к выводу, что мне, вероятно, понадобится glGetUniformLocation
. Как именно я использую это в файле cpp OpenGL для передачи уже заполненных обработок текстуры в шейдер фрагмента?
(Это домашнее задание, поэтому, пожалуйста, ответьте с минимальными фрагментами кода (если вообще). Спасибо!)
В противном случае, у кого-нибудь есть чайная уютная сетка?
Ответы
Ответ 1
Это очень просто, на самом деле. Все, что вам нужно, - привязать пробоотборник к некоторой текстурной единице с помощью glUniform1i
. Итак, для вашего примера кода, предполагая два одинаковых сэмплера:
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)
В коде инициализации:
// 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);
ОК, шейдерная униформа, теперь мы визуализируем. Для этого вам понадобится обычный glBindTexture
плюс 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.
И в шейдере вы будете использовать образцы текстур точно так же, как вы уже делали:
vec4 a = texture2D(DecalTex, tc);
vec4 b = texture2D(BumpTex, tc);
Примечание. Для таких методов, как bump-mapping, вам нужен только один набор текстурных координат, так как текстуры одинаковы, только содержащие разные данные. Поэтому вы должны, вероятно, передать координаты текстуры как атрибут vertex.
Ответ 2
вместо использования:
glUniform1i(decalTexLocation, 0);
glUniform1i(bumpTexLocation, 1);
в вашем коде,
вы можете:
layout(location=0) uniform sampler2D DecalTex;
// The texture (we'll bind to texture unit 0)
layout(location=1)uniform sampler2D BumpTex;
// The bump-map (we'll bind to texture unit 1)
в вашем шейдере. Это также означает, что вам не нужно запрашивать местоположение.