【问题标题】:Batch model matrixes to single Uniform Buffer Object批量模型矩阵到单个统一缓冲区对象
【发布时间】:2019-07-15 09:50:11
【问题描述】:

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

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

【问题讨论】:

    标签: c++ opengl glsl


    【解决方案1】:

    每件事都有其权衡,并且需要性能测量来验证。

    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 风格的编程。

    【讨论】:

    • 我打算在单个 VBO 中发送带有顶点和其他数据的 id,所以我不会创建新的 VBO,我也会在渲染阶段结束时每帧更新一次 UBO 中的矩阵...所以我想知道为多个对象更新单个 UBO 或多次更新统一是否更有效。
    • 如果将id 预烘焙到 VBO 数据中不是负担,那么唯一的次要问题是着色器中的索引常量查找(ModelMatrix[id] 使用每个线程的 id)。如果顶点按 id 分组,它往往是统一的 -> 也很好。每帧更新 UBO 仍可能导致不希望的 CPU/GPU 同步,因为 OpenGL 建立了“软件/硬件管道”,例如 [CPU] 渲染线程 --> [CPU] 驱动程序线程 --> GPU。 Map 调用创建一个互锁。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多