VBO 最有可能(但并非总是如此!)分配在 GPU 的内存中。直到最近,glBufferData 还是在 VBO 上分配内存的唯一方法(如果您使用的是 GL4.5,现在推荐使用 glBufferStorage 来分配内存)。 VBO 中的数据基本上只是一大团未知的东西(好吧,GPU 不知道)。从 CPU/main ram,我们调用 glBufferData,GPU 会分配一块内存来保存数据,并盲目地将数据从 main ram 复制到 GPU ram。 GPU 不知道它包含什么......
VAO 只是对缓冲区内存布局的描述。举个例子吧……
- VBO1:包含立方体的顶点和法线数据。
- VBO2:这包含球体的顶点和法线数据。
让我们假设法线和顶点被打包成一个如下所示的结构:
struct VertexNormal {
float vx, vy, vz;
float nx, ny, nz;
};
在这两种情况下,所有这些都是正确的:
- 顶点的偏移量为 0
- 法线的偏移量为 12(即 3 x sizeof(float))
- 每个顶点和法线元素的步幅为 24 (6 x sizeof(float))
此信息需要从 CPU 传递到 GPU,以便 GPU 在渲染时能够正确地将数据从缓冲区读取到顶点属性中。如果没有这些信息,GPU 只会将 VBO 视为一团未知的东西。
我们将此信息传递给 GPU 的方式是通过 VAO。 VAO 存储有关着色器所需的给定顶点属性的以下信息:
- 数据类型(GL_FLOAT、GL_INT 等)
- 元素数量(Vec2、Vec3、Vec4??)
- 每个元素之间的步幅
- 包含该数据的缓冲区 [又名绑定点]
对于相当复杂的着色器来说,每个顶点的信息可能会变得非常大,因此我们不想经常设置它。这就是 VAO 的用武之地。我们创建一个 VAO,并用顶点着色器的每个输入属性的信息填充它。
鉴于我们的立方体和球体可能使用相同的着色器渲染,并且两个缓冲区中的顶点和法线数据相同,我们可以在这种情况下使用 1 VAO(只需更改缓冲区[s]我们与 glVertexArrayVertexBuffers 绑定)。