Как использовать объекты буфера вершин (VBO) вместо тысяч вызовов glDrawArrays в OpenGL ES 1.0 на iOS? - PullRequest
0 голосов
/ 30 ноября 2011

Для моделирования мы создали представление OpenGL1.1 с сеткой из 32 х 48 прямоугольников.

Мы рисуем эту сетку каждый раз, когда CADisplayLink вызывает нашу функцию рисования, и позиции вершин никогда не меняются. Единственное, что меняется от кадра к кадру, это цвет вершины.

Это упрощенный пример того, как мы это делаем:

- (void)drawFrame {
    // draw grid
    for (int i = 0; i < numRectangles; i++) {
        // ... calculate CGPoint values for vertices ...

        GLshort vertices[ ] = {
            bottomLeft.x, bottomLeft.y,
            bottomRight.x, bottomRight.y,
            topLeft.x, topLeft.y,
            topRight.x, topRight.y
        };

        glVertexPointer(2, GL_SHORT, 0, vertices);           
        glColor4f(r, g, b, 1);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    }
}

Для повышения производительности инструмент OpenGL рекомендовал использовать объекты Vertex Buffer Objects (VBO).

Есть ли пример того, как настроить простое и простое использование объектов буфера вершин в случае, когда вершины не меняются от кадра к кадру?

Apple предоставляет пример здесь, в разделе Использование объектов буфера вершин для управления копированием данных вершин , но он неполон.

GLuint    vertexBuffer;
GLuint    indexBuffer;

void CreateVertexBuffers()
{

    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

}

Это не показывает, как на самом деле создавать данные. Предыдущий листинг (который должен быть «плохим примером») содержит следующие две строки:

const vertexStruct vertices[] = {...};
const GLubyte indices[] = {...};

Итак, эти два массива или структуры должны быть переданы в:

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

и

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

?

Является ли этот формат «чередующимся (массив структур)» предпочтительным для iOS, согласно Apple в разделе Использовать данные чередующихся вершин сечение?

1 Ответ

4 голосов
/ 30 ноября 2011

Вы не должны рисовать отдельные примитивы, используя 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. На самом деле они довольно просты в использовании, но есть несколько концептуальных ловушек, например, обманом компилятора для передачи числа для параметра указателя.

...