0

我决定看看统一缓冲区对象。但我不确定何时何地不使用它。

我试图将所有模型转换批处理成单个数组,我会立即发送到着色器。但它有它的后果。我还必须为每个顶点发送到着色器 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);
}
4

1 回答 1

1

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

glUniform其视为按值传递,而 UBO 是按引用传递。除了,GPU 着色器代码中 [通常] 没有性能损失,用于对 UBO 的额外间接。

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

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

其他注意事项:

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