#c #opengl #glsl #shader
#c #opengl #glsl #шейдер
Вопрос:
Я пишу программу OpenGL и у меня есть несколько моделей, созданных в среде, но я не знаю, как применить разные текстуры к каждой из этих моделей, поэтому на данный момент все они имеют одинаковую текстуру. Я читал, что мне нужно добавить в программу несколько текстурных блоков или использовать текстурный атлас. Текстурный атлас кажется более сложным, поэтому я пытаюсь добавить текстурные единицы.
Я думал, что этот процесс работает следующим образом:
- Создайте два текстурных блока с помощью glGenTextures.
- Привяжите данные первого изображения к первому текстурному блоку с помощью glBindTexture и glTexImage2D.
- Проделайте то же самое со вторым изображением.
Отсюда я подумал, что смогу указать OpenGL, какой текстурный блок я хочу использовать, используя glActiveTexture. Кажется, это работает только с одной текстурой (т. Е. пропустить шаг 3), но не работает с двумя или более.
Я уверен, что чего-то не хватает, так может кто-нибудь указать мне правильное направление?
//Generate textures
int texturec=2;
int w[texturec],h[texturec];
unsigned char *data[texturec];
data[0]=getImage(amp;w[0],amp;h[0],"resources/a.png");
data[1]=getImage(amp;w[1],amp;h[1],"resources/b.png");
//Apply textures
GLuint textures[texturec];
glGenTextures(texturec, textures);
//Bind a.png to the first texture unit
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[0], h[0], 0, GL_RGB, GL_UNSIGNED_BYTE, data[0]);
//Bind b.png to the second texture unit
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[1], h[1], 0, GL_RGB, GL_UNSIGNED_BYTE, data[1]);
glActiveTexture(GL_TEXTURE0);
//Not super clear on what this does, but it needs to be here.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
А вот и мои шейдеры:
Фрагмент:
#version 330 core
in vec2 UV;
out vec3 color;
uniform sampler2D textureSampler;
void main(){
color=texture(textureSampler,UV).rgb;
}
Вершина:
#version 330 core
layout(location=0) in vec3 vertexPos;
layout(location=1) in vec2 vertexUV;
out vec2 UV;
uniform mat4 MVP;
void main(){
gl_Position=MVP*vec4(vertexPos,1);
UV=vertexUV;
}
Редактировать:
Вот мой новый код после применения предложений Rabid76:
//Generate textures
int texturec=2;
int w[texturec],h[texturec];
unsigned char *data[texturec];
data[0]=getImage(amp;w[0],amp;h[0],"resources/a.png");
data[1]=getImage(amp;w[1],amp;h[1],"resources/b.png");
//Apply textures
GLuint textures[texturec];
glGenTextures(texturec, textures);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[0], h[0], 0, GL_RGB, GL_UNSIGNED_BYTE, data[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w[1], h[1], 0, GL_RGB, GL_UNSIGNED_BYTE, data[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//Shaders
programID=loadShaders("shaders/vertex.shader","shaders/fragment.shader");
glUseProgram(programID);
//Use texture unit 1
glActiveTexture(GL_TEXTURE1);
GLint texLoc=glGetUniformLocation(programID, "textureSampler");
glUniform1i(texLoc, 1);
Ответ №1:
- Создайте два текстурных блока с помощью
glGenTextures
.
Нет. glGenTextures
не генерирует текстурную единицу.
glGenTextures
резервирует значения имен, которые могут использоваться для текстурных объектов.
glBindTexture
привязывает именованную текстуру к целевому объекту текстурирования. Когда вызывается эта функция, текстурный объект привязывается к текущему текстурному блоку.
Текущая единица измерения текстуры может быть установлена с помощью glActiveTexture
:
например
GLuint textures[texturec];
glGenTextures(texturec, textures);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
// [...]
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textures[1]);
// [...]
Значение имени текстурных объектов и текстурная единица — это совершенно разные вещи.
Текстурный элемент является точкой привязки между объектом текстуры и программой шейдера.
С одной стороны, текстурный объект должен быть привязан к текстурному блоку, с другой стороны, текстурный блок должен быть настроен на единообразие текстурного сэмплера. Таким образом, текстурный блок является «связующим звеном» между ними.
Начиная с GLSL версии 4.2, текстурный блок может быть установлен с помощью классификатора макета (GLSL) внутри шейдера. Точка привязки соответствует текстурному блоку. например, binding = 1
означает текстурный блок 1:
layout(binding = 1) uniform sampler2D textureSampler;
В качестве альтернативы индекс текстурной единицы может быть присвоен текстуре sampler uniform с помощью glUniform1i
:
GLint texLoc = glGetUniformLocation(programID, "textureSampler");
glUniform1i(texLoc, 1);
Если программа шейдера использует 1 образец текстуры, единый
uniform sampler2D textureSampler;
тогда достаточно привязать соответствующий объект текстуры перед вызовом draw:
glActiveTexture(GL_TEXTURE0); // this is default
glBindTexture(GL_TEXTURE_2D, textures[0]);
Но если шейдерная программа использует несколько форм сэмплера текстур (одной и той же цели), тогда разные объекты текстуры должны быть привязаны к разным текстурным единицам:
например
layout(binding = 3) uniform sampler2D textureSampler1;
layout(binding = 4) uniform sampler2D textureSampler2;
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, textures[1]);
соответственно
layout(location = 7) uniform sampler2D textureSampler1;
layout(location = 8) uniform sampler2D textureSampler2;
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, textures[0]);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, textures[1]);
glUseProgram(programID);
glUniform1i(7, 3); // location = 7 <- texture unit 3
glUniform1i(8, 4); // location = 8 <- texture unit 4
Комментарии:
1. Поскольку OP не показал этого в предоставленном ими коде, возможно, стоит расширить это последнее предложение, чтобы показать вызов
glUniform()
для установки текстурного блока, используемого фрагментным шейдером.2. Я сделал все возможное, чтобы изменить свой код на основе вашего ответа. Я вставил измененный код в конец моего первоначального вопроса. Эти изменения позволяют мне использовать текстурный модуль 1, но я не могу переключиться обратно на текстурный модуль 0. Если я изменю второй аргумент glUniform1i на 0, все текстуры по умолчанию будут черными.
3. @sam Как упоминалось в средней части вопроса, достаточно привязать соответствующую текстуру перед вызовом draw. Поскольку в программе шейдеров одновременно используется только одна текстура, достаточно использовать текстурный модуль 0. Это означает, что они вам не нужны
glActiveTexture
, но сделайтеglBindTexture
это раньшеglDraw...
4. @sam В любом случае
glActiveTexture
полезно только передglBindTexture
. Любое другое изменение активного текстурного элемента не делает того, что вы ожидаете от него — что бы это ни было.5. @sam Есть ли в вашей программе какой-либо другой вызов
glBindTexture
? Программа должна быть установлена (glUseProgram(programID)
), прежде чем можно будет установить форму (glUniform1i(texLoc, 1)
).glTexParameteri
не изменяет некоторые глобальные параметры magic. Он задает параметры текущего связанного текстурного объекта. Он должен быть вызван для каждого объекта.