Различия и взаимосвязь между glActiveTexture и glBindTexture
насколько я понял,glActiveTexture
устанавливает активный "текстурный блок". Каждый текстурный блок может иметь несколько целевых объектов текстуры (обычно GL_TEXTURE_1D, 2D, 3D или CUBE_MAP).
если я правильно понял, вы должны позвонить glActiveTexture
для установки текстурного блока первым (инициализируется в GL_TEXTURE0
), а затем вы привязываете (один или несколько) "цели текстуры" к этому текстурному блоку?
количество доступных текстурных блоков зависит от системы. Я вижу перечисления до 32 в моей библиотеке. Я думаю, что это по сути, это означает, что я могу иметь меньший предел моего GPU (который, я думаю,16 8) и 32 текстуры в памяти GPU в любое время? Я думаю, что есть дополнительный предел, который я не превышаю максимальную память моего GPU (предположительно 1 ГБ).
правильно ли я понимаю взаимосвязь между текстурными целями и текстурными единицами? Допустим, мне разрешено 16 единиц и 4 цели каждая, означает ли это, что есть место для 16*4=64 целей, или это не работает, как это?
Далее, вы обычно хотите, чтобы загрузить текстуру. Вы можете сделать это через glTexImage2D
. Первый аргумент которого является целевой текстурой. Если это работы как glBufferData
, затем мы по существу связываем "дескриптор" / "имя текстуры" с целью текстуры, а затем загружаем данные текстуры в эту цель и, таким образом, косвенно связываем ее с этим дескриптором.
а как же glTexParameter
? Мы должны привязать цель текстуры, а затем снова выбрать ту же цель, что и первая спор? Или текстурная цель не должна быть привязана, пока у нас есть правильный активный текстурный блок?
glGenerateMipmap
работает на цель...эта цель все еще должна быть привязана к имени текстуры для ее успеха?
тогда, когда мы хотим нарисовать наш объект с текстурой на нем, мы должны и выберите активный текстурный блок, а затем цель текстуры? Или мы выбираем текстурный блок, а затем мы можем захватить данные из любой из 4 целей связано с этим подразделением? Это та часть, которая действительно сбивает меня с толку.
4 ответа:
Все Об Объектах OpenGL
стандартная модель для объектов OpenGL выглядит следующим образом.
объекты имеют состояние. Думайте о них как о
struct
. Таким образом, у вас может быть объект, определенный следующим образом:struct Object { int count; float opacity; char *name; };
объект имеет определенные значения, хранящиеся в нем, и он имеет state. Объекты OpenGL также имеют состояние.
Изменение Состояния
в C/C++, если у вас есть экземпляр типа
Object
, вы бы изменить его состояние как следует:obj.count = 5;
вы бы напрямую ссылались на экземпляр объекта, получали конкретный фрагмент состояния, который вы хотите изменить, и вставляли в него значение.в OpenGL, ты не сделать это.
по устаревшим причинам лучше оставить необъясненным, чтобы изменить состояние объекта OpenGL, вы должны сначала связать это в контексте. Это делается с некоторыми из
glBind*
звонок.эквивалент C/C++ к этому как следует:
Object *g_objs[MAX_LOCATIONS] = {NULL}; void BindObject(int loc, Object *obj) { g_objs[loc] = obj; }
текстуры интересны; они представляют собой особый случай привязки. Много
glBind*
вызовы имеют параметр "target". Это представляет различные местоположения в контексте OpenGL, где объекты этого типа могут быть связаны. Например, можно привязать объект framebuffer для чтения (GL_READ_FRAMEBUFFER
) или для записи (GL_DRAW_FRAMEBUFFER
). Это влияет на то, как OpenGL использует буфер. Этоloc
параметр выше представляет.текстуры особенные, потому что когда ты первый привязать их к цели, они получают специальную информацию. Когда вы впервые связываете текстуру как
GL_TEXTURE_2D
, вы на самом деле создание специальной государственной структуры. Вы говорите, что эта текстура является 2D текстуры. И это будет всегда быть 2D текстурой; это состояние не может быть изменено когда-нибудь. Если у вас есть текстура, которая была сначала связана какGL_TEXTURE_2D
необходимо всегда свяжите его какGL_TEXTURE_2D
; попытка привязать его какGL_TEXTURE_1D
приведет к ошибке (во время выполнения).как только объект привязан, его состояние может быть изменено. Это делается с помощью общих функций, специфичных для этого объекта. Они также принимают расположение, которое представляет какой объект для изменения.
в C/C++ это выглядит так:
void ObjectParameteri(int loc, ObjectParameters eParam, int value) { if(g_objs[loc] == NULL) return; switch(eParam) { case OBJECT_COUNT: g_objs[loc]->count = value; break; case OBJECT_OPACITY: g_objs[loc]->opacity = (float)value; break; default: //INVALID_ENUM error break; } }
обратите внимание, как эта функция устанавливает все, что происходит в текущей привязке
loc
значение.для объектов текстуры основными функциями изменения состояния текстуры являются
glTexParameter
. Единственные другие функции, которые изменяют состояние текстуры являютсяglTexImage
функции и их вариации (glCompressedTexImage
,glCopyTexImage
, последниеglTexStorage
). РазличныеSubImage
версии меняют содержание текстуры, но они технически не меняют ее state. ЭлементImage
функции выделяют хранилище текстур и устанавливают формат текстуры;SubImage
функции просто копировать пиксели вокруг. Это не считается состоянием текстуры.позвольте мне повторить: это только функции, которые изменяют состояние текстуры.
glTexEnv
изменяет состояние среды; это не влияет ни на что, хранящееся в текстурных объектах.Активный Текстуры
ситуация с текстурами более сложная, опять же по причинам наследия, которые лучше оставить нераскрытыми. Вот где
glActiveTexture
приходит.для текстур, есть это не просто цели (
GL_TEXTURE_1D
,GL_TEXTURE_CUBE_MAP
и т. д.). Есть также текстуры блоки. С точки зрения нашего примера C / C++, у нас есть следующее:Object *g_objs[MAX_OBJECTS][MAX_LOCATIONS] = {NULL}; int g_currObject = 0; void BindObject(int loc, Object *obj) { g_objs[g_currObject][loc] = obj; } void ActiveObject(int currObject) { g_currObject = currObject; }
обратите внимание, что теперь у нас есть не только 2D-список
Object
S, но у нас также есть понятие текущего объекта. У нас есть функция для установки текущего объекта, у нас есть концепция максимального количества текущих объектов, и все наши функции управления объектами настраиваются для выбора из текущего объект.при изменении текущего активного объекта изменяется весь набор целевых местоположений. Таким образом, вы можете привязать что-то, что входит в текущий объект 0, переключиться на текущий объект 4 и будет изменять совершенно другой объект.
эта аналогия с текстурными объектами идеальна... почти.
см.,
glActiveTexture
не принимает целое число; это перечислитель. Что в теории означает, что он может взять что угодно отGL_TEXTURE0
кGL_TEXTURE31
. Но есть одна вещь, которую вы должны понять:ЭТО ЛОЖЬ!
фактический диапазон, что
glActiveTexture
может взять управляетсяGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
. Это максимальное количество одновременных мультитекстур, которое позволяет реализация. Каждый из них разделен на различные группы для разных этапов шейдера. Например, на GL 3.оборудование класса X, вы получаете 16 вершинных текстур, шейдеров, 16 фрагмент текстур, шейдеров и 16 геометрических шейдеров текстуры. Таким образом,GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
будет 48.но нет 48 переписчиков. Вот почему
glActiveTexture
на самом деле не принимают переписчиков. Элемент правильно способ вызоваglActiveTexture
следующим образом:glActiveTexture(GL_TEXTURE0 + i);
здесь
i
- это число от 0 доGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
.визуализация
Итак, что же все это имеет отношение к визуализации?
при использовании шейдеров вы устанавливаете форму сэмплера на единицу изображения текстуры (
glUniform1i(samplerLoc, i)
, гдеi
единица изображения). Это представляет собой число, которое вы использовали сglActiveTexture
. Пробоотборник выберет цель на основе типа пробоотборника. Так чтоsampler2D
выберу изGL_TEXTURE_2D
цель. Это одна из причин, почему сэмплеры имеют разные типы.теперь это звучит подозрительно, как вы можете иметь два GLSL сэмплеры, с разными типы которые используют тот же блок изображения текстуры. Но вы не можете; OpenGL запрещает это и даст вам ошибку, когда вы попытка рендеринга.
Я дам ему попробовать ! Все это не так сложно, просто вопрос условий, надеюсь, я буду ясно выражаться.
вы можете создать примерно столько же Объекты Текстуры как есть доступная память в вашей системе. Эти объекты содержат фактические данные (тексели) ваших текстур, а также параметры, предоставляемые glTexParameter (см. часто задаваемые вопросы).
при создании, вы должны назначить один текстура Элемент к одному объекту текстуры, который представляет тип текстуры (
GL_TEXTURE_2D
,GL_TEXTURE_3D
,GL_TEXTURE_CUBE
, ...).эти два пункта, текстура объекта и целевой текстуры представляют данные текстуры. Мы вернемся к ним позже.
текстуры
теперь OpenGL предоставляет массив текстуры, который можно использовать одновременно во время рисования. Размер массива зависит от система OpenGL, ваша имеет 8.
вы можете связать объект текстуры для текстурного блока, чтобы использовать данную текстуру при рисовании.
в простом и легком мире, чтобы рисовать с заданной текстурой, вы бы привязали объект текстуры к текстурному блоку, и вы бы сделали (псевдокод):
textureObject есть данные дляglTextureUnit[0] = textureObject
GL_TEXTURE_2D
цель текстуры, мы выразим предыдущее назначение как:glActiveTexture(GL_TEXTURE0); // select slot 0 of the texture units array glBindTexture(GL_TEXTURE_2D, textureObject); // do the binding
отметим, что
GL_TEXTURE_2D
действительно зависит от типа текстуры, которую вы хотите связать.объекты текстуры
в псевдокоде, чтобы установить данные текстуры или параметры текстуры, вы бы сделали, например:
setTexData(textureObject, ...) setTexParameter(textureObject, TEXTURE_MIN_FILTER, LINEAR)
OpenGL не может напрямую управлять текстурными объектами, обновлять / устанавливать их содержимое или изменять их параметры, вы должны сначала привязать их к активному текстурному блоку (в зависимости от того, что это такое). Этот эквивалентный код становится:
glBindTexture(GL_TEXTURE_2D, textureObject) // this 'installs' textureObject in texture unit glTexImage2D(GL_TEXTURE_2D, ...) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
шейдеры
шейдеры имеют доступ ко всем текстурным единицам, они не заботятся об активной текстуре.
образцы униформы
int
значения, представляющие индекс единицы текстуры для использования в сэмплере (и не текстура объекта для использования).таким образом, вы должны привязать объекты текстуры к единицам, которые вы хотите использовать.
тип пробоотборника будет сделано совпадение с целевой текстурой, которая используется в текстурном блоке:
Sampler2D
наGL_TEXTURE_2D
и так далее...
представьте себе GPU, как какой-то завод по обработке краски.
несколько баков, которые поставляют краску к некоторой машине картины. В машине картины краска после этого приложена к объекту. Эти танки-это текстуры
те танки можно оборудовать с различными видами краски. Каждый вид краски требует некоторого другого вида растворителя. "Растворитель" - это целевой текстуры. Для удобства каждый бак соединен с некоторыми растворяющую поставку, и но только один вид растворителя можно использовать одновременно в каждом баке. Так что есть клапан / переключатель
TEXTURE_CUBE_MAP
,TEXTURE_3D
,TEXTURE_2D
,TEXTURE_1D
. Вы можете заполнить все типы красителя в бак в то же время, но так как только один вид растворителя входит, он будет "разбавлять" только вид соответствия красителя. Таким образом, вы можете связать каждый вид текстуры, но связывание с" самым важным " растворителем фактически войдет в резервуар и смешается с тем видом красителя, к которому он принадлежит к.и затем есть сам краситель, который поступает со склада и заполняется в бак, "связывая" его. Это твоя текстура.
если в вашем шейдере вам нужен поиск из 2 текстур:
uniform sampler2D tex1; uniform sampler2D tex2;
для tex1 и tex2 необходимо указать их источники следующим образом:
tex1 = gl.createTexture(); gl.activeTexture(gl.TEXTURE3); gl.bindTexture(gl.TEXTURE_2D, tex1); gl.texParameteri(gl.TEXTURE_2D, ...); .... tex2 = gl.createTexture(); gl.activeTexture(gl.TEXTURE7); gl.bindTexture(gl.TEXTURE_2D, tex2); gl.texParameteri(gl.TEXTURE_2D, ...); .... var tex1Loc = gl.getUniformLocation(your_shader,"tex1"); var tex2Loc = gl.getUniformLocation(your_shader,"tex2");
в цикле рендеринга:
gl.uniform1i(tex1Loc, 3); gl.uniform1i(tex2Loc, 7); // but you can dynamically change these values
С gl_bindtexture, не возможно сделать такую вещь. С другой стороны возможным использованием привязки в цикле рендеринга, является случай, когда вы подаете текстуру с контентом в потоке (видео, веб-камера) :
gl.bindTexture(gl.TEXTURE_2D, tex1); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video); // in the render loop