Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

understanding glVertexAttribPointer?

Tags:

opengl

vbo

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);

The vertex shader code looks like

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

So, here is my understanding. The purpose of glVertexAttribPointer is to define the format of data in the vertex buffer object. So, in vbo it stores data as follows

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());

So, we have two glVertexAttribPointer lines because we have two variables defined in the vertex shader. So basically we are defining what these two variables point to. So, the first glVertexAttribPointer defines that the first variable "position" is a vertex with three coordinates each being float. The second glVertexAttribPointer defines the second variable "texCoord" being a pair of texture coordinates each being float. So, if my understanding is correct so far then i was assuming we first need to bind the vertex buffer object first but even after commenting out this line

glBindBuffer(GL_ARRAY_BUFFER, vbo);

it still works. I am confused. How does it know which buffer object we are talking about since there are two vbos?

like image 620
user3256520 Avatar asked Jul 21 '14 23:07

user3256520


People also ask

What is stored in a VAO?

A Vertex Array Object (VAO) is an OpenGL Object that stores all of the state needed to supply vertex data (with one minor exception noted below). It stores the format of the vertex data as well as the Buffer Objects (see below) providing the vertex data arrays.

What does a VAO do?

A Vertex Array Object (VAO) is an object which contains one or more Vertex Buffer Objects and is designed to store the information for a complete rendered object. In our example this is a diamond consisting of four vertices as well as a color for each vertex.

When should I call Enablevertexattribarray?

If you're not using VAOs, then you would usually call glVertexAttribPointer (and the corresponding glEnableVertexAttribArray ) right before rendering to setup the state properly.

What are VAOs and VBOS?

A VBO is a buffer of memory which the gpu can access. That's all it is. A VAO is an object that stores vertex bindings. This means that when you call glVertexAttribPointer and friends to describe your vertex format that format information gets stored into the currently bound VAO.


1 Answers

@datenwolf already covered the key aspect in a comment above. To elaborate some more:

You do not have to bind GL_ARRAY_BUFFER again before the glDrawElements() call. What matters is that the buffer you want to source a given attribute from is bound when you make the glVertexAttribPointer() call for that attribute.

The best way to picture this is that when you make this call:

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

you're specifying all the state needed to tell OpenGL where to get the data for attribute 0 (first argument) from, and how to read it. Most of that state is given directly by the arguments:

  • it has 3 components
  • the components are float values
  • vertices are read with a stride of 20 bytes...
  • ... and starting at byte 0 of the buffer

But there's an additional implied piece of state that is also stored away for attribute 0 when you make the call:

  • the data is read from the buffer currently bound to GL_ARRAY_BUFFER

In other words, the state associated with each attribute includes the id of the buffer the attribute data is sourced from. This can be the same buffer for multiple/all attributes, or it can be a different buffer for each attribute.

Note that the same is not true for GL_ELEMENT_ARRAY_BUFFER. That one needs to be bound at the time of the glDrawElements() call. While it seems somewhat inconsistent, this is necessary because there's no equivalent to glVertexAttribPointer() for the index array. The API could have been defined to have this kind of call, but... it was not. The reason is most likely that it was simply not necessary, since only one index array can be used for a draw call, while multiple vertex buffers can be used.

like image 75
Reto Koradi Avatar answered Sep 22 '22 11:09

Reto Koradi