我试图弄清楚如何使用现代OpenGL API(4.3)
实现以下概念我有一个顶点缓冲区,它有一个规则的顶点数组。但我需要一半的数据用ShaderProgram A处理,另一半用ShaderProgram B处理。
目前我所做的是创建两个不同的VAO,顶点属性指针指向顶点数组的相关部分。但在这种情况下,我必须发出2个绘制调用 - 每个VAO一个。
我可以通过一次平局调用来完成吗?
P.S:我想过原始重启,但AFAIK在每次重启时都没有切换着色器。
答案 0 :(得分:1)
如果两个程序具有相同的属性,则可以在它们之间共享相同的VAO,并使用各种start
调用中的glDraw
参数绘制后半部分数据,而无需切换VAO(你仍然需要切换着色器)。
答案 1 :(得分:1)
我有一个顶点缓冲区,它有一个规则的顶点数组。
首先,顶点缓冲区没有任何数组。顶点数组是顶点数组对象的状态,甚至在白天,当有客户端侧顶点数组时,它们不是顶点缓冲区对象的一部分。从规范的意义上说,顶点数组仅仅是相关数据存储布局的描述。数据存储加上一些状态是组成顶点缓冲区对象的原因。一个或多个顶点数组和相关数据存储的组合可以在着色器内拉出顶点属性(除非禁用相应的数组)。
我需要使用ShaderProgram A处理其一半数据,另外一半使用ShaderProgram B.当前我所做的是创建两个不同的VAO,顶点属性指针指向顶点数组的相关部分。但在这种情况下我必须发出2个绘制调用 - 每个VAO一个。
无论如何,请使用单个VAO
如果在使用任一着色器获取顶点属性时具有相同的缓冲区布局,请使用单个顶点数组并仅使用glDrawArrays()
提供起始偏移量。
否则使用两个顶点数组,其中相应的偏移量进入缓冲区(以及保证单独顶点数组的其他属性),将数组A绑定到索引0,将数组B绑定到索引1,并在着色器中使用显式的attrib位置,如此(假设有些4分量属性):
layout (location = 0) in vec4 Attrib; // inside Shader A
layout (location = 1) in vec4 Attrib; // inside Shader B
说到定义顶点数组:从GL 4.3开始,你不应该再使用旧的方式(即glVertexAttribPointer*()
),而是选择更灵活的glVertexAttribFormat()
,glBindVertexBuffer()
和glVertexAttribBinding()
。新方法解耦了attrib规范和缓冲区关联,并且特别适用于交错的attribs - 这是一件好事。然后,您将执行以下操作(伪代码):
bindVAO();
glVertexAttribFormat(0, 4, GL_FLOAT, GL_FALSE, 0);
glVertexAttribFormat(1, 4, GL_FLOAT, GL_FALSE, 0);
glBindVertexBuffer(0, buffer, 0, 0);
glBindVertexBuffer(1, buffer, offsetToBeginOfDataForShaderB, 0); //
glVertexAttribBinding(0, 0)
glVertexAttribBinding(1, 1);
如果您突然想要切换任一着色器处理的数据,假设两个着色器都可以处理这种情况,那么您需要做的就是调用:
// assuming your VAO is still bound (which it should be unless you really needed to swtich ... )
glVertexAttribBinding(0, 1)
glVertexAttribBinding(1, 0);
现在着色器A开始从缓冲区绑定1获取位置0的attribs,反之亦然。在这种情况下,这不会添加太多或任何值。但是,如果需要,它可以更轻松地切换布局/缓冲区关联,并减少API和驱动程序开销。如果您想要某个数组从另一个缓冲区中获取数据,则无需再次调用glBindBuffer()
或glVertexAttribPointer()
。另一个巧妙的事情是:我们终于摆脱了void*
的{{1}}论点......;)
请注意,绑定索引和属性索引不必相同,您也可以这样做,尽管在您的情况下它很无意义:
glVertexAttribPointer()
我可以通过一次平局调用来完成吗?
不,你不能。问问自己,如何在单次抽奖期间切换着色器?
如果您发现任何错误,请发表评论。