glVertexAttribPointer
glVertexAttribPointer
RifglVertexAttribPointer 是将 VBO 中的原始数据与顶点着色器(Vertex Shader)中的属性(layout(location = ...))关联起来的关键桥梁。当你的顶点数据变得复杂时(比如同时包含位置、颜色、纹理坐标),理解它的每个参数就变得至关重要。
我们先用一个包含位置(Position)和纹理坐标(Texture Coordinate)的顶点数组作为例子,然后为你整理一份清晰的笔记。
示例场景:渲染一个带纹理的正方形
我们要画一个由两个三角形组成的正方形。每个顶点都需要两个信息:
- 它在屏幕上的位置 (x, y)。
- 它对应纹理图片的哪个坐标 (s, t)。
1. 准备顶点数据 (在 CPU 端)
我们把位置和纹理坐标交错(Interleaved)存放在一个数组里。这样做通常性能更好,因为 GPU 在读取一个顶点的数据时,所有相关属性都在内存中相邻的位置。
1 | float vertices[] = { |
- 这个正方形有4个顶点。
- 每个顶点有
2个float(位置) +2个float(纹理坐标) =4个float。 - 整个数组有
4个顶点 * 4个float/顶点 = 16个float。
2. 在顶点着色器中定义输入
我们的顶点着色器 (vertex.shader) 需要接收这两种数据:
1 |
|
3. 使用 glVertexAttribPointer 进行解析
现在,我们已经用 glBufferData 把 vertices 数组发送到了 GPU 的 VBO 中。GPU 看到的是一长串的、没有结构的字节流。glVertexAttribPointer 的任务就是告诉 GPU 如何去解读这串字节。
我们需要调用两次 glVertexAttribPointer,一次为位置属性,一次为纹理坐标属性。
1 | // 假设VBO和VAO已经绑定好了 (glBindBuffer, glBindVertexArray) |
可视化解读:
学习笔记:glVertexAttribPointer 函数
1. 核心作用
glVertexAttribPointer 的核心作用是“定义顶点数据在内存中的布局”。它告诉 OpenGL 如何从当前绑定的 GL_ARRAY_BUFFER(VBO)中提取数据,并将其发送到顶点着色器中特定 location 的 in 变量。
这个函数的所有设置都会被记录在当前绑定的顶点数组对象(VAO)中。
2. 函数原型
1 | void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); |
3. 参数详解
GLuint index- 含义: 顶点属性的位置索引(Location Index)。
- 作用: 指定要配置哪个顶点属性。这个值必须与顶点着色器中的
layout(location = ...)相匹配。 - 示例:
0对应layout(location = 0) in vec3 aPos;。
GLint size- 含义: 每个顶点该属性的分量数量。
- 作用: 指定该属性由几个值组成。例如,一个 2D 位置是2个,3D 位置是3个,RGB 颜色是3个。这个值必须是 1, 2, 3 或 4。
- 示例:
2表示位置由x和y两个分量组成。
GLenum type- 含义: 属性分量的数据类型。
- 作用: 指定数组中每个分量是什么类型。
- 示例:
GL_FLOAT,GL_INT,GL_UNSIGNED_BYTE等。最常用的是GL_FLOAT。
GLboolean normalized- 含义: 是否需要将数据标准化。
- 作用: 如果设为
GL_TRUE,非浮点类型的数据(如GL_INT,GL_UNSIGNED_BYTE)会被映射到[0, 1](无符号)或[-1, 1](有符号)的范围内。对于浮点数,此参数无效。 - 示例: 通常设为
GL_FALSE。对于用0-255的unsigned byte表示的颜色,可以设为GL_TRUE,OpenGL 会自动将其转换为0.0-1.0的浮点颜色。
GLsizei stride- 含义: 步长,即两个连续顶点之间相隔的字节数。
- 作用: 告诉 OpenGL 在读取完一个顶点的这个属性后,要跳过多少字节才能找到下一个顶点的相同属性。
- 计算: 一个完整顶点占用的总字节数。在我们的例子中,一个顶点是
(pos.x, pos.y, tex.s, tex.t),共 4 个 float,所以步长是4 * sizeof(float)。 - 特殊值: 如果设为
0,表示数据是紧密排列的(Tightly Packed),OpenGL 会自动计算步长(size * sizeof(type))。这只在 VBO 中只有一种属性时才适用。
const void* pointer- 含义: 偏移量,即在一个顶点的数据块中,该属性从何处开始。
- 作用: 指定属性在顶点数据块内的起始位置的字节偏移。
- 计算: 它是一个从顶点数据块开始位置的字节偏移量。在我们的例子中,位置属性从
0开始,纹理坐标属性在位置属性(2个float)之后,所以偏移量是2 * sizeof(float)。 - 注意: 参数类型是
void*,但它代表的是字节偏移量,不是一个真正的指针。需要进行类型转换,如(const void*)0。
4. 不要忘记 glEnableVertexAttribArray
调用 glVertexAttribPointer 只是配置了如何解析数据,但属性默认是禁用的。必须调用 glEnableVertexAttribArray(index) 来启用该属性槽,否则数据不会被发送到顶点着色器。