Все об объектах 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;
}
Обратите внимание, что теперь у нас есть не только двухмерный список Objects, но и концепция текущего объекта. У нас есть функция для установки текущего объекта, у нас есть концепция максимального количества текущих объектов, и все наши функции манипулирования объектами настроены для выбора из текущего объекта.
Когда вы меняете текущий активный объект, вы меняете весь набор целевых местоположений. Таким образом, вы можете привязать что-то, что входит в текущий объект 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- я хотел проверить значения перечисления, чтобы увидеть, было ли это правильно или нет. И последний абзац - не знал, законно это или нет. Превосходно! Я добавляю в закладки все ваши ответы, чтобы снова обратиться к ним.