Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

RedBook

.pdf
Скачиваний:
18
Добавлен:
11.06.2015
Размер:
7.43 Mб
Скачать

Представьте себе, что в какой-то момент вы хотите выключить освещение и рисовать все геометрические объекты одним цветом. Вам понадобится glDisable() для выключения расчетов, связанных с освещением. Кроме того, вы, вероятно, захотите отключить присваивание нормалей вершинам, так как без света это лишняя трата времени. Чтобы это сделать, вызовите:

glDisableClientState(GL_NORMAL_ARRAY);

void glDisableClientState (GLenum array);

Указывает массив, который надо выключить (то есть массив, из которого не нужно забирать данные при обработке). Возможные значения параметра аналогичны значениям параметра glEnableClientState().

Возможно, вы спрашиваете себя, зачем архитекторам OpenGL понадобилось создавать эти новые длинные имена команд (gl*ClientState()), почему нельзя было просто использовать пару glEnable() / glDisable()? Одна из причин заключается в том, что glEnable() / glDisable() могут входить в список отображения, а спецификация вершинных массивов нет, так как данные остаются на клиентской стороне.

Для реализаций OpenGL, поддерживающих расширение мультитекстурирования,

включение и выключение вершинных массивов влияет только на текущий элемент текстуры.

2.7.2 Шаг 2: Указание данных для массивов

Передача данных для вершинных массивов является достаточно прямолинейным процессом. Одна команда задает один массив в пространстве клиента. Существует 6 различных команд для передачи данных в 6 типов массивов. Кроме того, существует команда, позволяющая указать в качестве источника данных для нескольких типов вершинных массивов, один физический перекрестный массив.

void glVertexPointer (Glint size, GLenum type, GLsizei stride, const GLvoid *pointer);

Позволяет указать, где находятся данные для массива вершинных координат. pointer это указатель на область памяти, где содержится первая координата первой вершины. type задает тип данных для каждой координаты в массиве (GL_SHORT, GL_INT, GL_FLOAT или GL_DOUBLE). size количество координат на одну вершину, должен принимать значения 2, 3 или 4. stride промежуток в памяти (в байтах) между первой координатой предыдущей и первой координатой следующей вершины. Если stride равен 0 (специальное значение), считается, что вершины плотно упакованы в памяти.

Для указания данных к другим пяти массивам, существует еще пять похожих команд:

void glColorPointer (Glint size, GLenum type, GLsizei stride, const GLvoid *pointer);

void glIndexPointer (GLenum type, GLsizei stride, const GLvoid *pointer); void glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer); void glTexCoordPointer (Glint size, GLenum type, GLsizei stride, const GLvoid *pointer);

void glEdgeFlagPointer (GLsizei stride, const GLvoid *pointer);

Главное различие этих команд заключается в том, что для каких-то из них необходимо указывать тип данных и количество элементов данных на каждую вершину, а для каких-то нет. Например, у нормали к поверхности всегда три координаты, таким образом, нет смысла указывать число элементов физического массива на одну нормаль. Флаг ребра всегда имеет булевский тип, поэтому нет смысла указывать число и тип

элементов физического массива на каждую вершину. В таблице 2-4 перечислены возможные значения параметров size и type для всех команд загрузки массивов, в которых эти параметры присутствуют, а также значения, принимаемые OpenGL изначально, для команд, где нет этих параметров в явном виде.

Таблица 2-4. Типы и количество элементов (на одну вершину) вершинных массивов

 

Количество

 

Команда

элементов на

Тип элементов

 

вершину

 

glVertexPointer

2,3, 4

GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE

glNormalPointer

не указывается

GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE

всегда 3

 

 

 

 

GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,

glColorPointer

3, 4

GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT,

 

 

GL_FLOAT, GL_DOUBLE

glIndexPointer

не указывается

GL_UNSIGNED_BYTE, GL_SHORT, GL_INT, GL_FLOAT,

всегда 1

GL_DOUBLE

 

glTexCoordPointer

1, 2, 3, 4

GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE

