我决定看一下统一的缓冲区对象。但是我不确定何时以及何时不使用它。
我尝试将所有模型转换批处理为单个数组,然后将其立即发送到着色器。但这有其后果。我还必须为每个顶点发送着色器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);
}
答案 0 :(得分:0)
一切都有其取舍,并且需要性能测量来验证。
将glUniform
视为传递值,而UBO是传递引用。除此以外,[GPU]着色器代码中通常不存在针对UBO的其他间接访问的性能损失。
UBO的主要好处是在“绑定”阶段减少了CPU开销,因为所有值都已写入内存。渲染器可以在加载时预先准备许多UBO(每个“状态向量”一个UBO),以避免在主渲染循环期间必须传输数据。通常,您不想在渲染器中就地修改UBO,因为glMapBuffer
将等待使用该UBO完成的先前绘制。
在此特定示例中,着色器使用输入属性id
执行“索引常量查找”,这比统一常量查找要慢。
其他注意事项:
layout (location = 1) in int id;
要求CPU准备一个额外的顶点缓冲区和索引缓冲区。这也可能意味着要对原始几何图形进行数据复制,这会占用更多的CPU和内存。glDrawArraysInstanced
或glDrawElementsInstanced
可以让OpenGL为您生成id
。在着色器中,使用gl_InstanceID
。无需额外的顶点缓冲区。那将类似于https://learnopengl.com/Advanced-OpenGL/Instancing glUniform
将在每次调用时从应用程序代码->驱动程序-> GPU传输数据。