Теория мультитекстурирования с текстурными объектами и сэмплерами
Я не смог найти хороших теоретических статей о том, как кодировать мультитекстурирование, используя только объекты текстуры или объекты текстуры плюс сэмплеры. Я просто не знаю, как управлять функцией 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.