42

It's not obvious from the documentation when glVertexAttribPointer should be called. It looks like it's part of VBO initialisation, but I notice example code calling it during rendering.

glVertexAttribPointer(vertexAttributeId, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), reinterpret_cast<const GLvoid*>(offsetof(Vertex2D, m_x)));

Should glVertexAttribPointer be called during initialisation of a GL_ARRAY_BUFFER or should it be called during rendering (after a call to glBindBuffer)?

Mark Ingram
  • 71,849
  • 51
  • 176
  • 230
  • 2
    Maybe the question you should ask is *what does it do*, not when it should be called. If you know what it does, then when to call it is *obvious*. And if you think "it's part of VBO initialization", then your idea of what this function does is very wrong. – Nicol Bolas Jun 17 '13 at 15:16
  • 1
    @NicolBolas It stores the offset of the attribute data (from the currently bound buffer)? And the attributeId is the location of the attribute in the shader (retrieved from `glGetAttribLocation` or set via `glBindAttribLocation`)? – Mark Ingram Jun 17 '13 at 15:21
  • 2
    "*It stores the offset of the attribute data (from the currently bound buffer)?*" [*Dangerously* incomplete.](http://www.opengl.org/wiki/Vertex_Specification#Vertex_Buffer_Object) It also stores the buffer object to be used for that attribute (as well as [format information](http://www.opengl.org/wiki/Vertex_Specification#Vertex_format) and [stride data](http://www.opengl.org/wiki/Vertex_Specification#Vertex_buffer_offset_and_stride) for it). – Nicol Bolas Jun 17 '13 at 15:26
  • What is your favourite OpenGL learning resource, by the way? – Christian Rau Jun 18 '13 at 14:47
  • 1
    @ChristianRau I mostly read the docs on the OpenGL site. Nicol's site is excellent as well. – Mark Ingram Jun 18 '13 at 15:15

4 Answers4

63

The function glVertexAttribPointer specifies the format and source buffer (ignoring the deprecated usage of client arrays) of a vertex attribute that is used when rendering something (i.e. the next glDraw... call).

Now there are two scenarios. You either use vertex array objects (VAOs) or you don't (though not using VAOs is deprecated and discouraged/prohibited in modern OpenGL). If you're not using VAOs, then you would usually call glVertexAttribPointer (and the corresponding glEnableVertexAttribArray) right before rendering to setup the state properly. If using VAOs though, you actually call it (and the enable function) inside the VAO creation code (which is usually part of some initialization or object creation), since its settings are stored inside the VAO and all you need to do when rendering is bind the VAO and call a draw function.

But no matter when you call glVertexAttribPointer, you should bind the corresponding buffer right before (no matter when that was actually created and filled), since the glVertexAttribPointer function sets the currently bound GL_ARRAY_BUFFER as source buffer for this attribute (and stores this setting, so afterwards you can freely bind another VBO).

So in modern OpenGL using VAOs (which is recommended), it's usually similar to this workflow:

//initialization
glGenVertexArrays
glBindVertexArray

glGenBuffers
glBindBuffer
glBufferData

glVertexAttribPointer
glEnableVertexAttribArray

glBindVertexArray(0)

glDeleteBuffers //you can already delete it after the VAO is unbound, since the
                //VAO still references it, keeping it alive (see comments below).

...

//rendering
glBindVertexArray
glDrawWhatever

When not using VAOs it would be something like that:

//initialization
glGenBuffers
glBindBuffer
glBufferData

...

//rendering
glBindBuffer
glVertexAttribPointer
glEnableVertexAttribArray
glDrawWhatever
Christian Rau
  • 45,360
  • 10
  • 108
  • 185
  • Take care with deleting buffers `If a buffer object that is currently bound is deleted, the binding reverts to 0 (the absence of any buffer object, which reverts to client memory usage).` – t.niese Jun 17 '13 at 14:52
  • So you delete the buffer whilst the VAO is still bound? Do you need to call `glBindBuffer(GL_ARRAY_BUFFER, 0);` before you delete it? – Mark Ingram Jun 17 '13 at 14:52
  • @t.niese when can I unbind the VBO / delete the VBO? – Mark Ingram Jun 17 '13 at 14:53
  • @t.niese Still no problem, because after the `glVertexAttribPointer` you can freely unbind it. – Christian Rau Jun 17 '13 at 14:53
  • @MarkIngram The `glVertexAttribPointer` call stores the VBO used for that attribute, so after this call, you can at least unbind it. With deleting I'm not sure if you can do that without a VAO (but you should). But if a VAO is used, you can freely delete the VBO after `glVertexAttribPointer` (of course only if *you* don't need it anymore, e.g. for updating its data). It won't get deleted by the GL until it's not referenced anymore, it's just deleted from *your* point of view. – Christian Rau Jun 17 '13 at 14:56
  • @ChristianRau that would be great if that is the case, do you have a source for that? `VAO` just stores states but no data, and i could not - does not mean that it does not exist :D - find a part in the specs that say that the Buffer an be deleted and is kept in memory while the `VAO` is _using_ it. – t.niese Jun 17 '13 at 14:58
  • @t.niese The VAO doesn't store data, but it *references* data and that keeps it alive. All those `glDelete...` functions are in the end non-binding requests. They only delete things for *you*. From the top of my head the only source I can provide right now is that I have succesfully done it like so but I try to dig it up in the spec. – Christian Rau Jun 17 '13 at 15:01
  • @t.niese Of course the previous comment only applies for the statement about freely *deleting* it. The fact the you can *unbind* it after `glVertexAttribPointer` is a given fact (and that I'm 110% percent sure of), otherwise you couldn't source different attributes from multiple buffers for a single draw call, could you? – Christian Rau Jun 17 '13 at 15:02
  • 1
    The point when the `glBindBuffer(GL_ARRAY_BUFFER, ...)` actually takes effect and when it's safe to change is a common point of confusion (and goes back to the fact that VBOs have been violently clubbed into the existing client array API driven by back-ward compatibility). A `glVertexAttribBuffer` function would have made more sense, though they recently cleared that up a bit (but those new functions mentioned by *t.niese*'s answer introduce other confusions). – Christian Rau Jun 17 '13 at 15:05
  • @ChristianRau unbind is fully valid. I mean the `glDeleteBuffers` – t.niese Jun 17 '13 at 15:06
  • I just tried this, and calling `glBindBuffer(GL_ARRAY_BUFFER, 0);` before `glBindVertexArray(0);` resulted in nothing drawing to the screen. I can only unbind the VBO *after* the VAO has been unbound. – Mark Ingram Jun 17 '13 at 15:09
  • 1
    @MarkIngram You can unbind it freely *after* `glVertexAttribPointer` (I have to search for the *deleting* case though, I have to admit, but *unbinding has to work*, anything else is a driver bug or SO question). It's different for the `GL_ELEMENT_ARRAY_BUFFER`, of course, since that binding is directly stored in the VAO so should be kept bound if you want to do indexed rendering. – Christian Rau Jun 17 '13 at 15:13
  • @t.niese I have removed the part about deleting for now, but I remember having searched for this fact and found it stated somewhere, otherwise I hadn't explicitly (and successfully) used it in my own code. – Christian Rau Jun 17 '13 at 15:16
  • @ChristianRau you can re-include it. I found the corresponding section (5.1.2 Automatic Unbinding of Deleted Objects) `Attachments to unbound container objects, such as deletion of a buffer attached to a vertex array object which is not bound to the context, are not affected and continue to act as references on the deleted object, as described in the following section.` Could you please add this to the comment, sometimes i hate the specs ;) – t.niese Jun 17 '13 at 15:19
  • 1
    @t.niese Thanks, but this sounds like it should at least be done *after* the `glBindVertexArray(0)`. Still I won't add this into the code comment (I already hated it to be two lines long ;)). – Christian Rau Jun 17 '13 at 15:31
  • @ChristianRau i just ment the section number ;) ... and yes you could be right with the `glBindVertexArray(0)`. I'll definitiv do some further reading. I would like to remove my comments to keep this answer clean without this discussion if you don't mind, otherwise i'll keep it here. – t.niese Jun 17 '13 at 15:39
  • @t.niese Well, it's just comments, I don't feel an urge to clean them. But if you want it's your decision, just try to keep the standard quote since I'm referencing it (and am too lazy to add it into my answer ;)). – Christian Rau Jun 17 '13 at 15:44
  • @t.niese / Christian. Found out why I needed to unbind the VBO after the VAO. The VBO was being deleted after all the unbinding, which meant the memory was disappearing. On Mac / iOS this is OK, somehow the memory stays around, regardless, but on Windows it crashes. I've changed my code to preserve the VBO for lifetime of VAO, and now I can unbind the VBO before the VAO. – Mark Ingram Jul 02 '13 at 07:47
  • 2
    @MarkIngram As concluded by the comments, you can delete the VBO, but you need to unbind the *VAO* beforehand. – Christian Rau Jul 02 '13 at 07:57
  • @ChristianRau when I tried that (deleting VBO after unbinding VAO) on Windows (using glew+glfw), I got `GL_OUT_OF_MEMORY` error in `glDrawArrays`. I don't know if that is a separate problem or not. – Mark Ingram Jul 02 '13 at 08:26
  • Can you recommend equivalent for `glBindVertexArray` in OpenGL ES 2.0? https://www.khronos.org/opengles/sdk/docs/man/ – kelin Dec 18 '15 at 07:51
