Вы не должны рисовать отдельные примитивы, используя glDrawArrays, но большие партии. Пока вы используете только обычные вершинные массивы, а не объекты буфера вершин.
Идея состоит в том, чтобы поместить геометрию из всех прямоугольников в один отдельный VBO (VBO - это, по сути, массив вершин, хранящийся «в» OpenGL, а не в вашем процессе). Изменение отдельных вершин возможно с помощью glBufferSubData.
Цвет вершины можно поместить в массив вершин и, следовательно, в VBO.
Обновление
Скажем, у вас есть шестигранник:
GLfloat vertices[2][] = {
{0, 0}, // 0
{1, 0}, // 1
{0.5, 0.866}, // 2
{-0.5, 0.866}, // 3
{-1, 0}, // 4
{0.5, -0.866}, // 5
{-0.5, -0.866}, // 6
};
и вы хотите нарисовать только часть треугольников, скажем, треугольники, состоящие из вершин [0,1,2], [0,3,4] и [0,5,6], тогда вы создадите следующий индексный массив
GLushort indices[] = {
0, 1, 2,
0, 3, 4,
0, 5, 6
};
И использовать это как индексы для glDrawElements.
Обновление 2
Одна вещь, которую многие компьютерные графики и новички в OpenGL ошибаются, это то, что вершина - это не просто позиция, а комбинация атрибутов вершины. Какие атрибуты составляют вершину - это выбор дизайна, сделанный программистом. Но обычно используемые атрибуты вершин
- положение
- нормальный
- текстурные координаты
- цвет вершины
До ядра OpenGL-3 атрибут position был обязательным. Поскольку ядро OpenGL-3, которое сделало шейдеры обязательными, атрибуты вершин - это просто произвольные входные данные в шейдеры, и пока вершинному шейдеру удается доставить вывод * gl_Position *, OpenGL рад.
Важно то, что две вершины идентичны только тогда, если все атрибуты одинаковы. Если они отличаются только одним атрибутом, это не одна и та же вершина. Теперь давайте возьмем наш предыдущий пример шестиугольника. Сейчас мы делаем треугольники красного, зеленого и синего и , чтобы добавить два треугольника, чтобы расширить красный и зеленый треугольники:
// x, y, red, green, blue
GLfloat vertices[5][] = {
// red
{0, 0, 1, 0, 0}, // 0
{1, 0, 1, 0, 0}, // 1
{0.5, 0.866, 1, 0, 0}, // 2
{1, 1, 1, 0, 0}, // 3
// green
{0, 0, 0, 1, 0}, // 4
{-0.5, 0.866, 0, 1, 0}, // 5
{-1, 0, 0, 1, 0}, // 6
{-1, 1, 0, 1, 0}, // 7
// blue
{0, 0, 0, 0, 1}, // 8
{0.5, -0.866, 0, 0, 1}, // 9
{-0.5, -0.866, 0, 0, 1}, // 10
};
Треугольники, которые мы сейчас хотим нарисовать, это
GLushort indices[] = {
// the two red triangles
0, 1, 2,
3, 2, 1,
// the two green triangles
4, 5, 6,
5, 7, 6,
// the blue triangle
8, 9, 10
};
Теперь нам нужно рассказать OpenGL о структуре нашего массива вершин. Именно здесь параметр шага функций gl… Pointer входит в изображение. Если не ноль, шаг сообщает OpenGL расстояние (в байтах) между началом каждой вершины в массиве. Передав указатель data со смещением вправо, OpenGL получает доступ к нужным объектам. В нашем случае вершина состоит из
- 2 позиционных элемента GLfloat со смещением 0
- 3 цветных элемента GLfloat со смещением 2 * sizeof (GLfloat)
и каждая вершина находится на расстоянии sizeof(GLfloat)*5
байт.
Мы позволим компилятору C выполнять вычисления смещения за нас, просто разыменовывая нужные элементы массива и получая его адрес:
glVertexPointer(2, GL_FLOAT, sizeof(GLfloat)*5, &vertices[0][0]);
glColorPointer(3, GL_FLOAT, sizeof(GLfloat)*5, &vertices[0][2]);
Остальное просто glDrawElements(GL_TRIANGLES, 5, GL_UNSIGNED_SHORT, indices)
.
Обратите внимание, что в данный момент мы не используем VBO, а только клиентские массивы вершин. VBO основаны на массивах вершин. Поэтому я настоятельно рекомендую вам сначала получить полный контроль над массивами вершин, прежде чем переходить к VBO. На самом деле они довольно просты в использовании, но есть несколько концептуальных ловушек, например, обманом компилятора для передачи числа для параметра указателя.