glEdgeFlagPointer

не указывается

не указывается всегда булевский тип

 

всегда 1

 

Для реализаций OpenGL, поддерживающих мультитекстурирование, указание массива

координат текстуры с помощью glTexCoordPointer() влияет только на текущий элемент текстуры.

В примере 2-9 вершинные массивы используются одновременно для хранения координат вершин и их цветов в режиме RGBA. Значения с плавающей точкой для RGB

цветов и соответствующие им целые координаты вершин (x, y) загружаются в

GL_COLOR_ARRAY (массив цветов в режиме RGBA) и GL_VERTEX_ARRAY (массив координат вершин).

Пример 2-9. Включение и загрузка вершинных массивов

GLint vertices[]= {25, 25, 100, 325, 175, 25, 175, 325, 250, 25, 325, 325};

GLfloat colors[]= {1.0, 0.2, 0.2, 0.2, 0.2, 1.0, 0.8, 1.0, 0.2, 0.75, 0.75, 0.75, 0.35, 0.35, 0.35, 0.5, 0.5, 0.5};

glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);

glColorPointer(3,GL_FLOAT, 0, colors); glVertexPointer(2,GL_INT, 0, vertices);

2.7.2.1Смещение

Параметр stride команд gl*Pointer() говорит OpenGL, как получать доступ к данным предоставляемого вами физического массива. Этот параметр должен быть равен числу байт памяти между первым элементом массива, относящимся к предыдущей вершине, и первым элементом, относящимся к следующей вершине. Кроме того, параметр может быть равен 0 – эта величина имеет специальное назначение. Например, предположим, что вы сохранили RGB – цвета вершин и их координаты (x, y, z) в одном физическом массиве:

GLfloat interwined[]={

1.0, 0.2, 1.0, 100.0, 100.0, 0.0, 1.0, 0.2, 0.2, 0.0, 200.0, 0.0, 1.0, 1.0, 0.2, 100.0, 300.0, 0.0, 0.2, 1.0, 0.2, 200.0, 300.0, 0.0, 0.2, 1.0, 1.0, 300.0, 200.0, 0.0, 0.2, 0.2, 1.0, 200.0, 100.0, 0.0};

Замечание: Важно четко понимать разницу между физическим массивом и вершинным массивом. Физический массив представляет собой некоторый диапазон памяти, где хранится некоторое количество элементов одинакового типа. Например, вы можете объявить массив типа GLubyte. Элементом массива при этом считается одна величина указанного при объявлении типа. Любой же вершинный массив – понятие, не связанное прямо с физической памятью компьютера, поскольку любая реализация OpenGL может реализовывать вершинные массивы тем способом, который ее разработчики, считают эффективным. Кроме того, элементом любого вершинного массива считаются все данные, относящиеся к одной вершине, независимо от реального типа этих данных и количества компонент. Например, в качестве источника данных для вершинного массива RGB-цветов вы можете задать объявленный и определенный ранее физический массив типа GLubyte. Если вы укажете, что каждый цвет состоит из трех компонент, то одним элементом вершинного массива RGB – цветов будут считаться 3 байта, определяющих эти компоненты для одной вершины. То есть в данном случае одним элементом вершинного массива являются 3 элемента физического массива. Более того, источник данных для вершинных массивов может и не являться физическим массивом с простым типом элементов. Можно объявить массив сложных структур и использовать его. В общем случае, описываемый здесь Шаг 2 как раз и нужен для того, чтобы указать OpenGL, откуда брать данные для вершинных массивов и как их трактовать.

Чтобы сослаться только на цветовые значения массива interwined, следующий вызов начинает забирать данные из начала массива (указатель на которое передается в виде &interwined[0]), затем сдвигается на 6*sizeof(GLfloat), что является размером в байтах трех компонент цвета и трех координат одной вершины. Этого прыжка достаточно, чтобы попасть на начало цветовых данных для следующей вершины.

glColorPointer(3,GL_FLOAT,6*sizeof(GLfloat),&interwined[0]);

