1

我正在使用 OpenGL、glew 和 GLFW 为项目编写一个简单的游戏。我已经有一个使用 Assimp 的 3D 模型导入器,它也可以处理纹理。

这是我绘制一个网格的方式:

    glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[NORMAL_VB]);
    glNormalPointer(GL_FLOAT, 0, NULL);

    glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[TEXCOORD_VB]);
    glTexCoordPointer(2, GL_FLOAT, 0, NULL);

    glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[POS_VB]);
    glVertexPointer(3, GL_FLOAT, 0, NULL);

    //Render the triangles
    glDrawArrays(GL_TRIANGLES, 0, m_Entries[i].NumIndices);

我的问题是如何使用同一个网格渲染数百个移动实体,但每个实体都有不同的世界位置和旋转?

如果我有数百个移动实体,每一帧我都会渲染相同的网格数百次,我现在可以注意到 FPS 下降。

顺便说一句,我没有使用着色器,只是简单的绘制

4

1 回答 1

2

由于glVertexPointer()(和其他gl<Foo>Pointer()调用)在 OpenGL 3 及更高版本中已弃用,我假设您当前未使用 OpenGL 3+ 核心配置文件。

有两种可能可用的实例化渲染方法,都通过扩展提供; ARB_Draw_InstancedARB_Instanced_Arrays。在任何特定的卡/驱动程序上都可能不可用,或者两者都不可用,或者都不可用。

ARB_Draw_Instanced提供,它的工作原理与您已经在使用glDrawArraysInstancedARB()的调用基本相似,但还提供了一个整数变量供您的着色器使用,然后您可以使用它从 UBO、TBO、或您想使用的任何其他机制将每个实例的数据导入着色器。理论上,这个扩展可以在 OpenGL 1.1 的上下文中使用。glDrawArraysgl_InstanceId

ARB_Instanced_Arrays提供glVertexAttribDivisorARB(),它允许您修改特定顶点属性的工作方式。在顶点着色器中,每个后续顶点通常从附加的缓冲区中获取下一个属性值。所以第一个顶点获取缓冲区中第一个指定的位置,第二个顶点获取第二个位置,依此类推。使用此函数,您可以告诉 OpenGL 根据实例而不是根据顶点来推进提供给着色器的数据。因此,例如,您可以创建一个通用顶点属性,其中包含将要绘制的所有实例的世界位置,并告诉 OpenGL 仅在实例之间更新该值,因此第一个实例的每个顶点都获得第一个值,第二个实例的每个顶点都获得第二个值,依此类推。从着色器的角度来看,这些值现在被视为顶点属性,而不是统一。理论上,这个扩展可以在 OpenGL 2 的上下文中使用。

在我的硬件上,这些方法都不能在 OpenGL 2.1 上下文中使用(因为这些扩展或相关的扩展没有公开)。你的电脑可能和我的一样;无法在 OpenGL 2.1 上下文中进行实例化渲染。或者你的可能支持这两种方法。或者只是其中之一。同样,您向其提供程序的任何其他人可能会发现他们的计算机支持其中一种或两种,或两者都不支持。扩展就是这样,无论主机支持什么,你的程序都应该能够应付。

就我而言,不是根据计算机支持的内容来处理单独的实现,“简单”的解决方案是切换到 OpenGL 3+ 上下文,其中两个接口都以非扩展形式提供。

glDrawArraysInstanced()(上述 ARB 接口的非扩展版本)在 OpenGL 3.1 中成为核心,因此保证存在于每个 3.1 核心配置文件中。同样,glVertexAttribDivisor()它被添加到 OpenGL 3.3 的核心配置文件中,并将在每个 3.3 核心配置文件中可用。

于 2014-06-10T00:58:00.387 回答