Как минимизировать вызовы glVertexAttribPointer при использовании Instanced Arrays?

У меня есть код OpenGL, использующий один VAO для всех данных модели и два VBO. Первый для стандартных атрибутов вершин, таких как положение и нормаль, а второй для модельных матриц. Я использую инстансированное рисование, поэтому я загружаю матрицы моделей в виде инстансированных массивов (которые в основном являются атрибутами вершин).

Сначала я загружаю стандартные атрибуты вершины в VBO и настраиваю все один раз сglVertexAttribPointer, Затем я загружаю матрицы моделей в другое VBO. Теперь мне нужно позвонитьglVertexAttribPointerв цикле розыгрыша. Могу ли я как-то предотвратить это?

Код выглядит так:

// vertex data of all models in one array
GLfloat myvertexdata[myvertexdatasize];

// matrix data of all models in one array
// (one model can have multiple matrices)
GLfloat mymatrixdata[mymatrixsize];

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, myvertexdatasize*sizeof(GLfloat), myvertexdata, GL_STATIC_DRAW);

glVertexAttribPointer(
          glGetAttribLocation(myprogram, "position"),
          3,
          GL_FLOAT,
          GL_FALSE,
          24,
          (GLvoid*)0
);
glEnableVertexAttribArray(glGetAttribLocation(myprogram, "position"));
glVertexAttribPointer(
          glGetAttribLocation(myprogram, "normal"),
          3,
          GL_FLOAT,
          GL_FALSE,
          24,
          (GLvoid*)12
);
glEnableVertexAttribArray(glGetAttribLocation(myprogram, "normal"));

GLuint matrixbuffer;
glGenBuffers(1, &matrixbuffer);
glBindBuffer(GL_ARRAY_BUFFER, matrixbuffer);
glBufferData(GL_ARRAY_BUFFER, mymatrixsize*sizeof(GLfloat), mymatrixdata, GL_STATIC_DRAW);

glUseProgram(myprogram);


draw loop:
    int vertices_offset = 0;
    int matrices_offset = 0;
    for each model i:
        GLuint loc = glGetAttribLocation(myprogram, "model_matrix_column_1");
        GLsizei matrixbytes = 4*4*sizeof(GLfloat);
        GLsizei columnbytes = 4*sizeof(GLfloat);
        glVertexAttribPointer(
              loc, 
              4, 
              GL_FLOAT, 
              GL_FALSE, 
              matrixbytes,
              (GLvoid*) (matrices_offset*matrixbytes + 0*columnbytes)
        );
        glEnableVertexAttribArray(loc);
        glVertexAttribDivisor(loc, 1); // matrices are in instanced array
        // do this for the other 3 columns too...

        glDrawArraysInstanced(GL_TRIANGLES, vertices_offset, models[i]->num_vertices(), models[i]->num_instances());

        vertices_offset += models[i]->num_vertices();
        matrices_offset += models[i]->num_matrices();

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

Любая помощь будет принята с благодарностью.

Ответы на вопрос(1)

Решение Вопроса

Если у вас есть доступ крендеринг базового экземпляра (требуется GL 4.2 илиARB_base_instance), тогда вы могли бы сделать это. Поместите заполненный экземпляр атрибута в настройку с помощью атрибута без экземпляра:

GLuint loc = glGetAttribLocation(myprogram, "model_matrix_column_1");

for(int count = 0; count < 4; ++count, ++loc)
{
    GLsizei matrixbytes = 4*4*sizeof(GLfloat);
    GLsizei columnbytes = 4*sizeof(GLfloat);
    glVertexAttribPointer(
          loc, 
          4, 
          GL_FLOAT, 
          GL_FALSE, 
          matrixbytes,
          (GLvoid*) (count*columnbytes)
    );
    glEnableVertexAttribArray(loc);
    glVertexAttribDivisor(loc, 1); // matrices are in instanced array
}

Затем вы просто связываете VAO, когда будете готовы визуализировать эти модели. Ваш розыгрыш становится:

glDrawArraysInstancedBaseInstance​(GL_TRIANGLES, vertices_offset, models[i]->num_vertices(), models[i]->num_instances(), matrix_offset);

Эта функцияна удивление широко доступный, даже на pre-GL 4.x оборудовании (если оно имеет последние драйверы).

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

 Nicol Bolas29 мая 2016 г., 19:06
@mak: Вы не опубликовали весь свой код, поэтому я предположил, что ваш матричный атрибут былmat4, что вполне приемлемо. Если это так, то 4 локациибудет последовательно выделен, Хотя на самом деле вы не должны получать эти места вообще. Вы должны указывать их прямо в своем шейдере.
 mak29 мая 2016 г., 18:27
Места всегда следующие номера?
 mak30 мая 2016 г., 00:47
Что плохого в получении местоположений, когда вы делаете это только один раз?

Ваш ответ на вопрос