Для получения координат вершин, необходимо начать с 4-го элемента физического массива interwined (помните, что в C нумерация элементов массива начинается с 0).

glVertexPointer(3,GL_FLOAT, 6*sizeof(GLfloat),&interwined[3]);

Если stride равен 0, считается, что данные плотно упакованы в памяти и массив является гомогенным (или однородным), то есть в нем только цвета, только координаты вершин, только нормали и так далее.

2.7.3 Шаг 3: Разрешение данных

До тех пор, пока не произошло разрешение данных вершинных массивов, они остаются на клиентской стороне и можно легко менять их содержимое. На третьем шаге

данные извлекаются из массивов и отправляются на сервер и далее обрабатываются конвейером визуализации.

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

2.7.3.1Разрешение одного элемента массива

void glArrayElement (Glint ith);

Извлекает данные для одной вершины с индексом ith из всех включенных в текущий момент массивов. Для массива с координатами вершин соответствующей сгенерированной командой будет glVertex[size][type]v(), где size будет равен 2, 3 или

4, а type – s, i, f или d (для GLshort, Glint, GLfloat и GLdouble соответственно). И size, и type были ранее определены вызовом glVertexPointer(). Для других типов массивов вызов glArrayElement() приведет к генерации команд glEdgeFlagv(), glTexCoord[size][type]v(), glColor[size][type]v(), glIndex[type]v() и glNormal[type]v(). Если включен массив вершинных координат, команда glVertex*v() будет вызвана последней, после исполнения до пяти других команд, если включены соответствующие массивы.

Обычно glArrayElement() вызывается между командами glBegin() и glEnd() (если glArrayElement() вызывается за пределами этих командных скобок, он устанавливает текущее значение для всех переменных состояния, соответствующих включенным массивам, например, текущий цвет, текущий вектор нормали и так далее; если при этом включен массив вершинных координат, то его данные ни на что не влияют, поскольку не существует понятия текущей вершины). В примере 2-10 треугольник рисуется с помощью данных, относящихся к третьей, четвертой и шестой вершинам (следует опять-таки помнить, что в языке C нумерация массивов начинается с 0).

Пример 2-10. Использование glArrayElement() для задания координат вершин и их

цветов

glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);

glColorPointer(3,GL_FLOAT,0,colors); glVertexPointer(2,GL_INT,0,vertices);

glBegin(GL_TRIANGLES); glArrayElement(2); glArrayElement(3); glArrayElement(5);

glEnd();

В период выполнения последние пять строк кода будут иметь такой же эффект, как

glBegin(GL_TRIANGLES); glColor3fv(colors+(2*3)); glVertex2iv(vertices+(2*2)); glColor3fv(colors+(3*3)); glVertex2iv(vertices+(3*2)); glColor3fv(colors+(5*3)); glVertex2iv(vertices+(5*2));

glEnd();

Поскольку при использовании glArrayElement() происходит только один вызов на одну вершину, это может сократить общее количество вызовов функций и тем самым увеличить быстродействие.

Имейте в виду, что если содержимое массива изменяется между вызовами glBegin() и glEnd(), нет гарантии, что вы получите оригинальные или измененные данные для запрошенного элемента. Для большей предсказуемости результата не изменяйте данные тех элементов массивов, доступ к которым может понадобиться до завершения примитива.

2.7.3.2Разрешение списка элементов массива

Команду glArrayElement() удобно применять для случайных выборок данных из вершинных массивов. Похожие команды glDrawElements() и glDrawRangeElements() удобны для проведения случайных выборок данных в более упорядоченной манере.

void glDrawElements (GLenum mode, GLsizei count, GLenum type, void *indices);

Определяет последовательность геометрических примитивов, используя count элементов вершинных массивов, индексы которых находятся в массиве indices. type

может принимать значение GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT или

GL_UNSIGNED_INT, задавая тип данных в массиве indices. Параметр mode указывает, какие примитивы следует построить, и может принимать те же значения, что и единственный параметр glBegin(), например GL_POLYGON, GL_LINE_LOOP, GL_LINES, GL_POINTS и так далее.

