选项 1:为每个着色器创建不同的 VAO
VAO 定义了着色器属性的映射(例如,从 VBO 中的此内存位置读取 vec3,步长为 N 字节,并将其映射到绑定到位置 X 的属性)。
一些用于存储 VAO 名称的全局变量
GLuint g_vao;
然后创建它(对于您在着色器中定义的数据布局):
// create the VAO
glCreateVertexArrays(1, &g_vao);
// set up: layout(location = 0) in vec3 aPos;
glEnableVertexArrayAttrib(g_vao, 0); //< turn on attribute bound to location 0
// tell OpenGL that attribute 0 should be read from buffer 0
glVertexArrayAttribBinding(
g_vao, //< the VAO
0, //< the attribute index (location = 0)
0); //< the vertex buffer slot (start from zero usually)
// tell openGL where within the buffer the data exists
glVertexArrayAttribFormat(
g_vao, //< the VAO
0, //< the attribute index
3, //< there are 3 values xyz
GL_FLOAT, //< all of type float
GL_FALSE, //< do not normalise the vectors
0); //< the offset (in bytes) from the start of the buffer where the data starts
// set up: layout(location = 1) in vec4 aBoneWeights
glEnableVertexArrayAttrib(g_vao, 1); //< turn on attribute bound to location 0
// tell OpenGL that attribute 1 should be read from buffer 0
glVertexArrayAttribBinding(
g_vao, //< the VAO
1, //< the attribute index (location = 1)
0); //< the vertex buffer slot (start from zero usually)
// tell openGL where within the buffer the data exists
glVertexArrayAttribFormat(
g_vao, //< the VAO
1, //< the attribute index
4, //< there are 4 values
GL_FLOAT, //< all of type float
GL_FALSE, //< do not normalise the vectors
sizeof(float) * 8); //< the offset (in bytes) from the start of the buffer where the data starts
// set up: layout(location = 2) in vec4 aBoneIndices;
glEnableVertexArrayAttrib(g_vao, 2); //< turn on attribute bound to location 2
// tell OpenGL that attribute 2 should be read from buffer 0
glVertexArrayAttribBinding(
g_vao, //< the VAO
2, //< the attribute index (location = 2)
0); //< the vertex buffer slot (start from zero usually)
// tell openGL where within the buffer the data exists
glVertexArrayAttribFormat(
g_vao, //< the VAO
2, //< the attribute index
4, //< there are 4 values xyz
GL_FLOAT, //< all of type float
GL_FALSE, //< do not normalise the vectors
sizeof(float) * 12); //< the offset (in bytes) from the start of the buffer where the data starts
但是,我认为属性 2 的着色器定义是错误的(因为您必须将骨骼索引作为浮点数据传递,这对我来说感觉非常错误!)。
我原以为你会想要整数而不是浮点数:
layout(location = 2) in ivec4 aBoneIndices;
但是当绑定整数时,你需要使用glVertexArrayAttribIFormat而不是glVertexArrayAttribFormat:
glVertexArrayAttribIFormat(
g_vao, //< the VAO
2, //< the attribute index
4, //< there are 4 indices
GL_UNSIGNED_INT, //< all of type uint32
sizeof(float) * 12);
在所有这些之后,您需要将顶点缓冲区绑定到您在上面使用的顶点槽零...
glVertexArrayVertexBuffer(
g_vao, //< the VAO
0, //< the vertex buffer slot
0, //< offset (in bytes) into the buffer
sizeof(float) * 16); //< num bytes between each element
选项 2:使用相同的 VAO 和相同的 VBO
只需将索引编码为具有特定含义,然后您就可以始终使用相同的 VAO。
layout(location = 0) in vec3 aPos;
//layout(location = 1) in vec4 aCol; //< not used in this shader
//layout(location = 2) in vec4 aUv; //< not used in this shader
layout(location = 3) in vec4 aBoneWeights;
layout(location = 4) in vec4 aBoneIndices;
/编辑
在回答您的问题时,这在很大程度上取决于您使用的 OpenGL 版本。我在此处发布的答案使用了 OpenGL4.5 中最新的直接状态访问 (DSA) 扩展。如果您可以使用它们,我强烈建议您这样做。
OpenGL 3.0:glVertexAttribPointer
是的,这会起作用。然而,它是一种与 OpenGL 的 bind 范式密切相关的机制。每个属性都有效地绑定到调用 glVertexAttribPointer 时绑定的缓冲区(即,您将执行以下操作:glBindBuffer(); glEnableVertexAttribArray(); glVertexAttribPointer();)。
这样做的问题是它有点锁定你为每个 VBO(或一组 VBO,如果从多个数据中提取数据)创建 VAO,因为属性绑定到确切的指定该属性时绑定的缓冲区。
OpenGL 4.3:glVertexAttribFormat
这个版本很像我上面介绍的那个。与其将 VAO 传递给函数调用,不如先调用 glBindVertexArray(如果搜索上述方法的文档,没有 VAO 参数的方法只使用当前绑定的 VAO)。
这种方法相对于旧 API 的优势在于,将 VAO 绑定到另一个 VBO(s) [i.e.您可以将 VAO 与 GLSL 程序相关联,而不是为每个 VBO/程序对设置一个 VAO]- 只需为每个 VBO 调用 glBindVertexBuffer,它就会很好地工作。
OpenGL 4.5:glVertexArrayAttribFormat
从长远来看,这是迄今为止最容易使用的 API 版本。主要优点是您无需担心当前绑定了哪个 VAO(因为您将它作为参数传入)。这有很多优点,因为您不再关心绑定了哪个 VAO,而且它还为从不同线程修改 OpenGL 对象打开了大门(旧 API 版本不允许这样做)。