理解glVertexAttribPointer?

use*_*520 8 opengl vbo

我是Open GL的新手,来到这里清除我的困惑.我感谢任何帮助!

private int vbo;
private int ibo;

vbo = glGenBuffers();
ibo = glGenBuffers();

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, Util.createFlippedBuffer(vertices), GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, Util.createFlippedBuffer(indices), GL_STATIC_DRAW);




glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
//glEnableVertexAttribArray(2);

//glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, false, Vertex.SIZE * 4, 12);
//glVertexAttribPointer(2, 3, GL_FLOAT, false, Vertex.SIZE * 4, 20);

//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
//glDisableVertexAttribArray(2);
Run Code Online (Sandbox Code Playgroud)

顶点着色器代码看起来像

#version 330

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;

out vec2 texCoord0;

uniform mat4 transform;

void main()
{
    gl_Position = transform * vec4(position, 1.0);
    texCoord0 = texCoord;
}
Run Code Online (Sandbox Code Playgroud)

所以,这是我的理解.glVertexAttribPointer的目的是定义顶点缓冲区对象中的数据格式.因此,在vbo中,它存储数据如下

buffer.put(vertices[i].getPos().getX());
buffer.put(vertices[i].getPos().getY());
buffer.put(vertices[i].getPos().getZ());
buffer.put(vertices[i].getTexCoord().getX());
buffer.put(vertices[i].getTexCoord().getY());
buffer.put(vertices[i].getNormal().getX());
buffer.put(vertices[i].getNormal().getY());
buffer.put(vertices[i].getNormal().getZ());
Run Code Online (Sandbox Code Playgroud)

因此,我们有两个glVertexAttribPointer行,因为我们在顶点着色器中定义了两个变量.所以基本上我们正在定义这两个变量指向的内容.因此,第一个glVertexAttribPointer定义第一个变量"position"是一个顶点,其中三个坐标都是float.第二个glVertexAttribPointer定义第二个变量"texCoord"是一对纹理坐标,每个纹理坐标都是浮点数.所以,如果到目前为止我的理解是正确的,那么我假设我们首先需要首先绑定顶点缓冲区对象,但即使在注释掉这一行之后

glBindBuffer(GL_ARRAY_BUFFER,vbo);

它仍然有效.我很迷惑.由于有两个vbos,它如何知道我们正在讨论哪个缓冲区对象?

我感谢任何帮助.非常感谢!

Ret*_*adi 17

@datenwolf已经涵盖了上述评论中的关键方面.详细说明:

具备约束GL_ARRAY_BUFFER的前再次glDrawElements()呼叫.重要的是,当您glVertexAttribPointer()调用该属性时,您要从其中获取给定属性的缓冲区将被绑定.

拍照的最佳方式是,当您拨打此电话时:

glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
Run Code Online (Sandbox Code Playgroud)

你要指定告诉OpenGL从哪里获取属性0(第一个参数)的数据以及如何读取它所需的所有状态.该状态的大部分直接由参数给出:

  • 它有3个组件
  • 组件是浮点值
  • 以20字节的步幅读取顶点...
  • ...从缓冲区的字节0开始

但是,当您拨打电话时,还有另外一个隐含的状态,也会存储为属性0:

  • 从当前绑定的缓冲区中读取数据 GL_ARRAY_BUFFER

换句话说,与每个属性相关联的状态包括属性数据源自的缓冲区的id.这可以是多个/所有属性的相同缓冲区,也可以是每个属性的不同缓冲区.

请注意,情况并非如此GL_ELEMENT_ARRAY_BUFFER.那个人需要在glDrawElements()通话时受到约束.虽然看起来有点不一致,但这是必要的,因为glVertexAttribPointer()索引数组没有等价物.可以定义API来进行这种调用,但是......事实并非如此.原因很可能是根本没有必要,因为只有一个索引数组可以用于绘制调用,而可以使用多个顶点缓冲区.