Эффект от вызова glDrawElements() практически то же, что и от следующей последовательности команд:

int i; glBegin(mode);

for(i=0;i<COUNT;I++)

glArrayElement(indices[i]);

glEnd();

В дополнение glDrawElements() проверяет mode, count и type на корректность значений. Также, в отличие от предыдущих строк, вызов glDrawElements() оставляет некоторые переменные в неопределенном состоянии. После исполнения glDrawElements() текущие RGB – цвет, цветовой индекс, координаты нормали, координаты текстуры и флаг ребра не определены (или неизвестны, непредсказуемы) если во время вызова были включены соответствующие массивы.

При использовании glDrawElements() индексы всех вершин каждой грани куба могут быть помещены в массив индексов. Пример 2-11 демонстрирует два пути использования glDrawElements() для визуализации куба. На рисунке 2-16 показана нумерация вершин, используемая в примере 2-11.

Рисунок 2-16. Куб с пронумерованными вершинами

Пример 2-11. Два способа использования glDrawElements()

GLubyte frontIndices[] = {4,5,6,7};

GLubyte rightIndices[] = {1,2,6,5};

GLubyte bottomIndices[] = {0,1,5,4};

GLubyte backIndices[] = {0,3,2,1};

GLubyte leftIndices[] = {0,4,7,3};

GLubyte topIndices[] = {2,3,7,6};

glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,frontIndices); glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,rightIndices); glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,bottomIndices); glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,backIndices); glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,leftIndices); glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,topIndices);

Или другой вариант собираем все индексы вместе:

GLubyte allIndices[] ={4,5,6,7,1,2,6,5, 0,1,5,4,0,3,2,1, 0,4,7,3,2,3,7,6};

glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE,allIndices);

Замечание: Вызов glDrawElements() между glBegin() и glEnd() является ошибкой.

Как и glDrawElements(), команда glDrawRangeElements() удобна для случайной выборки данных из массивов и визуализации этих данных. glDrawRangeElements() также позволяет определить ограничения на диапазон допустимых значений индексов, что может увеличить быстродействие программы. Для оптимального быстродействия, некоторые реализации OpenGL могут еще до визуализации извлекать из вершинных массивов ограниченное количество данных. glDrawRangeElements() позволяет указать диапазон вершин, который будет кэширован таким образом.

void glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void *indices);

Создает последовательность геометрических примитивов, так же как и glDrawElements(), однако накладывает дополнительные ограничения на значения принимаемых параметров. Часть параметров glDrawRangeElements(), включая mode (тип примитивов), count (количество элементов), type (тип данных) и indices (массив индексов), имеет то же значение, что и аналогичные параметры glDrawElements(). В glDrawRangeElements() присутствуют еще два параметра: start и end, которые указывают диапазон допустимых значений для indices. Для того, чтобы быть допустимыми, значения элементов массива indices должны лежать в диапазоне между start и end включительно.

Указание в массиве indices значений индексов вне диапазона [start, end] является ошибкой. Однако реализация OpenGL не обязательно обнаруживает эту ошибку или рапортует о ней. То есть, недопустимая величина индекса может генерировать ошибку OpenGL, а может и нет. Что будет происходить в каждом конкретном случае, зависит от каждой конкретной реализации.

Вы можете использовать glGetIntegerv() с параметрами GL_MAX_ELEMENTS_VERTICES и GL_MAX_ELEMENTS_INDICES для того, чтобы выяснить, соответственно,

рекомендуемые максимум количества кэшируемых вершин и максимальное количество индексов (то есть общее количество вершин, которые должны быть визуализированы). Если end-start+1 больше, чем рекомендованный максимум кэшируемых вершин, или если count больше рекомендуемого максимума индексов, glDrawRangeElements() должна по-прежнему работать корректно, но быстродействие может быть снижено.

Не является обязательной ссылка на все вершины из диапазона [start, end]. Однако

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

