Jas*_*son 6 c++ opengl opengl-es vertex-buffer vertex-array-object
我不明白GL_ARRAY_BUFFEROpenGL 中绑定点(例如)的目的是什么.据我所知,glGenBuffers()创建了一种指向位于GPU内存中某处的顶点缓冲区对象的指针.
所以:
glGenBuffers(1, &bufferID)
Run Code Online (Sandbox Code Playgroud)
意味着我现在有一个句柄,bufferID,到图形卡上的1个顶点对象.现在我知道下一步是将bufferID绑定到绑定点
glBindBuffer(GL_ARRAY_BUFFER, bufferID)
Run Code Online (Sandbox Code Playgroud)
这样我就可以使用该绑定点使用如下glBufferData()函数发送数据:
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW)
Run Code Online (Sandbox Code Playgroud)
但为什么我不能只使用bufferID来指定我想要发送数据的位置呢?就像是:
glBufferData(bufferID, sizeof(data), data, GL_STATIC_DRAW)
Run Code Online (Sandbox Code Playgroud)
然后当调用绘图函数时,我也只是将任何ID放入我想要绘制绘图函数的VBO中.就像是:
glDrawArrays(bufferID, GL_TRIANGLES, 0, 3)
Run Code Online (Sandbox Code Playgroud)
为什么我们需要额外的间接步骤glBindBuffers?
Nic*_*las 11
OpenGL使用对象绑定点来做两件事:指定一个对象作为渲染过程的一部分,并能够修改对象.
为什么它将它们用于前者很简单:OpenGL需要很多对象才能渲染.
考虑一下你过于简单化的例子:
glDrawArrays(bufferID, GL_TRIANGLES, 0, 3)
Run Code Online (Sandbox Code Playgroud)
该API不允许我有单独的顶点属性来自单独的缓冲区.当然,你可能会建议glDrawArrays(GLint count, GLuint *object_array, ...).但是,如何将特定缓冲区对象连接到特定的顶点属性?或者,如何从缓冲区0中获取2个属性,从缓冲区1中获取第三个属性?这些是我现在可以用当前的API做的事情.但你提议的人无法处理它.
甚至那就是抛弃你需要渲染的许多其他对象:程序/管道对象,纹理对象,UBO,SSBO,变换反馈对象,查询对象等.在一个命令中指定所有需要的对象将从根本上不可行(并且不考虑性能成本).
每次API需要添加新类型的对象时,您都必须添加新glDraw*功能的变体.而现在,有超过一打这样的功能.你的方式会给我们数百.
因此,OpenGL定义了一种方式让您说"下次渲染时,以这种方式使用此对象进行该过程." 这就是绑定使用对象的意思.
但为什么我不能只使用bufferID来指定我想要发送数据的位置呢?
这是为了修改对象而绑定一个对象,而不是说它将被使用.那是......另一件事.
显而易见的答案是,"你不能这样做,因为OpenGL API(直到4.5)没有让你这么做的功能." 但我更怀疑这个问题是为什么OpenGL没有这样的API(直到4.5,glNamedBufferStorage存在等等).
实际上,4.5确实具有这样的功能的事实证明了4.5之前的OpenGL的绑定对象修改API 没有技术原因.由于遵循阻力最小的路径,OpenGL API从1.0发展而来的确是一个"决定".反复.
实际上,OpenGL所做的每一个错误决定都可以追溯到API中阻力最小的路径.但我离题了.
在OpenGL 1.0中,只有一种对象:显示列表对象.这意味着即使纹理也没有存储在对象中.因此,每次切换纹理时,都必须重新指定整个纹理glTexImage*D.这意味着重新上传它.现在,您可以(并且人们确实)将每个纹理的创建包装在显示列表中,这允许您通过执行该显示列表来切换纹理.并希望驱动程序会意识到你正在这样做,而是适当地分配视频内存等.
因此,当1.1出现时,OpenGL ARB意识到这是多么令人难以置信的愚蠢.因此,他们创建了纹理对象,它封装了纹理的内存存储和内部的各种状态.当你想使用纹理时,你绑定它.但有一个障碍.即,如何改变它.
看,1.0有一堆已经存在的函数glTexImage*D,glTexParamter等等.这些修改纹理的状态.现在,ARB可以添加新功能,它们执行相同的操作,但将纹理对象作为参数.
但这意味着将所有OpenGL用户划分为2个阵营:使用纹理对象的人和不使用纹理对象的人.这意味着,如果你想使用纹理对象,你必须重写所有修改纹理的现有代码.如果你有一些函数glTexParameter在当前纹理上进行了一系列调用,则必须更改该函数以调用新的纹理对象函数.但是你还必须改变调用它的函数,以便它作为参数获取它所操作的纹理对象.
如果该功能不属于您(因为它是您正在使用的库的一部分),那么您甚至无法做到这一点.
因此,ARB决定保留这些旧函数,并根据纹理是否与上下文绑定而使它们的行为不同.如果绑定了一个,那么glTexParameter/ etc会修改绑定纹理,而不是上下文的普通纹理.
这一决定建立了几乎所有OpenGL对象共享的一般范例.
出于同样的原因,ARB_vertex_buffer_object使用了这个范例.注意各种gl*Pointer函数(glVertexAttribPointer等)如何与缓冲区相关.您必须将缓冲区绑定到GL_ARRAY_BUFFER,然后调用其中一个函数来设置属性数组.当缓冲区绑定到该槽时,该函数将选择该缓冲区并将指针视为在*Pointer调用函数时绑定的缓冲区中的偏移量.
为什么?出于同样的原因:易于兼容(或促进懒惰,取决于您希望如何看待它).ATI_vertex_array_object必须为gl*Pointer函数创建新的模拟.而ARB_vertex_buffer_object只是背负了现有的入口点.
用户不必使用更改glVertexPointer到glVertexBufferOffset或其他一些功能.他们所要做的只是在调用设置顶点信息的函数之前绑定一个缓冲区(当然,将指针更改为字节偏移).
这也意味着他们不必添加一堆glDrawElementsWithBuffer类型的函数来使用来自缓冲区对象的索引进行渲染.
所以这在短期内并不是一个坏主意.但与大多数短期决策一样,随着时间的推移,它开始变得不那么合理了.
当然,如果您可以访问GL 4.5/ARB_direct_state_access,那么您可以采用最初应该完成的方式.