【问题标题】:OpenGL Batch render MeshOpenGL 批量渲染网格
【发布时间】:2014-06-09 20:31:41
【问题描述】:

我正在使用 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 下降了。

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

【问题讨论】:

  • 这就是顶点着色器和实例化的用途。问题是因为您使用的是glVertexPointer (...) 等。我真的不知道您使用的是什么版本的GL;实例化在 GL 3.1 中被提升为核心,但此代码可能与 GL 1.5 一样古老。您能否提及您使用什么版本的 GL 来简化编写答案?
  • @AndonM.Coleman,其实我真的不知道我在用什么版本,但它可能是最后一个,我不知道
  • @AndonM.Coleman,我仍在使用很多旧的和已弃用的函数
  • 嗯,你在使用着色器吗?这是一个很好的起点。即使没有 GL 的支持,您也可以使用一些技术进行实例化,但它们至少需要顶点着色器。
  • @AndonM.Coleman:我同意这一点。通过使用着色器并学习如何编写它们(尤其是顶点着色器),他会对他的问题有一个自然的答案。 (只需在统一缓冲区中设置新的世界矩阵后发出多个绘制调用)

标签: opengl mesh glew 3d-modelling


【解决方案1】:

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

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

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

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 核心配置文件中可用。

【讨论】:

  • 是什么让您出于好奇而认为这是 OpenGL 2.1?我看到的只有顶点数组(OpenGL 1.1)和缓冲区对象(OpenGL 1.5)。
  • 可能是一个严重的 MacOsX 偏见。十年来,2.1 一直是超级默认版本。
  • 嗯,没错。 (回想起来,我已经编写了 OpenGL 1.x 代码,它使用了顶点数组并检查了是否支持缓冲区对象)在这种情况下,我将补充一点,ARB_Instanced_Arrays 可能早在很久以前就可用与 OpenGL 1.1 一样,而 ARB_Draw_Instanced(因为它需要可编程着色器才能使用)至少需要 OpenGL 2。
  • 硬件实例化很可爱,但如果渲染的网格不仅仅是一个立方体,它并不能提高性能。写入组合内存用于将命令流式传输到图形卡,多个绘图调用很好地流水线化,并且在网格模型描绘必须至少有一千个三角形的人的情况下不会导致足够的开销来看到胜利。
  • @v.oddou 在现代计算机图形学中,性能从来没有你想象的那么简单。
猜你喜欢
  • 2021-10-30
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 2018-02-11
  • 2016-03-19
  • 2019-05-22
  • 1970-01-01
  • 2014-04-15
相关资源
最近更新 更多