Возможно, что при использовании glArrayElements(), glDrawElements() и glDrawRangeElements(), ваша реализация OpenGL кэширует недавно обработанные (то есть преобразованные, освещенные и так далее) вершины, позволяя вашему приложению повторно использовать их, не передавая их на конвейер визуализации еще раз. Например, означенный выше куб состоит из 6-ти граней (полигонов) и всего 8-ти вершин. Каждая вершина используется 3-мя гранями. Без команд gl*Elements() визуализация всех 6-ти граней потребовала бы обработки 24-х вершин, несмотря на то, что обработка 16-ти из них являлась бы избыточной. Ваша реализация OpenGL может минимизировать избыточную обработку, визуализировав всего 8 вершин. (Повторное использование вершин может быть ограничено всеми вершинами, указанными в одном вызове glDrawElements() или glDrawRangeElements(), или в случае glArrayElement(), всеми вершинами, указанными внутри одного блока glBegin()/glEnd().)

2.7.3.3 Разрешение последовательности элементов массива

В отличие от команд glArrayElements(), glDrawElements() и glDrawRangeElements(), позволяющих осуществлять случайную выборку элементов вершинных массивов, команда glDrawArrays() осуществляет последовательную выборку.

void glDrawArrays (GLenum mode, Glint first, GLsizei count);

Конструирует последовательность геометрических примитивов, используя элементы включенных вершинных массивов, начиная с индекса first и заканчивая индексом first+count-1. Параметр mode указывает, какие примитивы следует построить, и может принимать те же значения, что и единственный параметр glBegin(), например

GL_POLYGON, GL_LINE_LOOP, GL_LINES, GL_POINTS и так далее.

Эффект от вызова glDrawArrays() аналогичен следующей последовательности команд:

int i; glBegin(mode);

for(i=0;i<COUNT;I++)

glArrayElement(first+i);

glEnd();

Как и glDrawElements(), glDrawArrays() производит проверку значений своих параметров на допустимость и оставляет текущие RGB-цвет, цветовой индекс, координаты нормали, координаты текстуры и флаг ребра в неопределенном состоянии, если соответствующий массив был включен во время ее вызова.

2.7.4 Смешанные массивы

Дополнительно: Ранее мы рассматривали специальный случай смешанного массива. Тогда в массиве interwined чередовались данные RGB цветов и 3D – координат вершин. Доступ к ним был получен с помощью команд glColorPointer() и glVertexPointer() и правильного выбора значений параметра stride.

GLfloat interwined[]={1.0, 0.2, 1.0, 100.0, 100.0, 0.0, 1.0, 0.2, 0.2, 0.0, 200.0, 0.0, 1.0, 1.0, 0.2, 100.0, 300.0, 0.0, 0.2, 1.0, 0.2, 200.0, 300.0, 0.0,

0.2, 1.0, 1.0, 300.0, 200.0, 0.0, 0.2, 0.2, 1.0, 200.0, 100.0, 0.0};

Существует также команда glInterleavedArrays(), которая позволяет задавать несколько вершинных массивов за один вызов. Кроме того, glInterleavedArrays() включает и выключает выбранные массивы, таким образом, объединяя действия на Шаге 1: Включение массивов и Шаге 2: Указание данных для массивов. На самом деле массив interwined отвечает одной из 14 возможных конфигураций данных смешанных массивов, поддерживаемых glInterleavedArrays(). Таким образом, для того, чтобы использовать данные interwined в массиве RGB-цветов и массиве координат вершин, а также для включения обоих этих массивов, вызовите:

glInterleavedArrays(GL_C3F_V3F, 0, interwined);

Этот вызов glInterleavedArrays() включает массивы GL_COLOR_ARRAY и GL_VERTEX_ARRAY и выключает массивы GL_INDEX_ARRAY, GL_TEXTURE_COORD_ARRAY, GL_NORMAL_ARRAY и GL_EDGE_FLAG_ARRAY.

