OpenGL glVertexAttribPointer()函数解析

 

  • glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
  • glEnableVertexAttribArray(0);glVertexAttribPointer函数的参数非常多,所以我会逐一介绍它们:    第一个参数指定我们要配置的顶点属性。还记得我们在顶点着色器中使用layout(location = 0)定义了position顶点属性的位置值(Location)吗?它可以把顶点属性的位置值设置为0。因为我们希望把数据传递到这一个顶点属性中,所以这里我们传入0。    第二个参数指定顶点属性的大小。顶点属性是一个vec3,它由3个值组成,所以大小是3。    第三个参数指定数据的类型,这里是GL_FLOAT(GLSL中vec*都是由浮点数值组成的)。    下个参数定义我们是否希望数据被标准化(Normalize)。如果我们设置为GL_TRUE,所有数据都会被映射到0(对于有符号型signed数据是-1)到1之间。我们把它设置为GL_FALSE。    第五个参数叫做步长(Stride),它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在3个float之后,我们把步长设置为3 * sizeof(float)。要注意的是由于我们知道这个数组是紧密排列的(在两个顶点属性之间没有空隙)我们也可以设置为0来让OpenGL决定具体步长是多少(只有当数值是紧密排列时才可用)。一旦我们有更多的顶点属性,我们就必须更小心地定义每个顶点属性之间的间隔,我们在后面会看到更多的例子(译注: 这个参数的意思简单说就是从这个属性第二次出现的地方到整个数组0位置之间有多少字节)。    最后一个参数的类型是void*,数据指针, 这个值受到VBO的影响;1:在不使用VBO的情况下,就是一个指针,指向的是需要上传到顶点数据指针,项目中通常在不使用VBO的情况下,绘制之前,执行glBindBuffer(GL_ARRAY_BUFFER, 0),否则会导致数组顶点无效,界面无法显示;2:使用VBO的情况下,先要执行glBindBuffer(GL_ARRAY_BUFFER, 1),如果一个名称非零的缓冲对象被绑定至GL_ARRAY_BUFFER目标(见glBindBuffer)且此时一个定点属性数组被指定了,那么pointer被当做该缓冲对象数据存储区的字节偏移量。并且,缓冲对象绑定(GL_ARRAY_BUFFER_BINDING)会被存为索引为index的顶点属性数组客户端状态;此时指针指向的就不是具体的数据了。因为数据已经缓存在缓冲区了。这里的指针表示位置数据在缓冲中起始位置的偏移量(Offset)。由于位置数据在数组的开头,所以这里是0。我们会在后面详细解释这个参数。每个顶点属性从一个VBO管理的内存中获得它的数据,而具体是从哪个VBO(程序中可以有多个VBO)获取则是通过在调用glVertexAttribPointer时绑定到GL_ARRAY_BUFFER的VBO决定的。由于在调用glVertexAttribPointer之前绑定的是先前定义的VBO对象,顶点属性0现在会链接到它的顶点数据。以下使具体的例子:    1:virtual void Draw(const EtFrame *frame)
{
glClearColor(0.5, 0.5, 0.5, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float vertices[] = {
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 顶部
};
//GLuint VBO;
//glGenBuffers(1, &VBO);
//glBindBuffer(GL_ARRAY_BUFFER, VBO);
//glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, 0);//这个解绑不能少了,否则绘制不出来。
EsProgramParticle *prog = EsGetProgramParticle();
if (NULL == prog) return;
glUseProgram(prog->program);

glEnableVertexAttribArray(prog->a_xyz);
glEnableVertexAttribArray(prog->a_rgba);
glVertexAttribPointer(prog->a_xyz, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), vertices);
glVertexAttribPointer(prog->a_rgba, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(vertices + 3));
//glVertexAttribPointer(prog->a_xyz, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void *)0);// (void *)0);
//glVertexAttribPointer(prog->a_rgba, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(3 * sizeof(float)));

glDrawArrays(GL_TRIANGLES, 0, 3);
}
};
  • 2:virtual void Draw(const EtFrame *frame)
{
glClearColor(0.5, 0.5, 0.5, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float vertices[] = {
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 顶部
};
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

//glBindBuffer(GL_ARRAY_BUFFER, 0);//这个不能解绑,否则也绘制不出来。
EsProgramParticle *prog = EsGetProgramParticle();
if (NULL == prog) return;
glUseProgram(prog->program);

glEnableVertexAttribArray(prog->a_xyz);
glEnableVertexAttribArray(prog->a_rgba);

//glVertexAttribPointer(prog->a_xyz, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), vertices);
//glVertexAttribPointer(prog->a_rgba, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(vertices + 3));
glVertexAttribPointer(prog->a_xyz, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void *)0);// (void *)0);
glVertexAttribPointer(prog->a_rgba, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(3 * sizeof(float)));

glDrawArrays(GL_TRIANGLES, 0, 3);
}
};