将模型矩阵批处理为单个统一缓冲区对象

时间:2019-07-11 19:36:24

标签: c++ opengl glsl

我决定看一下统一的缓冲区对象。但是我不确定何时以及何时不使用它。

我尝试将所有模型转换批处理为单个数组,然后将其立即发送到着色器。但这有其后果。我还必须为每个顶点发送着色器ID,以匹配这些转换。

所以我的问题是:值得吗?还是在特定情况下我更喜欢使用常规的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);  


}

这是我创建统一缓冲区对象的方式:

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 :(得分:0)

一切都有其取舍,并且需要性能测量来验证。

glUniform视为传递值,而UBO是传递引用。除此以外,[GPU]着色器代码中通常不存在针对UBO的其他间接访问的性能损失。

UBO的主要好处是在“绑定”阶段减少了CPU开销,因为所有值都已写入内存。渲染器可以在加载时预先准备许多UBO(每个“状态向量”一个UBO),以避免在主渲染循环期间必须传输数据。通常,您不想在渲染器中就地修改UBO,因为glMapBuffer将等待使用该UBO完成的先前绘制。

在此特定示例中,着色器使用输入属性id执行“索引常量查找”,这比统一常量查找要慢。

其他注意事项:

  • layout (location = 1) in int id;要求CPU准备一个额外的顶点缓冲区和索引缓冲区。这也可能意味着要对原始几何图形进行数据复制,这会占用更多的CPU和内存。
  • glDrawArraysInstancedglDrawElementsInstanced可以让OpenGL为您生成id。在着色器中,使用gl_InstanceID。无需额外的顶点缓冲区。那将类似于https://learnopengl.com/Advanced-OpenGL/Instancing
  • glUniform将在每次调用时从应用程序代码->驱动程序-> GPU传输数据。
  • UBO需要更多的对象管理和计划,但通常会集中在性能最快的渲染器上。 Vulkan和D3D12仅支持UBO风格的编程。