3

I understand how to create the vertex and fragments shaders and how to create vertex arrays and put them on the buffer, but how do i link the two?

Meaning - when i run my program, how does it know that the vertices array that is on the currently active buffer should be "fed" to the vertex shader?

Is that being done simply by using glVertexAttribPointer?

genpfault
  • 51,148
  • 11
  • 85
  • 139
gambit20088
  • 321
  • 2
  • 12

1 Answers1

4

how does it know that the vertices array that is on the currently active buffer should be "fed" to the vertex shader

The "currently active buffer", i.e. GL_ARRAY_BUFFER, isn't used during the draw call. It's only purpose is to tell the glVertexAttribPointer functions which buffer to bind to the VAO. Once this connection is established GL_ARRAY_BUFFER can be unbound.

... but how do i link the two?

The link between your vertex arrays and the vertex shader is the currently active vertex array object (VAO). The pipeline will fetch the vertex attributes that the shader needs from the buffers that were bound to the VAO.

It may help to summarized VAO state as the following pseudo-C definitions:

struct VertexArrayObject
{
    // VertexArrayElementBuffer
    uint element_buffer;

    struct Binding {
        // VertexArrayVertexBuffers
        uint buffer;
        intptr offset;
        sizei stride;

        // VertexArrayBindingDivisor
        uint divisor;
    } bindings[];

    struct Attrib {
        // VertexArrayAttribBinding
        uint binding; // This is an index into bindings[]

        // EnableVertexArrayAttrib
        bool enabled;

        // VertexArrayAttrib*Format
        int size;
        enum type;
        boolean normalized;
        boolean integer;
        boolean long;
        uint relativeoffset;
    } attribs[];
};

The comments mention the corresponding OpenGL 4.5 DSA function that can be used to set the respective state.

When you use glVertexAttribPointer, it essentially does the following on the currently bound VAO:

vao.attribs[index].binding = index;
vao.attribs[index].size = size;
vao.attribs[index].type = type;
vao.attribs[index].normalized = normalized;
vao.attribs[index].relativeoffset = 0;
vao.bindings[index].buffer = current ARRAY_BUFFER;
vao.bindings[index].offset = pointer;
vao.bindings[index].stride = stride; // if stride == 0 computes based on size and type

Notice that it's the glVertexAttribPointer call that binds the 'active' buffer to the VAO. If instead you set up your VAO using the direct state access API (DSA), you don't even need to ever 'activate' any buffer.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • Okay, and just to make sure i understand - the alternative to using VAO (which is not recommended) is to "redeclare" `glVertexAttribPointer` every time you have to tell the GPU how to handle the data in the buffer? – gambit20088 Jan 08 '17 at 20:37
  • Err what? You **must** use a VAO with OpenGL 3 onwards to transfer primitives to the GPU. – Yakov Galka Jan 08 '17 at 20:39
  • Also, in the first parameter of `glVertexAttribPointer`, i write a reference to a shader variable, right? Is that how the program knows to send the vertices to the shader? – gambit20088 Jan 08 '17 at 20:39
  • Yes, it's the attribute index, which you can specify with the `layout(location = n)` specifier in the shader. – Yakov Galka Jan 08 '17 at 20:44
  • Okay, thanks! Last question, i swear! haha I'm pretty sure the answer is "yes" but i want to double check. So the whole idea of VAO is for me to bind one, then create and bind a buffer with some data, a `glVertexAttribPointer`, etc... Then bind another VAO, and create a different buffer with other data and a different pointer, and then i could just switch between the VAOs and the subsequent draw calls will use the currently bounded VAO? – gambit20088 Jan 08 '17 at 21:00
  • Yes. Though in more 'advanced' scenarios you may use the same buffer in different VAOs. – Yakov Galka Jan 08 '17 at 21:03