2014-07-21 24 views
5

我是Open GL的新手,来到这里清除了我的困惑。我感谢任何帮助!了解glVertexAttribPointer?

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”,它是一对纹理坐标,每个纹理坐标都是浮点型坐标。所以,如果我的理解到目前为止是正确的,那么我假设我们首先需要绑定顶点缓冲区对象,但即使在注释掉这一行之后,即使在注释掉这一行之后也不例外。

它仍然有效。我很困惑。它如何知道我们正在讨论哪个缓冲区对象,因为有两个vbos?

我很感激任何帮助。非常感谢!

+1

没有两个VBO。有一个VBO和一个IBO。他们都可以(并且必须)同时保持约束。 – fintelia

+0

那么这是否意味着如果有两个VBO,那么我们需要显式绑定它,但既然只有一个,那么默认绑定它? – user3256520

+2

@fintelia:其实没有。在调用'gl ... Pointer'后,您可以安全地解除绑定VBO,在调用'gl ... Pointer'函数时与VBO绑定的关联不会丢失。 – datenwolf

回答

14

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

你这样做不是必须在调用glDrawElements()之前再次绑定GL_ARRAY_BUFFER。重要的是,当您为该属性调用glVertexAttribPointer()时,要从中获取给定属性的缓冲区将被绑定。

以图片的最佳方法是,当你做这样的判断:

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

你指定要告诉OpenGL从哪里得到的属性0的数据(第一个参数)所需的所有状态,以及如何阅读它。大多数国家由参数直接给出:

  • 它有3个组成部分
  • 组件是浮点值
  • 顶点具有的20个字节的步幅读...
  • ...并开始缓冲

的0字节但是,当你拨打电话有状态的附加隐含一块也存储离开属性0:

  • 将数据从当前绑定到GL_ARRAY_BUFFER

换句话说缓冲器读出,与每个属性相关联的所述状态包括所述缓冲器中的属性数据被从源的ID。这可以是多个/所有属性的相同缓冲区,也可以是每个属性的不同缓冲区。

请注意,对GL_ELEMENT_ARRAY_BUFFER也是如此。在拨打电话glDrawElements()时需要绑定该号码。虽然看起来有些不一致,但这是必要的,因为索引数组没有相当于glVertexAttribPointer()。 API可能已被定义为具有这种呼叫,但是......它不是。原因很可能是它没有必要,因为只有一个索引数组可用于绘图调用,而多个顶点缓冲区可以使用。

+0

总之我已经绑定了这两个缓冲区.. glBindBuffer(GL_ARRAY_BUFFER,vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibo);因此我不需要重新绑定......正确? – user3256520

+0

当然,你不需要重新绑定已绑定的缓冲区。我在回答中想要说明的是哪些缓冲区必须针对哪些呼叫进行绑定。 –