是否可以将索引缓冲区对象 (IBO) 与函数“glMultiDrawElements”一起使用?
Posted
技术标签:
【中文标题】是否可以将索引缓冲区对象 (IBO) 与函数“glMultiDrawElements”一起使用?【英文标题】:Is it possible to use Index Buffer Objects (IBO) with the function 'glMultiDrawElements'? 【发布时间】:2014-07-01 18:27:00 【问题描述】:我使用 OpenGL 和 GLSL 开发了一个小型 3D 引擎。
我已经合并了一个顶点数据批处理系统,其目标是在一个唯一的顶点缓冲区对象 (VBO) 中收集共享相同着色器程序和相同转换的所有几何图形(所有对象),从而最大限度地减少状态更改(绑定)并绘制电话。
我目前使用函数 'glMultiDrawElements' 来渲染特定批次的数据(因此是一次绘制调用)。因此,例如,如果我的批次中有 3 个网格,我也有 3 个索引数组(每个网格一个),它们组织在一个“GLvoid **”数组(一个双数组)中。所以要渲染我的 3 个网格,我有一个独特的 glMultiDrawElements 调用,但我必须直接将参数中的双精度数组传递给函数。
但我想知道(关于性能问题)是否可以将所有元素(元素的双数组)存储在索引缓冲区对象 (IBO) 中(就像可以使用 glDrawElements 一样 -> 这里是一个简单的数组元素)并在 glMultiDrawElements 调用之前绑定它......我不这么认为,因为它是一个双数组而不是一个简单的数组,但也许(我希望如此)我错了。
这是一个使用 glDrawElements 的示例(伪代码):
[...]
//Setup data
[...]
#define OFFSET_BUFFER(offset) ((char*)NULL + offset)
foreach (pMeshGeometry from meshes) //iterates for each mesh of the scene
pMeshGeometry->GetIndexBuffer().Lock(); //Bind IBO
glDrawElements(pMeshGeometry->GetPrimitiveType(),
pMeshGeometry->GetIndexBufferSize(), pMeshGeometry->GetIndexBuffer().GetType(), OFFSET_BUFFER(0)); //Render a specific mesh eccording to indices
目前我以这种方式使用 glMultiDrawElement:
glMultiDrawElements(GL_TRIANGLES, &this->m_CountElementArray[0], GL_UNSIGNED_INT,
(const GLvoid **)&this->m_IndexAttribArray[0], this->m_CountElementArray.size()); //I enter the array of pointer directly in parameter
所以,也许下面的例子应该是可能的:
#define OFFSET_BUFFER(offset) ((char**)NULL + offset) //Something like this
glMultiDrawElements(GL_TRIANGLES, &this->m_CountElementArray[0], GL_UNSIGNED_INT,
OFFSET_BUFFER(0), this->m_CountElementArray.size()); //Something like this
因此,如果无法做到这一点,我想到了函数“glDrawRangeElements”。对于我将 3 个网格放入唯一 VBO 的示例,我只需要在每个 glDrawRangeElements 调用之前绑定一个 IBO(这里,每个网格有 3 个绘制调用 -> 所以是一个 glDrawRangeElements 循环)。所以这里显然可以使用 IBO。
这种方法肯定行得通,但我认为它不是最好的方法!我认为可以使用带有 IBO 的 glMultiDrawElements 来做到这一点,但我不知道该怎么做。
或许这真的不可能。也许在参数中直接输入索引数组的事实比使用 glDrawRangeElements 及其 IBO 的方法更快,因此在这种情况下使用 IBO 可能已被弃用,因此不适用。
你怎么看?
【问题讨论】:
请使用一些换行符。这个巨大的段落几乎无法阅读。 你到底在问什么?即使有换行符我也不确定。 对不起,我以为很清楚。总而言之,我想知道是否可以将 IBO 与 glMultiDrawElements 一起使用,而不是直接在参数中使用双索引数组。 @user1364743:没有“双数组”。有一组指针/偏移量。有ARB_multi_draw_indirect。但我不确定这是否是您要求的。 对不起,我想说的是指针数组而不是双数组。我已经使用“glDrawElements”方法更新了我的问题,添加了一个源代码(伪代码)示例。正如您在主循环之前看到的,我将所有顶点数据设置为 VBO,将所有索引数据设置为 IBO。之后,在主循环中我使用宏 OFFSET_BUFFER。这行得通。是否可以为函数“glMultiDrawElements”使用这样的宏(因此使用 IBO 而不是直接使用指针数组)? 【参考方案1】:您当然可以将索引缓冲区与glMultiDrawElements()
一起使用。客户端索引数组在 OpenGL 核心配置文件中已弃用。所以如果glMultiDrawElements()
不能使用索引缓冲区,就没有办法再使用它了。
要了解它是如何工作的,我们需要看看glMultiDrawElements()
的参数是什么意思。该调用基本上只是多个glDrawElements()
调用的快捷方式。签名是:
void glMultiDrawElements(GLenum mode, const GLsizei* count, GLenum type,
const GLvoid** indices, GLsizei primcount);
除了一些错误检查细节之外,这个调用相当于:
for (int i = 0; i < primcount; ++i)
glDrawElements(mode, count[i], type, indices[i]);
现在请记住,如果绑定了索引缓冲区,glDrawElements()
的最后一个参数是缓冲区的相对偏移量。所以glMultiDrawElements()
对应的第 4 个元素是缓冲区中的一个偏移数组。第二个参数是一个匹配的计数数组。
人们经常使用宏来隐藏glDrawElements()
最后一个参数的繁琐类型转换。使用这个:
#define BUFFER_OFFSET(offset) (static_cast<char*>(0) + (offset))
例如,假设我们有一个索引缓冲区绑定,并且我们想通过一次调用绘制索引数组的 3 个子范围:
20 个索引,从缓冲区中的索引 10 开始。 30 个索引,从缓冲区中的索引 40 开始。 缓冲区中从索引 90 开始的 10 个索引。我将使用无符号短裤 (GLushort) 作为索引类型。因此,索引缓冲区将在过去的某个时间填充来自GLushort indexA[100]
的数据。设置和绘制调用如下所示:
GLsizei count[3] = 20, 30, 10;
GLvoid* indices[3] =
BUFFER_OFFSET(10 * sizeof(GLushort)),
BUFFER_OFFSET(40 * sizeof(GLushort)),
BUFFER_OFFSET(90 * sizeof(GLushort)),
;
glMultiDrawElements(GL_TRIANGLE_STRIP, count, GL_UNSIGNED_SHORT, indices, 3);
【讨论】:
非常感谢您的完整回答。我相信你的解决方案是最好的,而且非常合乎逻辑。我要把它集成到我的程序中。祝你有美好的一天。再见!以上是关于是否可以将索引缓冲区对象 (IBO) 与函数“glMultiDrawElements”一起使用?的主要内容,如果未能解决你的问题,请参考以下文章
VAO 是不是同时记住 EBO/IBO(元素或索引)和 VBO?