不深⼊理解OpenGL:UBO(UniformBlockObject)
最近刚刚开始研究图形⽅⾯的东西,如果理解有误请务必指正。在OpenGL 4.5已经有更好的解法了,奈何我辣鸡I卡只⽀持4.4。
UBO是OpenGL 3.1 Core中引⼊的概念。通过到缓存的通信,修改Uniform变量(=运⾏时常量)造成的开销更低,不同的Shader间还可以共享同⼀UBO的内容。具体就不扯那么多了,有兴趣可以阅读了解更多。
因为OpenGL的状态机模型,有的时候调⽤相关API会发⽣意料之外的结果。⼀般也就是画不出东西,再惨就是报错了。这⾥记录⼀下UBO 的缓冲区⽣成与绑定流程:
GLuint buf;
glGenBuffers(1, &buf); // 创建缓存,此时仅仅创建了缓存句柄(name、handle、id,就那个意思),对象并没有被创建。
auto index = glGetUniformBlockIndex(prog, "UBOName"); // 通过UBO名查询索引。
glUniformBlockBinding(prog, index, bindingPoint); // 绑定着⾊器程序$prog的UBO到$bindingPoint。bindingPoint不和同⼀程序其他UBO重复即可。
glBindBuffer(GL_UNIFORM_BUFFER, buf); // 在⾸次绑定时会通过句柄构造对象。
glBufferData(GL_UNIFORM_BUFFER, GetUniformBlockSize(index), nullptr, GL_STATIC_DRAW); // 注意显存中内容是未定义的,在指定数据前不可使⽤。glBindBuffer(GL_UNIFORM_BUFFER, 0); // 为了安全解除绑定。
这⾥通过buf就可以修改相应UBO的内容了。
绘图时再完成另⼀半的绑定:
记住我
glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, buf); // 绑定缓存$buf到$bindingPoint。也可以使⽤glBindBufferRange()。
需要注意的地⽅:
1. glBindBufferBase()被调⽤时虽然也会将buf绑定到GL_UNIFORM_BUFFER,但在缓存对象没有被构造的时候调⽤glBindBuffer{Base, Range}会造
成GL_INVALID_VALUE错误,参见。所以在构建UBO缓存的时候并没有使⽤这两个⽅法。
2. 从UBO到Binding Point的绑定是对着⾊器程序的操作;⽽从缓存到Binding Point的绑定是对OpenGL状态机进⾏的操作。所以,在每
次draw的时候不需要重新定义UBO到Binding Point的绑定,但需要重新定义对缓存的绑定。参见。