4

glVertexAttribPointer is something that does not really belong to the Buffer nor to the Program it is - let's say - the glue between them. (The functionality of this is splitten in Opengl 4.3 in different functions VertexAttrib*Format, VertexAttribBinding and BindVertexBuffer aviable through the ARB_vertex_attrib_binding )

But if you want to say that it is part of something i would say it is part of the VAO that stores the state of which Buffer objects are bound, which attribs are enabled and how the Buffer data has to be passed to the Program.

So it belongs to part where you setup your VAOs.

EDIT Simple setup that illustrates the order:

  1. creating/setup of Buffers and creating programs
  2. create VAO define which attribs are enabled, which buffers should be bound when the VAO is used and how that data is passed to the program (glVertexAttribPointer)
t.niese
  • 39,256
  • 9
  • 74
  • 101
2

The association of buffer, generic vertex attribute and shader attribute variable are quite subtle. glVertexAttribPointer establishes this association. See OpenGL-Terminology for a detailed explanation.

Also, the link OpenGL-VBO,shader,VAO shows a working example with the necessary sequence of API calls.

ap-osd
  • 2,624
  • 16
  • 16
1

glVertexAttribPointer has to be called (in most cases) when the appropriate (i.e. the one you want to use) VBO is bound. Then last parameter to it is offset in said buffer.

