Странность текстурирования в OpenGL ES 3 (iOS) — хотите знать, почему

У меня есть работающая программа 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+ (может быть, текстурные блоки ???), но мне нужно некоторое руководство, чтобы выяснить, что именно.

1

Решение

Так как это часто сбивает с толку новых программистов 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, может быть привязан к одному и тому же текстурному блоку.)

3

Другие решения

GL_TEXTURE1 и GL_TEXTURE2 относятся к текстурным единицам. glUniform1i принимает идентификатор модуля текстуры для второго аргумента для сэмплеров. Вот почему они 1 и 2.

С веб-сайта OpenGL:

Значение сэмплера в программе не является объектом текстуры,
но индекс единицы изображения текстуры. Таким образом, вы устанавливаете индекс единицы текстуры для
каждый сэмплер в программе.

2

По вопросам рекламы [email protected]