重用 VBO 进行硬件实例化

Posted

技术标签:

【中文标题】重用 VBO 进行硬件实例化【英文标题】:Reusing VBO for hardware instancing 【发布时间】:2016-04-16 18:39:34 【问题描述】:

通常我会尝试将特定于网格的信息 (VBO/VAO) 与特定于实例的信息(变换、制服等)分开。

通过这种方式,操作实例信息的部分代码不需要了解有关 VBO/VAO 的任何信息,反之亦然。

但是,最近我开始使用 glDrawInstanced 使用硬件实例化,而实例属性在 VAO 中绑定在一起的事实使我的关注点分离变得更加困难。

原因是通常 VBO/VAO 是从我的 .OBJ 加载器(它包含构建它所需的所有信息)构建的,然后代码的其他部分只担心着色器制服。现在,这些部分代码需要了解 VAO 的结构,以便附加有关其实例属性的信息。

当我有可用于正常渲染和实例化渲染的 VBO 时,这变得更加烦人。

是否有推荐的方法可以在设置网格属性和实例属性之间保持关注点分离?

我想有两个 VAO,一个用于普通渲染,另一个用于实例渲染,我将添加我需要的额外实例属性,但我发现无法复制或检查原始 VAO 数据,所以我的组件似乎需要了解 VBO/VAO 的实际结构,而不仅仅是实例参数。

【问题讨论】:

在您的几何图形上创建另一个抽象级别,它将以指定的方式(有或没有实例化)创建和绘制成批数据。 是的,这正是我希望避免的......如果没有其他建议出现,我最终会这样做。 【参考方案1】:

找到了一种方法!

我忘记了您实际上可以使用 glGetVertexAttrib* 检查 VAO 的状态。这允许我的实例参数操作模块实际创建一个新的 VAO 用于实例化并从原始网格 VAO 重建其基本结构,然后为实例化参数添加附加属性。

这样他们可以保持独立于网格的特定顶点结构,并且只需要担心实例化数据的结构。

检查是这样的:

std::vector<VertexAttrib> attribs;
for (int i = 0; ; i++)

  int enabled;
  glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
  if (enabled == 0) break;

  VertexAttrib attrib;
  glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib.size);
  glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib.stride);
  glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib.type);
  glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib.normalized);
  attribs.push_back(attrib);

VertexAttrib 是我自己的存储自省顶点属性状态的结构。

获得自省状态列表后,我只需创建并绑定我的新 VAO 并将其状态设置为与原始 VAO 相同。然后我继续为硬件实例添加额外的属性。这还有一个好处是我可以将这个新的 VAO 绑定到原始 VBO 并重复使用完全相同的网格数据。

然后一切都按照正常的实例化管道进行。如果我需要在不实例化的情况下绘制模型,我也可以只绑定原始的 VAO。

【讨论】:

以上是关于重用 VBO 进行硬件实例化的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Qt 5 中使用带有实例化的 VAO

使用 OpenGL 3.3 进行实例化似乎很慢

OpenGL实例化数组奇怪的顶点位置

设计:重用 QProcess 实例,还是再次实例化?

iPhone iOS 实例化静态 NSString 单元重用标识符的正确方法是啥?

RepGhost:一个通过重新参数化实现硬件高效的Ghost模块