Методы наиболее успешной практики для работы с данными вершины
Сложные формы и подробные 3D модели требуют, чтобы большие суммы данных вершины описали их в OpenGL. Движущиеся данные вершины с Вашего приложения на аппаратное обеспечение машинной графики несут расходы производительности, которые могут быть довольно большими в зависимости от размера набора данных.
Приложения, использующие большие наборы данных вершины, могут принять один или больше стратегий, описанных в Стратегиях Проектирования приложений OpenGL оптимизировать, как данные вершины поставлены главе OpenGL.This, подробно останавливается на тех методах наиболее успешной практики с определенными методами для работы с данными вершины.
Поймите как потоки данных вершины через OpenGL
Понимание, как потоки данных вершины через OpenGL важны для выбора стратегий обработки данных. Данные вершины вводят в этап вершины, где это обрабатывается или встроенным этапом вершины стандартной функции или пользовательской вершиной.
Рисунок 10-3 бросает более внимательный взгляд на канал передачи данных вершины при использовании непосредственного режима. Без любой оптимизации Ваши данные вершины могут быть скопированы в различных точках в канале передачи данных. Если Ваше приложение использует непосредственный режим для каждой вершины отдельно, вызовы к OpenGL сначала изменяют текущую вершину, копирующуюся в буфер команд каждый раз, когда Ваше приложение делает a glVertex*
вызвать. Это не только дорого с точки зрения операций копии, но также и в функции наверху для указания каждой вершины.
Команды OpenGL glDrawRangeElements
, glDrawElements
, и glDrawArrays
представьте многократные геометрические примитивы от данных массива, с помощью очень немногих вызовов подпрограммы. Перечисление 10-1 показывает типичную реализацию. Ваше приложение создает структуру вершины, содержащую все элементы для каждой вершины. Для каждого элемента Вы включаете клиентский массив и обеспечиваете указатель и смещаете к OpenGL так, чтобы это знало, как найти те элементы.
Перечисление 10-1 , Представляющее использование данных вершины glDrawElements
.
typedef struct _vertexStruct |
{ |
GLfloat position[2]; |
GLubyte color[4]; |
} vertexStruct; |
void DrawGeometry() |
{ |
const vertexStruct vertices[] = {...}; |
const GLubyte indices[] = {...}; |
glEnableClientState(GL_VERTEX_ARRAY); |
glVertexPointer(2, GL_FLOAT, sizeof(vertexStruct), &vertices[0].position); |
glEnableClientState(GL_COLOR_ARRAY); |
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertexStruct), &vertices[0].color); |
glDrawElements(GL_TRIANGLE_STRIP, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, indices); |
} |
Каждый раз Вы вызываете glDrawElements
, OpenGL должен скопировать все данные вершины в буфер команд, позже копирующийся в аппаратные средства. Копия наверху является все еще дорогой.
Методы для обработки данных вершины
Предотвращение ненужных копий Ваших данных вершины критически важно по отношению к производительности приложения. Этот раздел суммирует общие методы для управления Вашими данными вершины с помощью или встроенной функциональности или расширений OpenGL. Перед использованием этих методов необходимо гарантировать, что необходимые функции доступны приложению. Посмотрите Функциональность Обнаружения.
Избегите использования
glBegin
иglEnd
указать Ваши данные вершины. Функция и копирование наверху делают этот путь полезным только для очень небольших наборов данных. Кроме того, приложения, записанные сglBegin
иglEnd
не являются переносимыми на OpenGL ES на iOS.Минимизируйте преобразования типа данных поставляющими типами данных OpenGL для данных вершины. Использовать
GLfloat
,GLshort
, илиGLubyte
типы данных, потому что большинство графических процессоров обрабатывает эти типы исходно. Если Вы используете некоторый другой тип, то OpenGL, возможно, должен выполнить дорогостоящее преобразование данных.Предпочтительный способ управлять Вашими данными вершины с буферными объектами вершины. Буферные объекты вершины являются буферами, принадлежавшими OpenGL, которые содержат Вашу информацию о вершине. Эти буферы позволяют OpenGL помещать Ваши данные вершины в память, которая доступна для аппаратного обеспечения машинной графики. Посмотрите Буферы Вершины для получения дополнительной информации.
Если буферные объекты вершины не доступны, Ваше приложение может искать
GL_APPLE_vertex_array_range
иAPPLE_fence
расширения. Диапазоны массива вершины позволяют Вам препятствовать тому, чтобы OpenGL копировал Ваши данные вершины в буфер команд. Вместо этого Ваше приложение должно избежать изменять или удалять данные вершины, пока OpenGL не заканчивает выполнять команды рисования. Это решение требует большего усилия от приложения и не совместимо с другими платформами, включая iOS. Посмотрите Расширение диапазона Массива Вершины для получения дополнительной информации.Сложные операции вершины требуют, чтобы много указателей массива были включены и установлены, перед вызовом
glDrawElements
.GL_APPLE_vertex_array_object
расширение позволяет Вашему приложению консолидировать группу указателей массива в отдельный объект. Ваше приложение переключает многократные указатели путем привязки единственного объекта массива вершины, сокращения издержек изменяющегося состояния. Посмотрите Объект Массива Вершины.Используйте двойную буферизацию для сокращения конкуренции ресурса между приложением и OpenGL. Посмотрите Двойную буферизацию Использования для Предотвращения Конфликтов Ресурса.
Если необходимо вычислить новую информацию о вершине между кадрами, рассмотреть использование вершинных шейдеров и буферизовать объекты выполнить и сохранить вычисления.
Буферы вершины
Буферы вершины доступны, поскольку базовая функция, запускающаяся в OpenGL 1.5, и на более ранних версиях OpenGL через буфер вершины, возражает расширению (GL_ARB_vertex_buffer_object
). Буферы вершины используются для улучшения пропускной способности статических или динамических данных вершины в приложении.
Буферный объект является блоком памяти, принадлежавшей OpenGL. Ваше приложение читает из или пишет в буфер с помощью вызовов OpenGL такой как glBufferData
, glBufferSubData
, и glGetBufferSubData
. Ваше приложение может также получить указатель на эту память, работа, называемая отображением буфера. OpenGL предотвращает Ваше приложение и его от одновременного использования данных, хранивших в буфере. Когда Ваше приложение отображает буфер или пытается изменить его, OpenGL может блокировать, пока предыдущие команды рисования не завершились.
Используя буферы вершины
Можно установить и использовать буферы вершины путем выполнения этих шагов:
Вызовите функцию
glGenBuffers
создать новое имя для буферного объекта.void glGenBuffers(sizei n, uint *buffers );
n
число буферов, для которых Вы хотите создать идентификаторы.buffers
указывает указатель на память для хранения буферных имен.Вызовите функцию
glBindBuffer
связывать неиспользованное имя к буферному объекту. После этого вызова недавно создаваемый буферный объект инициализируется с буфером памяти нулевого размера и состояния по умолчанию. (Для настройки по умолчанию посмотрите спецификацию OpenGL для ARB_vertex_buffer_object.)void glBindBuffer(GLenum target, GLuint buffer);
target
должен быть установлен вGL_ARRAY_BUFFER
.buffer
указывает уникальное имя для буферного объекта.Заполните буферный объект путем вызывания функции
glBufferData
. По существу этот вызов загружает Ваши данные на GPU.void glBufferData(GLenum target, sizeiptr size,
const GLvoid *data, GLenum usage);
target
должен быть установлен вGL_ARRAY_BUFFER
.size
указывает размер хранилища данных.*data
точки к исходным данным. Если это неNULL
, исходные данные копируются в данные, хранившие буферного объекта. ЕслиNULL
, содержание хранилища данных не определено.usage
константа, обеспечивающая подсказку относительно того, как Ваше приложение планирует использовать данные, хранившие в буферном объекте. Эти примеры использованиеGL_STREAM_DRAW
, который указывает, что приложение планирует и изменить и нарисовать использование буфера, иGL_STATIC_DRAW
, который указывает, что приложение будет определять данные один раз, но использовать их для рисования много раз. Для получения дополнительной информации на буферных подсказках, посмотрите Буферные Подсказки ИспользованияВключите массив вершины путем вызова
glEnableClientState
и предоставлениеGL_VERTEX_ARRAY
постоянный.Укажите на содержание буферного объекта вершины путем вызывания функции такой как
glVertexPointer
. Вместо того, чтобы обеспечить указатель, Вы обеспечиваете смещение в буферный объект вершины.Обновить данные в буферном объекте, Ваших вызовах приложения
glMapBuffer
. Отображение буфера препятствует тому, чтобы GPU воздействовал на данные и дает Вашему приложению подсказку к памяти, которую это может использовать для обновления буфера.void *glMapBuffer(GLenum target, GLenum access);
target
должен быть установлен вGL_ARRAY_BUFFER
.access
указывает операции, которые Вы планируете выполнить на данных. Можно предоставитьREAD_ONLY
,WRITE_ONLY
, илиREAD_WRITE
.Запишите пиксельные данные в указатель, полученный от вызова до
glMapBuffer
.Когда Ваше приложение закончит изменять содержимое буфера, вызовите функцию
glUnmapBuffer
. Необходимо предоставитьGL_ARRAY_BUFFER
как параметр к этой функции. Как только буфер не отображается, указатель больше не действителен, и содержание буфера загружается снова на GPU.
Перечисление 10-2 показывает код, использующий буферное расширение объекта вершины для динамических данных. Этот пример перезаписывает все данные вершины во время каждой работы получения.
Перечисление 10-2 Используя буфер вершины возражает расширению с динамическими данными
// To set up the vertex buffer object extension |
#define BUFFER_OFFSET(i) ((char*)NULL + (i)) |
glBindBuffer(GL_ARRAY_BUFFER, myBufferName); |
glEnableClientState(GL_VERTEX_ARRAY); |
glVertexPointer(3, GL_FLOAT, stride, BUFFER_OFFSET(0)); |
// When you want to draw using the vertex data |
draw_loop { |
glBufferData(GL_ARRAY_BUFFER, bufferSize, NULL, GL_STREAM_DRAW); |
my_vertex_pointer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); |
GenerateMyDynamicVertexData(my_vertex_pointer); |
glUnmapBuffer(GL_ARRAY_BUFFER); |
PerformDrawing(); |
} |
Перечисление 10-3 показывает код, использующий буферное расширение объекта вершины со статическими данными.
Перечисление 10-3 Используя буфер вершины возражает расширению со статическими данными
// To set up the vertex buffer object extension |
#define BUFFER_OFFSET(i) ((char*)NULL + (i)) |
glBindBuffer(GL_ARRAY_BUFFER, myBufferName); |
glBufferData(GL_ARRAY_BUFFER, bufferSize, NULL, GL_STATIC_DRAW); |
GLvoid* my_vertex_pointer = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); |
GenerateMyStaticVertexData(my_vertex_pointer); |
glUnmapBuffer(GL_ARRAY_BUFFER); |
glEnableClientState(GL_VERTEX_ARRAY); |
glVertexPointer(3, GL_FLOAT, stride, BUFFER_OFFSET(0)); |
// When you want to draw using the vertex data |
draw_loop { |
PerformDrawing(); |
} |
Буферные подсказки использования
Главное преимущество буферных объектов - то, что приложение может предоставить информацию о том, как это использует данные, хранившие в каждом буфере. Например, Перечисление 10-2 и Перечисление 10-3 дифференцировались между случаями, где данные, как ожидали, никогда не изменятся (GL_STATIC_DRAW
) и случаи, где буферные данные могли бы измениться (GL_DYNAMIC_DRAW
). Параметр использования позволяет средству рендеринга OpenGL изменять свою стратегию выделения буфера вершины для улучшения производительности. Например, в то время как динамические буферы могут быть сохранены в оперативной памяти и получены GPU через DMA, статические буферы могут быть выделены непосредственно в памяти GPU.
Если OpenGL необходимо ограничить подсказки использования одним из трех случаев использования, совместимость ES полезна для Вас:
GL_STATIC_DRAW
должен использоваться для данных вершины, указанных один раз и никогда не изменяющихся. Ваше приложение должно создать эти буферы вершины во время инициализации и неоднократно использовать их, пока не закрывается Ваше приложение.GL_DYNAMIC_DRAW
должен использоваться, когда буфер, как ожидают, изменится после того, как он будет создан. Ваше приложение должно все еще выделить эти буферы во время инициализации и периодически обновлять их путем отображения буфера.GL_STREAM_DRAW
используется, когда Ваше приложение должно создать переходную геометрию, представляющуюся и затем отбрасывающуюся. Это является самым полезным, когда Ваше приложение должно динамично изменить данные вершины каждый кадр в пути, который не может быть выполнен в вершинном шейдере. Для использования потокового буфера вершины приложение первоначально заполняет буферное использованиеglBufferData
, тогда альтернативы между рисованием использования буфера и изменением буфера.
Другие константы использования детализированы в буферной спецификации вершины.
Если различные элементы в Вашем формате вершины имеют различные характеристики использования, можно хотеть разделить элементы на одну структуру для каждого образца использования и выделить буфер вершины для каждого. Перечисление 10-4 показывает, как реализовать это. В то время как цветные данные могут быть анимированы в каждом кадре, в этом примере данные позиции, как ожидают, будут тем же в каждом кадре.
Геометрия перечисления 10-4 с различными образцами использования
typedef struct _vertexStatic |
{ |
GLfloat position[2]; |
} vertexStatic; |
typedef struct _vertexDynamic |
{ |
GLubyte color[4]; |
} vertexDynamic; |
// Separate buffers for static and dynamic data. |
GLuint staticBuffer; |
GLuint dynamicBuffer; |
GLuint indexBuffer; |
const vertexStatic staticVertexData[] = {...}; |
vertexDynamic dynamicVertexData[] = {...}; |
const GLubyte indices[] = {...}; |
void CreateBuffers() |
{ |
glGenBuffers(1, &staticBuffer); |
glGenBuffers(1, &dynamicBuffer); |
glGenBuffers(1, &indexBuffer); |
// Static position data |
glBindBuffer(GL_ARRAY_BUFFER, staticBuffer); |
glBufferData(GL_ARRAY_BUFFER, sizeof(staticVertexData), staticVertexData, GL_STATIC_DRAW); |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); |
// Dynamic color data |
// While not shown here, the expectation is that the data in this buffer changes between frames. |
glBindBuffer(GL_ARRAY_BUFFER, dynamicBuffer); |
glBufferData(GL_ARRAY_BUFFER, sizeof(dynamicVertexData), dynamicVertexData, GL_DYNAMIC_DRAW); |
} |
void DrawUsingVertexBuffers() |
{ |
glBindBuffer(GL_ARRAY_BUFFER, staticBuffer); |
glEnableClientState(GL_VERTEX_ARRAY); |
glVertexPointer(2, GL_FLOAT, sizeof(vertexStatic), (void*)offsetof(vertexStatic,position)); |
glBindBuffer(GL_ARRAY_BUFFER, dynamicBuffer); |
glEnableClientState(GL_COLOR_ARRAY); |
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertexDynamic), (void*)offsetof(vertexDynamic,color)); |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); |
glDrawElements(GL_TRIANGLE_STRIP, sizeof(indices)/sizeof(GLubyte), GL_UNSIGNED_BYTE, (void*)0); |
} |
Буферное расширение диапазона сброса
Когда Ваше приложение не отображает буфер вершины, реализация OpenGL может скопировать полное содержание буфера к аппаратному обеспечению машинной графики. Если Ваши изменения приложений только подмножество большого буфера, это неэффективно. APPLE_flush_buffer_range
расширение позволяет Вашему приложению говорить OpenGL точно, который части буфера были изменены, позволив ему отправить только измененным данным в аппаратное обеспечение машинной графики.
Для использования буферного расширения диапазона сброса выполните эти шаги:
Включите буферное расширение сброса путем вызова
glBufferParameteriAPPLE
.glBufferParameteriAPPLE(GL_ARRAY_BUFFER,GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
Это отключает нормальное поведение сбрасывания OpenGL.
Прежде чем Вы не отобразите буфер, необходимо вызвать
glFlushMappedBufferRangeAPPLE
для каждого диапазона буфера, измененного приложением.void glFlushMappedBufferRangeAPPLE(enum target, intptr offset, sizeiptr size);
target
тип изменяемого буфера; для данных вершины этоARRAY_BUFFER
.offset
смещение в буфер для измененных данных.size
длина измененных данных в байтах.Вызвать
glUnmapBuffer
. OpenGL не отображает буфер, но это требуется, чтобы обновлять только части буфера Ваше приложение, явно отмеченное, как изменено.
Для получения дополнительной информации посмотрите спецификацию APPLE_flush_buffer_range.
Расширение диапазона массива вершины
Расширение диапазона массива вершины (APPLE_vertex_array_range
) позволяет Вам определить область памяти для Ваших данных вершины. Драйвер OpenGL может оптимизировать использование памяти путем создания единственной памяти, отображающейся для данных вершины. Можно также обеспечить подсказку относительно того, как должны храниться данные: кэшируемый или совместно использованный. Кэшируемая опция указывает для кэширования данных вершины в видеопамяти. Совместно используемая опция указывает, что данные должны быть отображены в область памяти, позволяющей GPU получать доступ к данным вершины непосредственно с помощью передачи DMA. Эта опция является лучшей для динамических данных. При использовании общей памяти Вам будут нужны к двойному буферу Ваши данные.
Можно установить и использовать расширение диапазона массива вершины путем выполнения этих шагов:
Включите расширение путем вызова
glEnableClientState
и предоставлениеGL_VERTEX_ARRAY_RANGE_APPLE
постоянный.Выделите хранение для данных вершины. Вы ответственны за поддержание хранения для данных.
Определите массив данных вершины путем вызывания функции такой как
glVertexPointer
. Необходимо предоставить указатель на данные.Дополнительно установите подсказку об обработке хранения данных массива путем вызывания функции
glVertexArrayParameteriAPPLE
.GLvoid glVertexArrayParameteriAPPLE(GLenum pname, GLint param);
pname
должен бытьVERTEX_ARRAY_STORAGE_HINT_APPLE
.param
подсказка, указывающая, как Ваше приложение ожидает использовать данные. OpenGL использует эту подсказку для оптимизации производительности. Можно предоставить такжеSTORAGE_SHARED_APPLE
илиSTORAGE_CACHED_APPLE
. Значение по умолчаниюSTORAGE_SHARED_APPLE
, который указывает, что данные вершины являются динамичными и что OpenGL должен использовать методы оптимизации и сбрасывания, подходящие для этого вида данных. Если Вы ожидаете, что данные, которыми снабжают, будут статичны, использоватьSTORAGE_CACHED_APPLE
так, чтобы OpenGL мог оптимизировать соответственно.Вызовите функцию OpenGL
glVertexArrayRangeAPPLE
установить набор данных.void glVertexArrayRangeAPPLE(GLsizei length, GLvoid *pointer);
length
указывает длину диапазона массива вершины. Длина обычно является числом байтов без знака.*pointer
точки к основе вершины выстраивают диапазон.Нарисуйте с данными вершины с помощью стандартных команд массива вершины OpenGL.
Если необходимо изменить данные вершины, установить объект предела после представления всех команд рисования. Посмотрите Пределы Использования для Синхронизации с более прекрасными зернами
Выполните другую работу так, чтобы GPU имел время для обработки команд рисования, использующих массив вершины.
Вызвать
glFinishFenceAPPLE
получить доступ к массиву вершины.Измените данные в массиве вершины.
Вызвать
glFlushVertexArrayRangeAPPLE
.void glFlushVertexArrayRangeAPPLE(GLsizei length, GLvoid *pointer);
length
указывает длину диапазона массива вершины, в байтах.*pointer
точки к основе вершины выстраивают диапазон.Для динамических данных, каждый раз, когда Вы изменяете данные, необходимо поддержать синхронность путем вызова
glFlushVertexArrayRangeAPPLE
. Вы предоставляете как параметры размер массива и указатель на массив, который может быть подмножеством данных, пока это включает все изменившиеся данные. Вопреки имени функции,glFlushVertexArrayRangeAPPLE
фактически не сбрасывает данные как функция OpenGLglFlush
делает. Это просто делает OpenGL знающим, что изменились данные.
Перечисление 10-5 показывает код, устанавливающий и использующий расширение диапазона массива вершины с динамическими данными. Это перезаписывает все данные вершины во время каждой итерации через цикл получения. Вызов к glFinishFenceAPPLE
команда гарантирует, что CPU и GPU не получают доступ к данным одновременно. Несмотря на то, что этот пример вызывает glFinishFenceAPPLE
функционируйте почти сразу после установки предела, в действительности необходимо разделить эти вызовы для разрешения параллельной работы GPU и CPU. Чтобы видеть, как это сделано, считайте Двойную буферизацию Использования для Предотвращения Конфликтов Ресурса.
Перечисление 10-5 Используя вершину выстраивает расширение диапазона с динамическими данными
// To set up the vertex array range extension |
glVertexArrayParameteriAPPLE(GL_VERTEX_ARRAY_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); |
glVertexArrayRangeAPPLE(buffer_size, my_vertex_pointer); |
glEnableClientState(GL_VERTEX_ARRAY_RANGE_APPLE); |
glEnableClientState(GL_VERTEX_ARRAY); |
glVertexPointer(3, GL_FLOAT, 0, my_vertex_pointer); |
glSetFenceAPPLE(my_fence); |
// When you want to draw using the vertex data |
draw_loop { |
glFinishFenceAPPLE(my_fence); |
GenerateMyDynamicVertexData(my_vertex_pointer); |
glFlushVertexArrayRangeAPPLE(buffer_size, my_vertex_pointer); |
PerformDrawing(); |
glSetFenceAPPLE(my_fence); |
} |
Перечисление 10-6 показывает код, использующий расширение диапазона массива вершины со статическими данными. В отличие от установки для динамических данных, установка для статических данных включает использование подсказки для кэшированных данных. Поскольку данные статичны, является ненужным установить предел.
Перечисление 10-6 Используя вершину выстраивает расширение диапазона со статическими данными
// To set up the vertex array range extension |
GenerateMyStaticVertexData(my_vertex_pointer); |
glVertexArrayParameteriAPPLE(GL_VERTEX_ARRAY_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE); |
glVertexArrayRangeAPPLE(array_size, my_vertex_pointer); |
glEnableClientState(GL_VERTEX_ARRAY_RANGE_APPLE); |
glEnableClientState(GL_VERTEX_ARRAY); |
glVertexPointer(3, GL_FLOAT, stride, my_vertex_pointer); |
// When you want to draw using the vertex data |
draw_loop { |
PerformDrawing(); |
} |
Для получения дальнейшей информации на этом расширении, посмотрите, что спецификация OpenGL для вершины выстраивает расширение диапазона.
Объект массива вершины
Посмотрите на DrawUsingVertexBuffers
функция в Перечислении 10-4. Это конфигурирует буферные указатели для позиции, цвета, и индексирующий перед вызовом glDrawElements
. Более сложная структура вершины может потребовать, чтобы дополнительные буферные указатели были включены и изменены, прежде чем можно будет наконец нарисовать геометрию. Если Ваше приложение часто подкачивает между многократными конфигурациями элементов, изменение этих параметров добавляет значительные издержки к Вашему приложению. APPLE_vertex_array_object
расширение позволяет Вам комбинировать набор буферных указателей в единственный объект OpenGL, позволяя Вам изменить все буферные указатели путем привязки различного объекта массива вершины.
Для использования этого расширения выполните эти шаги во время подпрограмм инициализации приложения:
Генерируйте объект массива вершины для конфигурации указателей, которые Вы хотите использовать вместе.
void glGenVertexArraysAPPLE(sizei n, const uint *arrays);
n
число массивов, для которых Вы хотите создать идентификаторы.arrays
указывает указатель на память для хранения имен массива.glGenVertexArraysAPPLE(1,&myArrayObject);
Свяжите объект массива вершины, который что Вы хотите сконфигурировать.
void glBindVertexArrayAPPLE(uint array);
array
идентификатор для массива, из которого Вы получилиglGenVertexArraysAPPLE
.glBindVertexArrayAPPLE(myArrayObject);
Вызовите подпрограммы указателя (
glColorPointer
и т.д.), что Вы обычно вызывали бы в своем цикле рендеринга. Когда объект массива вершины связывается, эти вызовы изменяют в настоящее время связанный объект массива вершины вместо состояния OpenGL по умолчанию.glBindBuffer(GL_ARRAY_BUFFER, staticBuffer);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(vertexStatic), (void*)offsetof(vertexStatic,position));
...
Повторите предыдущие шаги для каждой конфигурации указателей вершины.
В Вашем цикле рендеринга замените вызовы для конфигурирования указателей массива с вызовом для привязки объекта массива вершины.
glBindVertexArrayAPPLE(myArrayObject);
glDrawArrays(...);
Если необходимо возвратиться к поведению OpenGL по умолчанию, вызвать
glBindVertexArrayAPPLE
и передача в0
.glBindVertexArrayAPPLE(0);