Все об объектах OpenGL
Стандартная модель для объектов OpenGL выглядит следующим образом.
Объекты имеют состояние. Думайте о них как о struct
. Таким образом, вы можете иметь объект, определенный следующим образом:
struct Object
{
int count;
float opacity;
char *name;
};
В объекте хранятся определенные значения, и он имеет состояние . Объекты 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*
звонки имеют целевой параметр. Это представляет различные местоположения в контексте 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
версии изменяют содержимое текстуры, но технически не изменяют ее состояние . Эти 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;
}
Обратите внимание, что теперь у нас есть не только двухмерный список 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 запрещает это и выдает ошибку при попытке рендеринга.
GL_TEXTURE0 + i
- я хотел проверить значения перечисления, чтобы увидеть, было ли это правильно или нет. И последний абзац - не знал, законно это или нет. Превосходно! Я добавляю в закладки все ваши ответы, чтобы снова обратиться к ним.