通常我会尝试将网格特定信息(VBO/VAO)与实例特定信息(变换、统一等)分离。
通过这种方式,操作实例信息的代码部分不需要知道任何关于VBO/VAO的信息,反之亦然。
然而,最近我开始使用glDrawInstanced使用硬件实例化,并且实例属性在VAO中绑定在一起的事实使我更难分离关注点。
原因是通常VBO/VAO是从我的.OBJ加载程序(它拥有构建此加载程序所需的所有信息)构建的,然后代码的其他部分只担心着色器统一性。现在,代码的这些部分需要了解VAO的结构,以便附加有关其实例属性的信息。
当我有VBO时,这会变得更加令人讨厌,这些VBO可能会被重新用于普通渲染和实例化渲染。
是否有一种推荐的方法可以在设置网格属性和实例属性之间保持关注点的分离?
我想过有两个VAO,一个用于正常渲染,另一个用于实例化渲染,在那里我将添加我需要的额外实例属性,但我找不到复制或检查原始VAO数据的方法,所以我的组件似乎需要知道VBO/VAO的实际结构,而不仅仅是实例参数。
找到了一种方法!
我忘记了您实际上可以通过使用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。