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

Я использую 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. Как именно использовать этот в файле OpenGL cpp для передачи уже заполненных дескрипторов текстуры фрагментному шейдеру?

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

А если нет, есть ли у кого-нибудь уютная сеточка для чая?


person lofidevops    schedule 11.08.2014    source источник
comment
Я использую несколько текстур в GLSL из Python. Вот мое репо со скриншотами   -  person Szabolcs Dombi    schedule 30.06.2017


Ответы (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);

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

person glampert    schedule 11.08.2014
comment
отлично! это был порядок glGetUniformLocation / glUseProgram / glUniform1i, который был моей основной причиной путаницы - как упоминалось в stackoverflow.com/a/12065077/236081 Мне пришлось glActiveTexture(GL_TEXTURE0 + 0); после последнего glBindTexture, чтобы он заработал - и спасибо за ссылки на хронос - person lofidevops; 12.08.2014
comment
Каким образом glGenSampler и GlBindSampler участвуют в этой процедуре? - person dudu; 25.03.2019

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

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)

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

person merak    schedule 26.06.2017
comment
Это неверно для GLSL 1.2, потому что макета (location = 0) не существует. - person GenericPtr; 07.01.2018
comment
Я бы сказал, что это элегантное решение в современном Opengl. Использование привязки макета дает возможность связывать шнуры текстуры и индекс текстуры из ваших данных вершин (glVertexAttribPointer ()), старые стандарты openGL ОЧЕНЬ не в чести. и это дает вашему шейдеру возможность выбрать правильный индекс из группы сэмплеров. - person Pnelego; 14.04.2020
comment
Возможно, и я в целом согласен с вами, @Pnelego, но, честно говоря, мы имеем в виду очень современный - макет (привязка) не был введен до GLSL версии 4.2. Я лично работаю над проектом, в котором я нацелен на 3.3, просто ради гибкости, и не могу на это рассчитывать. - person Michael Macha; 01.12.2020