Как минимизировать вызовы 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);

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

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

Другие вопросы по тегам