Кроме того, эта строка имеет тот же эффект, что и вызовы glColorPointer() и glVertexPointer(), задающие значения для шести вершин в каждом из указанных включаемых массивов. После этого можно переходить к Шагу 3, вызывая glArrayElement(), glDrawElements(), glDrawRangeElements() или glDrawArrays()

для разрешения данных массивов.

void glInterleavedArrays (GLenum format, GLsizei stride, void *pointer);

Инициализирует все шесть вершинных массивов, выключая не указанные и включая указанные в параметре format. Параметр format должен быть равен одной из 14 символических констант, соответствующих 14 конфигурациям данных. Значения format и их смысл перечислены в таблице 2-5. Параметр stride позволяет указать байтовое смещение между данными смежных вершин. Если stride равен 0, считается, что вершинные данные плотно упакованы в массиве. Параметр pointer это адрес памяти, где хранится первый элемент данных физического массива, относящийся к первой вершине (указатель на начало физического массива в памяти).

Для реализаций OpenGL, поддерживающих расширение мультитекстурирования glInterleavedArrays() влияет только на активный элемент текстуры.

Заметьте, что glInterleavedArrays() не поддерживает флаги ребра.

Объяснение механики glInterleavedArrays() достаточно сложно и требует ссылок на пример 2-12 и таблицу 2-5. В этих примере и таблице, вы увидите несколько переменных. Переменные et, ec и en, содержат булевские значения и представляют

соответственно включенное или выключенное состояние массивов текстурных координат, цвета и координат нормалей. Переменные st, sc и sv представляют собой размеры (количество компонент) одного элемента в массивах координат текстуры, цвета и координат вершин соответственно. tc представляет собой тип данных для RGBA

цвета, поскольку это единственный массив, который при применении glInterleavedArrays() может содержать недробные значения. pc, pn и pv представляют собой вычисленные значения смещения (в байтах) от начала данных в физическом массиве, относящихся к определенной вершине, до начала значений цвета, координат нормали и самих координат той же вершины, а s -- это вычисленное смещение между началом данных физического массива, относящихся к предыдущей вершине и началом данных, относящихся к следующей за ней вершиной (применяется в том случае, если пользователь не указал свое смещение).

Эффект от вызова glInterleavedArrays() аналогичен эффекту от выполнения последовательности команд в примере 2-12. Для простоты понимания считайте et, ec, en, st, sc, sv, tc, pc, pn, pv и s функциями значений параметра format, перечисленных в таблице 2-5. Вся векторная арифметика производится в единицах равных sizeof(GLubyte) байт (теоретически это не обязательно 1 байт).

Пример 2-12. Эффект от вызова glInterleavedArrays(format, stride, pointer)

int str;

str=stride;

if(str==0)

str=s;

glDisableClientState(GL_EDGE_FLAG_ARRAY); glDisableClientState(GL_INDEX_ARRAY);

if (et)

{

glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(st,GL_FLOAT,str,pointer);

}

else glDisableClientState(GL_TEXTURE_COORD_ARRAY);

if (ec)

{

glEnableClientState(GL_COLOR_ARRAY); glColorPointer(sc, tc, str,pointer+pc);

}

else glDisableClientState(GL_COLOR_ARRAY);

if (en)

{

glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT,str,pointer+pn);

}

else glDisableClientState(GL_NORMAL_ARRAY);

glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(sv, GL_FLOAT,str,pointer+pv);

В таблице 2-5, T и F соответствуют True и False. f равно sizeof(GLfloat). с – sizeof(GLubyte)*4 (округленному до ближайшего произведения f, если необходимо).

Таблица 2-5. Конфигурации данных, поддерживаемые командой glInterleavedArrays()

Format

et

ec

en

st

sc

sv

tc

pc

pn

pv

s

GL_V2F

F

F

F

 

 

2

 

 

 

0

2f

GL_V3F

F

F

F

 

 

3

 

 

 

0

3f

GL_C4UB_V2F

F

T

F

 

4

2

GL_UNSIGNED_BYTE

0

 

c

c+2f

GL_C4UB_V3F

F

T

F

 

4

3

GL_UNSIGNED_BYTE

