我使用OpenGL和GLSL开发了一个小型3D引擎。
我已经合并了一个顶点数据批处理系统,其目的是收集共享相同着色器程序的所有几何体(所有对象)和相同的顶点缓冲对象(VBO)中的相同转换,从而最小化状态更改(绑定)并打电话。
我目前使用函数'glMultiDrawElements'来呈现特定批量的数据(因此单次绘制调用)。因此,例如,如果我在我的批处理3网格中,我有3个索引数组(每个网格一个)组织在'GLvoid **'数组(双数组)中。因此,为了渲染我的3个网格,我有一个独特的glMultiDrawElements调用,但是我必须直接将参数中的double元素数组传递给函数。
但我想(对于性能问题)是否可以将所有元素(双元素数组)存储在索引缓冲区对象(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可以做到这一点,但我不知道该怎么做。
或者这可能真的不可能。也许在参数索引数组中输入directy的事实比使用glDrawRangeElements及其IBO的方法更快,因此在这种情况下IBO的使用可能已被弃用,因此不适应。
你怎么看?
答案 0 :(得分:7)
您当然可以使用glMultiDrawElements()
的索引缓冲区。 OpenGL核心配置文件中不推荐使用客户端索引数组。因此,如果glMultiDrawElements()
无法使用索引缓冲区运行,则无法再使用它了。
要了解它是如何工作的,我们需要看看glMultiDrawElements()
的论点是什么意思。该呼叫基本上只是多个glDrawElemens()
呼叫的快捷方式。签名是:
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个子范围:
我将使用无符号短路(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);