У меня есть работающая программа OpenGL ES 3 (iOS), но мне трудно разобраться в текстурах OpenGL. Я пытаюсь вывести на экран несколько четырехугольников с разными текстурами. Текстуры — все 256 цветных изображений с отдельной палитрой.
Это код C ++, который отправляет текстуры шейдерам
// THIS CODE WORKS, BUT I'M NOT SURE WHY
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _renderQueue[idx]->TextureId);
glUniform1i(_glShaderTexture, 1); // what does the 1 mean here
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, _renderQueue[idx]->PaletteId);
glUniform1i(_glShaderPalette, 2); // what does the 2 mean here?
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
Это фрагмент шейдера
uniform sampler2D texture; // New
uniform sampler2D palette; // A palette of 256 colors
varying highp vec2 texCoordOut;
void main()
{
highp vec4 palIndex = texture2D(texture, texCoordOut);
gl_FragColor = texture2D(palette, palIndex.xy);
}
Как я уже сказал, код работает, но я не уверен, ПОЧЕМУ он работает. Несколько, казалось бы, незначительных изменений ломают его. Например, используя GL_TEXTURE0
, а также GL_TEXTURE1
в коде C ++ это нарушается. Изменение числа в glUniform1i
до 0, и 1 сломать его. Я предполагаю, что не понимаю кое-что о текстурировании в OpenGL 3+ (может быть, текстурные блоки ???), но мне нужно некоторое руководство, чтобы выяснить, что именно.
Так как это часто сбивает с толку новых программистов OpenGL, я попытаюсь объяснить концепцию текстурных блоков на самом базовом уровне. Это не сложная концепция, как только вы поймете терминологию.
Все это мотивировано тем, что предлагает возможность выборки нескольких текстур в шейдерах. Поскольку OpenGL традиционно работает с объектами, которые связаны с glBind*()
звонки, это означает, что необходима опция для привязки нескольких текстур. Поэтому концепция наличия один связанная текстура была расширена до наличия таблица связанных текстур. Что OpenGL называет Единица текстуры является записью в этой таблице, обозначается индексом.
Если вы хотите описать это состояние в нотации стиля C / C ++, вы можете определить таблицу связанной текстуры как массив идентификаторов текстуры, где размер — это максимальное количество связанных текстур, поддерживаемых реализацией (запрашивается с помощью glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, ...)
):
GLuint BoundTextureIds[MAX_TEXTURE_UNITS];
Если вы связываете текстуру, она привязывается к текущему активному текстурному блоку. Это означает, что последний звонок glActiveTexture()
определяет, какая запись в таблице связанных текстур будет изменена. В типичной последовательности вызовов, которая связывает текстуру с текстурным блоком i
:
glActiveTexture(GL_TEXTUREi);
glBindTexture(GL_TEXTURE_2D, texId);
это будет соответствовать изменению нашей воображаемой структуры данных путем:
BoundTextureIds[i] = texId;
Это охватывает установку. Теперь шейдеры могут получить доступ ко всем текстурам в этой таблице. Переменные типа sampler2D
используются для доступа к текстурам в коде GLSL. Чтобы определить, какая текстура каждый sampler2D
доступ к переменной, нам нужно указать, какую запись в таблице использует каждая из них. Это делается путем установки равномерного значения для индекса таблицы:
glUniform1i(samplerLoc, i);
указывает на то, что пробоотборник равномерно расположен samplerLoc
читает из таблицы i
это означает, что он производит выборку текстуры с идентификатором BoundTextureIds[i]
,
В конкретном случае вопроса первая текстура была связана с блоком текстуры 1, потому что glActiveTexture(GL_TEXTURE1)
был вызван раньше glBindTexture()
, Чтобы получить доступ к этой текстуре из шейдера, необходимо также установить униформу шейдера в 1. То же самое для второй текстуры, с блоком текстуры 2.
(Приведенное выше описание было несколько упрощено, потому что оно не учитывало разные текстурные цели. На самом деле, текстур с разными целями, например, GL_TEXTURE_2D
а также GL_TEXTURE_3D
, может быть привязан к одному и тому же текстурному блоку.)
GL_TEXTURE1 и GL_TEXTURE2 относятся к текстурным единицам. glUniform1i принимает идентификатор модуля текстуры для второго аргумента для сэмплеров. Вот почему они 1 и 2.
С веб-сайта OpenGL:
Значение сэмплера в программе не является объектом текстуры,
но индекс единицы изображения текстуры. Таким образом, вы устанавливаете индекс единицы текстуры для
каждый сэмплер в программе.