Массивы вершин, нормалей и цветов
Неэффективность алгоритма последовательного рисования большого числа примитивов не является тайной для тех, кто имеет дело с трехмерной графикой. Поэтому в технологии OpenGL существует ряд приемов (поддержанных функциями), которые основаны на использовании заранее заготовленных массивов, а также списков команд OpenGL. Они значительно повышают эффективность работы конвейера при передаче (rendering) изображений, составленных из десятков и сотен тысяч примитивов. Например, функция glDrawElements позволяет задать геометрические примитивы экономичным способом, то есть с минимальными затратами на вызовы функций.
До сих пор мы вызывали в среднем 4-5 функций для каждого треугольника. При этом многократно повторялись, так как вершины, общие для смежных треугольников, задавались не один раз. Массивы величин, ассоциируемых с вершинами (координаты, нормали, цвета и другие), могут быть сформированы заранее и использованы при описании геометрии с помощью массива индексов. Функция glDrawElements требует в качестве одного из параметров массив индексов вершин полигонов. Вот ее прототип:
void glDrawElements (GLenum mode, GLsizei count, GLenum type, <strong>const</strong> GLvoid *indices);
Функция конструирует count элементов типа mode. Параметр indices должен содержать адрес массива индексов, который формируется заранее. Параметр type определяет тип элементов массива indices. Он может принимать одно из трех фиксированных значений:
- GL_UNSIGNED_BYTE (используется 8-битовый индекс),
- GL_UNSIGNED_SHORT (16-биТНЫЙ ИНДСКС),
- GL_UNSIGNED_INT (32-биТНЫЙ).
Характерной особенностью рассматриваемой технологии является то, что величины, ассоциируемые с каждой вершиной примитива, могут храниться в разных массивах или в одном массиве структур с разными полями. Они задаются с помощью 6 функций:
- GIVertexPointer – задает адрес массива координат вершин;
- GINormalPointer – задает адрес массива нормалей в вершинах;
- GlColorPointer – задает адрес массива цветов, связанных с вершинами;
- GlTexCoordPointer – задает адрес массива координат текстуры материала, задаваемой в вершинах;
- GlEdgeFlagPointer – задает адрес массива флагов видимости линий, исходящих из вершины;
- GllndexPointer – задает адрес массива цветовых индексов вершин в режиме цветовой палитры, а не RGBA.
Другой массив индексов – indices, определяет порядок выбора элементов из этих шести массивов. Но этого мало – надо произвести еще некоторые настройки в машине состояний OpenGL. Для перевода ее в режим использования массивов надо несколько раз вызвать функцию glEnableClientstate. Каждый вызов включает один из шести рассмотренных режимов. Только после этого функция glDrawElements способна эффективно задать сразу все примитивы. Например, вызов:
glEnableClientState(GL_VERTEX_ARRAY);
Включает режим использования массива координат вершин, а вызов этой же функции с параметром GL_NORMAL_ARRAY включает использование массива нормалей.
Совместно с командой glDrawElements обычно используют тот способ повышения эффективности отображения примитивов, который мы уже используем. Речь идет о паре функций: glNewList, glEndList. Все команды OpenGL, заданные между вызовами этих двух функций, оптимизируются, компилируются (по выбору) и запоминаются в отдельном нумеруемом списке.