The last parameter is defined particularly nice in the reference manual:

Specifies a offset of the first component of the first generic vertex attribute in the array in the data store of the buffer currently bound to the GL_ARRAY_BUFFER target. The initial value is 0.

Appropriate Vertex Pointer Bindings with VBO sources are stored inside VAO, and you should use that if possible.

Short example (excuse my pseudocode):

// Setup
CreateVAO(); BindVAO();
CreateVBO(); BindVBO();
VertexAttribPointer(/*id*/ 0, 3, GL_FLOAT, /*starting at offset*/ 0);

// We have specified Vertex attribute bound to location 0,
// with size of 3 floats, starting at offset 0 of VBO we've just created.        

//Draw
BindVAO();
Draw();
Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
  • *"glVertexAttribPointer has to be called (in most cases) when the appropriate (i.e. the one you want to use) VBO is bound."* - Meh, rather the other way around. Binding of the VBO should be guided by when `glVertexAttribPointer` is called (and that is guided by either VAO setup time, or rendering time when not utilizing VAOs). – Christian Rau Jun 17 '13 at 14:35
  • 1
    Well, a `glVertexAttribBuffer` function would be much more intuitive anyway, but that's OpenGL. – Christian Rau Jun 17 '13 at 14:59
  • @ChristianRau IMHO that's pretty much the same, but I am not going to argue about semantics; also the community seems to agree with your answer more. – Bartek Banachewicz Jun 17 '13 at 15:00
  • @ChristianRau We can only hope for 4.4/5.0 doing something better in that regard. – Bartek Banachewicz Jun 17 '13 at 15:01