0

 

c

c+3f

GL_C3F_V3F

F

T

F

 

3

3

GL_FLOAT

0

 

3f

6f

GL_N3F_V3F

F

F

T

 

 

3

 

 

0

3f

6f

GL_C4F_N3F_V3F

F

T

T

 

4

3

GL_FLOAT

0

4f

7f

10f

GL_T2F_V3F

T

F

F

2

 

3

 

 

 

2f

5f

GL_T4F_V4F

T

F

F

4

 

4

 

 

 

4f

8f

GL_T2F_C4UB_V3F

T

T

F

2

4

3

GL_UNSIGNED_BYTE

2f

 

c+2f

c+5f

GL_T2F_C3F_V3F

T

T

F

2

3

3

GL_FLOAT

2f

 

5f

8f

GL_T2F_N3F_V3F

T

F

T

2

 

3

 

 

2f

5f

8f

GL_T2F_C4F_N3F_V3F

T

T

T

2

4

3

GL_FLOAT

2f

6f

9f

12f

GL_T4F_C4F_N3F_V4F

T

T

T

4

4

4

GL_FLOAT

4f

8f

11f

15f

 

 

 

 

 

 

 

 

 

 

 

 

Начинайте с использования простых форматов, таких как GL_V2F, GL_V3F или GL_C3F_V3F. Если вы хотите использовать форматы, включающие C4UB – часть, возможно, что для упаковки 4 беззнаковых байтов в одно 32-битовое слово вам придется использовать структурные типы данных, приведение типов или арифметику над указателями.

В некоторых реализациях OpenGL использование смешанных массивов может увеличить быстродействие приложения. При использовании смешанных массивов известен точный формат ваших данных. Вы точно знаете, что ваши данные плотно упакованы, и доступ к ним может быть произведен очень быстро. Без использования смешанных массивов, информация о смещениях и размерах должна дополнительно проверяться, чтобы обнаружить, плотно ли данные упакованы в памяти.

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

3: Разрешение данных и вызвать glArrayElement(), glDrawElements(), glDrawRangeElements() или glDrawArrays() для разрешения указателей и визуализации графики.

2.8 Группы атрибутов

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

OpenGL объединяет связанные по смыслу переменные состояния в группы атрибутов. Например, группа атрибутов GL_LINE_BIT состоит из 5 переменных состояния: толщины линии, статуса механизма шаблонирования линии GL_LINE_STIPPLE, рисунка шаблона линии, счетчика повтора шаблона и статуса механизма сглаживания линий

GL_LINE_SMOOTH. С помощью команд glPushAttrib() и glPopAttrib() вы можете

сохранять и восстанавливать значения всех этих пяти переменных состояния одновременно.

Некоторые переменные состояния относятся более чем к одной группе атрибутов. Например, переменная состояния GL_CULL_FACE является одновременно частью группы атрибутов полигона и группы включенных атрибутов.

В OpenGL версии 1.1 существует два различных стека атрибутов. В добавление к старому стеку (в котором сохраняются и из которого восстанавливаются переменные состояния сервера), существует также стек атрибутов клиента, доступ к которому можно получить посредством команд glPushClientAttrib() и glPopClientAttrib().

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

атрибутов для сохранения и восстановления должны быть переданы по сетевому соединению и обратно. Однако OpenGL имеет стек атрибутов на самом сервере, что позволяет избежать ненужных сетевых задержек.

Существует около 20 различных групп атрибутов, которые могут быть сохранены и восстановлены командами glPushAttrib() и glPopAttrib(). Также существует 2 клиентские группы, сохраняемые и восстанавливаемые командами glPushClientAttrib() и glPopClientAttrib(). И на сервере, и на клиенте атрибуты сохраняются в стеке, глубина которого должна быть достаточной для сохранения как минимум 16 групп атрибутов (Реальная глубина стеков в вашей реализации OpenGL может быть получена с помощью параметров GL_MAX_ATTRIB_STACK_DEPTH и

Соседние файлы в предмете Компьютерная Графика