Пакетные модельные матрицы в единый объект буфера - PullRequest
0 голосов
/ 11 июля 2019

Я решил взглянуть на однородные буферные объекты.Но я не уверен, когда и когда его не использовать.

Я попытался объединить все преобразования моделей в один массив, который я бы сразу отправил в шейдер.Но это имеет свои последствия.Я также должен отправить идентификатор шейдера для каждой вершины, чтобы соответствовать этим преобразованиям.

Итак, мой вопрос: стоит ли это?Или я предпочел бы в этом конкретном случае использовать обычные вызовы glUniform?

Ниже моя шейдерная программа.

#version 330 core

layout (location = 0) in vec3 position;
layout (location = 1) in int id;

layout (std140) uniform scene_data
{
    mat4 ViewProjectionMatrix;
    mat4 ModelMatrix[128];
};


void main()
{
    gl_Position = ViewProjectionMatrix * ModelMatrix[id] * vec4(position,1.0);  


}

Вот как я создаю объект Uniform Buffer:

Dot::UniformBuffer::UniformBuffer(const void*data, unsigned int size, unsigned int index)
    :m_Index(index),m_size(size)
{
    glGenBuffers(1, &m_UBO);
    glBindBuffer(GL_UNIFORM_BUFFER, m_UBO);
    glBufferData(GL_UNIFORM_BUFFER, size, data, GL_DYNAMIC_DRAW);

    glBindBufferBase(GL_UNIFORM_BUFFER, index, m_UBO);  
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

}

Dot::UniformBuffer::~UniformBuffer()
{
    glDeleteBuffers(1, &m_UBO);
}


void Dot::UniformBuffer::Update(const void* data)
{
    glBindBuffer(GL_UNIFORM_BUFFER, m_UBO);
    GLvoid* p = glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY);
    memcpy(p, data, m_size);
    glUnmapBuffer(GL_UNIFORM_BUFFER);
}

1 Ответ

0 голосов
/ 15 июля 2019

У всего есть свои компромиссы, и для проверки потребуются измерения производительности.

Думайте о glUniform как о передаче по значению, тогда как UBO - о передаче по ссылке. За исключением того, что в коде шейдера GPU [обычно] нет штрафов за перфорирование для дополнительного косвенного обращения к UBO.

Основным преимуществом UBO является снижение нагрузки на процессор на этапе «связывания», поскольку все значения уже записаны в память. Рендеринг может подготовить много UBO заранее во время загрузки (по одному UBO на «вектор состояния»), чтобы избежать необходимости передавать данные во время основного цикла рендеринга. Как правило, вы не хотите изменять UBO на месте в вашем рендере, потому что glMapBuffer будет ожидать предыдущих дро, которые используют это UBO для завершения.

В этом конкретном примере шейдер выполняет «поиск по индексированной константе» с использованием входного атрибута id, который медленнее, чем поиск с равномерной константой.

Другие соображения:

  • layout (location = 1) in int id; требует, чтобы ЦП подготовил дополнительный буфер вершин и индексный буфер. Это также может означать создание копий данных необработанной геометрии, что требует больше ресурсов процессора и памяти.
  • glDrawArraysInstanced или glDrawElementsInstanced может позволить OpenGL генерировать вместо вас id. Из шейдера используйте gl_InstanceID. Устраняет необходимость в дополнительных буферах вершин. Это было бы похоже на https://learnopengl.com/Advanced-OpenGL/Instancing
  • glUniform приведет к передаче данных из кода приложения -> драйвер -> GPU при каждом вызове.
  • UBO требует большего управления объектами и планирования, но обычно сходится к наиболее быстродействующему рендереру. Vulkan и D3D12 поддерживают только программирование в стиле UBO.
...