Теория мультитекстурирования с текстурными объектами и сэмплерами

Я не смог найти хороших теоретических статей о том, как кодировать мультитекстурирование, используя только объекты текстуры или объекты текстуры плюс сэмплеры. Я просто не знаю, как управлять функцией glActiveTexture и что именно она делает.

glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0 + 0); // Number between 0 and GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, img.getSize().x, img.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.getPixelsPtr()); // Not in sampler
glGenerateMipmap(GL_TEXTURE_2D); // Not in sampler

/* Values associated with the texture and not with sampler (sampler has priority over texture).
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);*/

glGenSamplers(1, &textureSampler);
glBindSampler(0, textureSampler);
glSamplerParameteri(textureSampler, GL_TEXTURE_WRAP_S, GL_REPEAT);
glSamplerParameteri(textureSampler, GL_TEXTURE_WRAP_T, GL_REPEAT);
glSamplerParameteri(textureSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(textureSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

glUniform1i(glGetUniformLocation(colorShader->program, "textureSampler"), 0); // 0 pour GL_TEXTURE0

Я немного запутался, если мультитекстурирование связано с наличием нескольких сэмплеров в фрагментном коде, связанных с несколькими текстурами, или если возможно иметь только один сэмплер с несколькими текстурами?

2 ответа

Решение

Многое из этого должно было быть объяснено ранее, но позвольте мне попытаться дать краткий обзор, который, мы надеемся, прояснит, как все различные части сочетаются друг с другом. Я начну с объяснения каждой части отдельно, а затем объясню, как они связаны.

Текстурная цель

Это относится к различным типам текстур (2D, 3D и т. Д.). Вы можете иметь несколько текстур, по одной на каждый тип текстуры, привязанных к одному и тому же текстурному блоку одновременно. Например, после:

glBindTexture(GL_TEXTURE_2D, texId1);
glBindTexture(GL_TEXTURE_3D, texId2);

И то и другоеtexId1 а также texId2 будет привязан к одному и тому же текстурному блоку, что возможно, потому что они привязаны к разным целям.

Детали этого несколько запутаны и запутаны, и я не буду рассматривать это в остальной части этого ответа. Я бы порекомендовал вам всегда привязывать разные текстуры к разным текстурным блокам. Это избавит вас от головных болей и неожиданностей.

Объект текстуры

Имена для текстурных объектов создаются с glGenTextures()они связаны с glBindTexture()и т. д. Объекты текстуры имеют:

  • Данные текстуры.
  • Состояние, определяющее способ выборки данных текстуры, например атрибуты фильтрации, установленные с glTexParameteri(),

Они также содержат информацию о формате / типе текстуры, который был указан вместе с данными.

Единица текстуры

Как часть текущего состояния OpenGL, вы можете представить таблицу текстур, которые в данный момент связаны. Нам нужно более одной текстуры, связанной одновременно, для поддержки мультитекстурирования. Единица текстуры может рассматриваться как запись в этой таблице состояний.

Ты используешь glActiveTexture() указать текущие активные текстурные блоки. Вызовы, которые должны работать с определенным текстурным модулем, будут затем работать с активным текстурным модулем. Например:

glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texId);

Будет связывать texId к текстурному блоку 3. Снова изображая таблицу связанных текстур, 4-я запись (нумерация начинается с 0) теперь указывает на текстуру texId,

Sampler Object

Это новый тип объектов, доступных в OpenGL 3.3 и более поздних версиях. Это не понадобится для большинства случаев использования, даже если они включают выборку из нескольких текстур. Я включил их здесь для полноты, но вам не нужно беспокоиться о сэмплерах, пока вы не получите четкое представление о текстурных объектах и ​​текстурных единицах.

Помните, как я объяснил выше, что объектам текстуры принадлежат данные текстуры, а также состояние, определяющее, как данные отбираются? То, что по сути дела делают сэмплеры, это разделение этих двух аспектов. Объект сэмплера содержит состояние, которое может переопределить состояние, связанное с выборкой, в объекте текстуры.

Это позволяет вам делать выборку одной текстуры с разными параметрами выборки в одном шейдере. Скажем, вы хотите выполнить ЛИНЕЙНУЮ и БЛИЖАЙШУЮ выборку одной и той же текстуры в одном шейдере. Без объектов сэмплера вы не сможете сделать это, не имея нескольких копий одной и той же текстуры (с несколькими копиями данных). Объекты сэмплера обеспечивают такую ​​функциональность.

Вид текстуры

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

В тех случаях, когда сэмплеры отделяют данные текстуры (с соответствующим форматом) от параметров сэмплирования, представления текстуры отделяют необработанные данные текстуры от формата. Они позволяют использовать одни и те же необработанные текстурные данные в разных форматах. Я подозреваю, что вы можете пройти очень долгий путь, даже не используя эту функцию.

Положить кусочки вместе

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

Глядя на него со стороны шейдера, шейдер знает, из каких текстурных единиц он сэмплирует. Это определяется значением равномерных переменных сэмплера. Например, если "MyFirstTexture" является именем переменной сэмплера в коде шейдера, следующее указывает, что переменная связана с модулем текстуры 3:

GLint loc = glGetUniformLocation(prog, "MyFirstTexture");
glUniform1i(loc, 3);

Ассоциация между модулем текстуры и объектом текстуры устанавливается с фрагментом кода, который уже был показан выше:

glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texId);

Эти две части являются критическими частями при подключении текстуры к переменной сэмплера в вашем шейдерном коде. Обратите внимание, что значение равномерной переменной является индексом единицы текстуры (3), в то время как аргумент glActiveTexture() это соответствующее перечисление (GL_TEXTURE3). Я бы сказал, что это неудачный дизайн API, но вам нужно просто привыкнуть к нему.

Как только вы поймете это, мы надеемся, что станет очевидным, как вы используете несколько текстур в своем шейдере (так называемое "мультитекстурирование"):

  • В вашем коде шейдера есть несколько переменных сэмплера.
  • Вы делаете glUniform1i() вызывает для установки значений переменных сэмплера на индексы различных текстурных блоков.
  • Вы привязываете текстуру к каждому из соответствующих текстурных блоков.

Показываем это для двух текстур, используя текстурные блоки 0 и 1:

glUseProgram(prog);

GLint loc = glGetUniformLocation(prog, "MyFirstTexture");
glUniform1i(loc, 0);
loc = glGetUniformLocation(prog, "MySecondTexture");
glUniform1i(loc, 1);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texId0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texId1);

Еще один способ взглянуть на это состоит в том, что существует некоторый уровень косвенности между переменными сэмплеров в шейдерах и объектами текстуры. Шейдер не имеет прямой связи с текстурными объектами. Вместо этого он имеет индекс в таблицу объектов текстуры (где этот индекс является значением универсальной переменной), и эта таблица, в свою очередь, содержит "указатели" на объекты текстуры (где записи таблицы заполняются glActiveTexture()/glBindTexture()`.

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

Существует объект сэмплера по умолчанию, содержащийся в каждом объекте текстуры, который будет использоваться для чтения из текстуры, когда ни один объект сэмплера не связан с соответствующей единицей сэмплера. Для изменения параметров этого объекта предусмотрена аналогичная функция glTexParameter.

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