Как я могу передать несколько текстур в один шейдер?

Я использую freeglut, GLEW и DevIL для рендеринга текстурированного чайника с использованием вершинного и фрагментного шейдера. Все это прекрасно работает в OpenGL 2.0 и GLSL 1.2 в Ubuntu 14.04.

Теперь я хочу применить карту рельефа к чайнику. Мой лектор, очевидно, не заваривает свой собственный чай, и поэтому не знает, что они должны быть гладкими. Во всяком случае, я нашел красивый учебник по рельефу старой школы, который включает фрагментный шейдер, который начинается:

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

так что теперь я

//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, чтобы передать уже заполненные маркеры текстуры фрагментному шейдеру?

(Это домашняя работа, поэтому, пожалуйста, ответьте с минимальным количеством фрагментов кода (если вообще). Спасибо!)

В противном случае, есть ли у кого-нибудь удобная чайная сетка?

2 ответа

Решение

Это очень просто, правда. Все, что вам нужно, это привязать сэмплер к некоторому текстурному блоку с помощью 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);

Примечание. Для таких методов, как рельефное отображение, вам нужен только один набор координат текстуры, так как текстуры одинаковы, содержат только разные данные. Так что вы, вероятно, должны передать координаты текстуры как атрибут вершины.

Вместо того, чтобы использовать:

glUniform1i(decalTexLocation, 0);
glUniform1i(bumpTexLocation,  1);

в вашем коде вы можете иметь:

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

в вашем шейдере. Это также означает, что вам не нужно запрашивать местоположение.

Другие вопросы по тегам