了解glVertexAttribPointer?

问题描述 投票:10回答:1
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);

顶点着色器的代码看起来像

#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;
}

所以,这是我的理解。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());

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

glBindBuffer(GL_ARRAY_BUFFER, vbo);

还能用。我很困惑,既然有两个vbos,它怎么知道我们说的是哪个缓冲对象?既然有两个vbos,它怎么知道我们说的是哪个缓冲区对象?

opengl vbo
1个回答
19
投票

@datenwolf已经在上面的评论中涵盖了关键方面。再详细说明一下。

你要做的是 束缚 GL_ARRAY_BUFFER 再到 glDrawElements() 调用。重要的是,当你调用 glVertexAttribPointer() 调用该属性。

最好的方式是,当您进行这个调用时,您指定了所有必要的状态来告诉OpenGL从哪里获取属性0(第一个参数)的数据以及如何读取它。

glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);

你指定了所有需要的状态来告诉OpenGL从哪里获取属性0(第一个参数)的数据,以及如何读取它。大部分状态是由参数直接提供的。

  • 它有三个组成部分
  • 分量是浮动值
  • 读取顶点的步长为20个字节... ...
  • ...... 从缓冲区的第0字节开始。

但是当你进行调用时,还有一个额外的隐含的状态也被存储起来,用于属性0。

  • 数据会从当前绑定到的缓冲区中读出 GL_ARRAY_BUFFER

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

请注意,对于 GL_ELEMENT_ARRAY_BUFFER. 那个人需要被捆绑的时候。glDrawElements() 呼叫。虽然看起来有些不一致,但这是必要的,因为没有等价的 glVertexAttribPointer() 的索引数组。API本来可以定义这样的调用,但是......它没有。原因很可能是它根本没有必要,因为只有一个索引数组可以用于绘制调用,而多个顶点缓冲区可以使用。

© www.soinside.com 2019 - 2024. All rights reserved.