OpenGL will only update the last vertex array object - c++

I am writing some code that generates some VAO and then when the physics have been updated a call is made to update the vertices inside the VAOs and then a call is made to redraw these objects.
The problem with my code is that only the last VAO is being updated by UpdateScene. The following two functions create the buffers.
void BuildBuffers(std::vector<demolish::Object>& objects)
{
VAO = new UINT[objects.size()];
glGenVertexArrays(objects.size(),VAO);
int counter = 0;
for(auto& o:objects)
{
if(o.getIsSphere())
{
BuildSphereBuffer(o.getRad(),o.getLocation(),counter);
counter++;
}
else
{
}
}
}
void BuildSphereBuffer(float radius,std::array<iREAL,3> position,int counter)
{
GeometryGenerator::MeshData meshObj;
geoGenObjects.push_back(meshObj);
geoGen.CreateSphere(radius,30,30,meshObj,position);
VAOIndexCounts.push_back(meshObj.Indices.size());
glGenBuffers(2,BUFFERS);
glBindVertexArray(VAO[counter]);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER,BUFFERS[0]);
glBufferData(GL_ARRAY_BUFFER,
meshObj.Vertices.size()*sizeof(GLfloat)*11,
&meshObj.Vertices.front(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, BUFFERS[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
meshObj.Indices.size() * sizeof(UINT),
&meshObj.Indices.front(), GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT,sizeof(GLfloat)*11, 0);
glNormalPointer(GL_FLOAT,sizeof(GLfloat)*11,(GLvoid*)(3*sizeof(GLfloat)));
}
Then the following function updates the buffers when it is called.
void UpdateScene(float dt, std::vector<demolish::Object>& objects)
{
float x = radius*sinf(phi)*cosf(theta);
float z = radius*sinf(phi)*sinf(theta);
float y = radius*cosf(phi);
AV4FLOAT position(x,y,z,1.0);
AV4FLOAT target(0.0,0.0,0.0,0.0);
AV4FLOAT up(0.0,1.0,0.0,0.0);
viewModelMatrix = formViewModelMatrix(position,target,up);
for(int i=0;i<objects.size();i++)
{
geoGen.CreateSphere(objects[i].getRad(),
30,
30,
geoGenObjects[i],
objects[i].getLocation());
VAOIndexCounts[i] = geoGenObjects[i].Indices.size();
glBindVertexArray(VAO[i]);
glBufferSubData(GL_ARRAY_BUFFER,
0,
geoGenObjects[i].Vertices.size()*sizeof(GLfloat)*11,
&geoGenObjects[i].Vertices.front());
}
RedrawTheWindow();
}
The problem with this code is that it is not updating all of the buffers, only the "last" one. For instance if objects has size 3 then even if the locations of all three objects change only the last buffer is being updated with the new vertices.
I have narrowed it down to OpenGL but I am not sure what I am doing wrong.

Binding the Vertex Array Object doesn't bind any array buffer object.
If you want to change the content of an array buffer, then you have to bind the array buffer:
GLuint VBO = .....; // VBO which corresponds to VAO[i]
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(
GL_ARRAY_BUFFER, 0,
geoGenObjects[i].Vertices.size()*sizeof(GLfloat)*11,
&geoGenObjects[i].Vertices.front());
Note, a vertex array object may refer to a different array buffer object, for each attribute. So which one should be bound?
Since OpenGL 4.5 you can do this by the direct state access version too.
See glNamedBufferSubData:
glNamedBufferSubData (
VBO, 0,
geoGenObjects[i].Vertices.size()*sizeof(GLfloat)*11,
&geoGenObjects[i].Vertices.front());
If the vertex array object is bound, then a named array buffer object which is bound to a binding point can be queried by glGetVertexAttribIuiv using the parameter GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
e.g.:
glBindVertexArray(VAO[i]);
GLuint VBO;
glGetVertexAttribIuiv(0, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &VBO);

Related

OpenGL VAO is pointing to address 0 for some reason

I am having some trouble with my VAO not binding properly (at least that's what I think is happening).
So, what I am doing is I have a class that is creating a vbo and vao from some raw data, in this case a pointer to an array of floats.
RawModel* Loader::loadToVao(float* positions, int sizeOfPositions) {
unsigned int vaoID = this->createVao();
this->storeDataInAttributeList(vaoID, positions, sizeOfPositions);
this->unbindVao();
return new RawModel(vaoID, sizeOfPositions / 3);
}
unsigned int Loader::createVao() {
unsigned int vaoID;
glGenVertexArrays(1, &vaoID);
glBindVertexArray(vaoID);
unsigned int copyOfVaoID = vaoID;
vaos.push_back(copyOfVaoID);
return vaoID;
}
void Loader::storeDataInAttributeList(unsigned int attributeNumber, float* data, int dataSize) {
unsigned int vboID;
glGenBuffers(1, &vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, dataSize * sizeof(float), data, GL_STATIC_DRAW);
glVertexAttribPointer(attributeNumber, 3, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
unsigned int copyOfVboID = vboID;
vbos.push_back(copyOfVboID);
}
void Loader::unbindVao() {
glBindVertexArray(0);
}
The RawModel is just a class that should take in the array of floats and create a vbo and a vao. The vectors vbos and vaos that I am using are just there to keep track of all the ids so that I can delete them once I am done using all the data.
I am 90% confident that this should all work properly. However, when I go to try and just run some code that would draw it, OpenGL is exiting because it is trying to read from address 0x0000000 and it doesn't like that. I pass the raw model that I created from the code before this into a function in my renderer that looks like this:
void Renderer::render(RawModel* model) {
glBindVertexArray(model->getVaoID());
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, model->getVertexCount());
glDisableVertexAttribArray(0);
glBindVertexArray(0);
}
I have checked to make sure that the VaoID is the same when I am creating the vao, and when I am trying to retrieve the vao. It is in fact the same.
I have no idea how to read what address is currently stored in whatever OpenGL has currently bound as the vertex attrib array, so I cannot test whether or not it is pointing to the vertex data. I'm pretty sure that it's pointing to address 0 for some reason though.
Edit:
It turns out it was not the hard-coded 0 that was a problem. It removed the errors that Visual Studio and OpenGL were giving me, but the actual error was somewhere else. I realized that I was passing in the vaoID as the attributeNumber in some of the code above, when I should have been passing in a hard-coded 0. I edited my code here:
RawModel* Loader::loadToVao(float* positions, int sizeOfPositions) {
unsigned int vaoID = this->createVao();
this->storeDataInAttributeList(0, positions, sizeOfPositions);
this->unbindVao();
return new RawModel(vaoID, sizeOfPositions / 3);
}
I changed the line this->storeDataInAttributeList(vaoID, positions, sizeOfPositions); to what you see above, with a hard-coded 0. So, it turns out I wasn't even binding the array to the correct location in the vbo. But, after changing that it worked fine.
You should be using your vertex attribute index with glVertexAttribPointer, glEnableVertexAttribArray and glDisableVertexAttribArray but what you've got is:
VAO id used with glVertexAttribPointer
hard coded 0 used with glEnableVertexAttribArray and glDisableVertexAttribArray (this isn't necessarily a bug though if you're sure about the value)
If you are not sure about the index value (e.g. if you don't specify the layout in your shader) then you can get it with a glGetAttribLocation call:
// The code assumes `program` is created with glCreateProgram
// and `position` is the attribute name in your vertex shader
const auto index = glGetAttribLocation(program, "position");
Then you can use the index with the calls mentioned above.

If my VBO class references vertex arrays, is data still stored on the GPU?

Quite simply, my question is this. My code is below for a C++ header file that keeps track of and handles a vertex buffer object in OpenGL. In order to comply with core standards, it must use vertex arrays (VAO). Since glGenVertexArrays() and other related methods are called, is this rendering method still have information stored on the GPU or in RAM?
class VertexBuffer
{
private:
int vertCount;
GLuint vertArray;
GLuint vertBuffer;
public:
VertexBuffer();
void renderInterleaved();
void createInterleaved(GLfloat*, int);
void destroy();
GLuint* getVboId();
};
VertexBuffer::VertexBuffer()
{
glGenVertexArrays(1, &vertArray);
glGenBuffers(1, &vertBuffer);
}
void VertexBuffer::renderInterleaved()
{
glBindVertexArray(vertArray);
glBindBuffer(GL_ARRAY_BUFFER, vertBuffer);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
int stride = 7 * sizeof(GLfloat);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*) 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(GLfloat)));
glDrawArrays(GL_TRIANGLES, 0, vertCount);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void VertexBuffer::createInterleaved(GLfloat* data, int vertices)
{
vertCount = vertices;
glBindBuffer(GL_ARRAY_BUFFER, vertBuffer);
glBufferData(GL_ARRAY_BUFFER, vertices * 21 * sizeof(GLfloat), data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void VertexBuffer::destroy()
{
glDeleteBuffers(1, &vertBuffer);
glDeleteVertexArrays(1, &vertArray);
}
GLuint* VertexBuffer::getVboId()
{
return &vertBuffer;
}
The term "vertex buffer object" is, and has always been, a misnomer, created by the unfortunate naming of the extension that introduced buffer objects.
There is no "vertex buffer object." There is only a buffer object, which represents a linear array of OpenGL-managed memory. Buffer objects can be used to store vertex data for rendering operations, but there is nothing intrinsic about any particular buffer object that lets it do that. It is only a question of how you use it.
If your object encapsulates the parameters you would use for glVertexAttribPointer, then it is not encapsulating just a buffer object. A buffer object does not know how to render itself or what data it contains; it's just a buffer. The closest OpenGL concept it represents is a vertex array object.
But your code isn't really using VAOs either. Every time you call renderInterleaved, you're setting state that's already stored as part of the VAO. All of those glVertexAttribPointer and glEnableVertexAttribArray calls are recorded into the VAO. That's something you ought to set up once, then just bind the VAO later and render with it. So yes, it is a less-efficient VAO.
But your class encapsulates more than a VAO. It knows how to render itself. So the best name for your class would be "mesh" or something of that effect.

glVertexAttribPointer set to pointer

so I have this class:
class BRENDERDLL_API Vertex
{
private:
glm::vec3 pos;
public:
Vertex(glm::vec3 pos);
~Vertex();
void setPos(glm::vec3 pos);
glm::vec3 getPos();
};
I would want to change:
glm::vec3 pos;
to:
glm::vec3* pos;
Then I need to change:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
To point somehow where I storage data. There is obviously no problem with first one case, but what to do with second version?
Can I even do that or should I copy data to some array before?
Changing this to glm::vec3* will not benefit you at all, especially in modern GL. What you need to do is create an array of instances of Vertex.
You have to store this stuff in a Vertex Buffer and that means it needs to be laid out "flatly" in memory (e.g. no pointer dereferencing). If you have a contiguous array of Vertex, then you can take the address of the first instance and use glBufferData (...) to upload it to GL-managed memory.
The following code illustrates this:
std::vector <Vertex> verts;
const size_t size = verts.size () * sizeof (Vertex);
// Generate, allocate and upload your array to an OpenGL Buffer Object
GLuint vbo;
glGenBuffers (1, &vbo);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, size, &verts [0], GL_STATIC_DRAW);
// This points to address **0** relative to the buffer currently bound to
// GL_ARRAY_BUFFER.
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

GL Error: Out of Memory when trying to render with VBO

I've been trying to use Vertex Buffer Objects to save vertex data on the GPU and reduce the overhead, but I cannot get it to work. The code is below.
From what I understand you generate the buffer with glGenBuffers, then you bind the buffer with glBindBuffer so it's ready to be used, then you write data to it with glBufferData and its done and can be unbinded and ready for use later with simply binding it again.
However the last part is what I'm having trouble with, when I bind it after I have created and loaded data to it and try to draw using it, it gives me lots of GL Error: Out of Memory.
I doubt that I am running out of memory for my simple mesh, so I must be doing something very wrong.
Thanks.
EDIT 1: I call glGetError after every frame, but since this is the only OpenGL I do in the entire program it shouldn't be a problem
//when loading the mesh we create the VBO
void createBuffer()
{
GLuint buf;
glGenBuffers(1, &buf);
glBindBuffer(GL_ARRAY_BUFFER, buf);
glBufferData(GL_ARRAY_BUFFER, vertNormalBuffer->size() * sizeof(GLfloat), (GLvoid*) bufferData, GL_STATIC_DRAW);
//EDIT 1: forgot to show how I handle the buffer
model->vertexNormalBuffer = &buf;
//Unbinds it
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Fighter::doRedraw(GLuint shaderProgram)
{
glm::mat4 transformationMatrix = getTransform();
GLuint loc = glGetUniformLocation(shaderProgram,"modelviewMatrix");
glUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat*) &transformationMatrix);
glBindBuffer(GL_ARRAY_BUFFER, *model->vertexNormalBuffer);
//If I uncomment this line below all works wonderfully, but isnt the purpose of VBO of not uploading the same data again and again?
//glBufferData(GL_ARRAY_BUFFER, model->vertAndNormalArraySize * sizeof(GLfloat), model->vertAndNormalArray, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(2);
renderChild(model, model);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Fighter::renderChild(ModelObject* model, ModelObject* parent)
{
//Recursively render the mesh children
for(int i = 0; i < model->nChildren; i++)
{
renderChild( dynamic_cast<ModelObject*>(model->children[i]), parent);
}
//Vertex and normal data are interlieved
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat),(void*)(model- >vertexDataPosition*sizeof(GLfloat)));
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (void*)((model->vertexDataPosition + 4)*sizeof(GLfloat)));
//Draws using two sets of indices
glDrawElements(GL_QUADS, model->nQuads * 4, GL_UNSIGNED_INT,(void*) model->quadsIndices);
glDrawElements(GL_TRIANGLES, model->nTriangles * 3, GL_UNSIGNED_INT, (void*) model->trisIndices);
}
This is your problem:
model->vertexNormalBuffer = &buf;
/* ... */
glBindBuffer(GL_ARRAY_BUFFER, *model->vertexNormalBuffer);
You're storing the address of your buf variable, rather than its contents, and then it falls out of scope when createBuffer returns, and is most likely overwritten with other data, so when you're later rendering, you're using an uninitialized buffer. Just store the contents of buf in your vertexNormalBuffer field instead.
I'll admit I don't know why OpenGL thinks it proper to say that it's "out of memory" just because of that, but perhaps you're just invoking undefined behavior. It does explain, however, why it starts working when you re-fill the buffer with data after you rebind it, because you then implicitly initialize the buffer that you just bound.

Vertex Array Objects - Confusion regarding exactly what state information is saved about the currently bound vertex buffer

I'm working through the excellent tutorials at arcsynthesis while building a graphics engine and have discovered I don't understand VAOs as much as I thought I had.
From the tutorial Chapter 5. Objects In Depth
Buffer Binding and Attribute Association
You may notice that glBindBuffer(GL_ARRAY_BUFFER) is not on that list, even though it is part of the attribute setup for rendering. The binding to GL_ARRAY_BUFFER is not part of a VAO because the association between a buffer object and a vertex attribute does not happen when you call glBindBuffer(GL_ARRAY_BUFFER). This association happens when you call glVertexAttribPointer.
When you call glVertexAttribPointer, OpenGL takes whatever buffer is at the moment of this call bound to GL_ARRAY_BUFFER and associates it with the given vertex attribute. Think of the GL_ARRAY_BUFFER binding as a global pointer that glVertexAttribPointer reads. So you are free to bind whatever you want or nothing at all to GL_ARRAY_BUFFER after making a glVertexAttribPointer call; it will affect nothing in the final rendering. So VAOs do store which buffer objects are associated with which attributes; but they do not store the GL_ARRAY_BUFFER binding itself.
I initially missed the last line "...but they do not store the GL_ARRAY_BUFFER binding itself". Before I noticed this line I thought that the currently bound buffer was saved once glVertexAttribPointer was called. Missing this knowledge, I built a mesh class and was able to get a scene with a number of meshes rendering properly.
A portion of that code is listed below. Note that I do not call glBindBuffer in the draw function.
// MESH RENDERING
/* ... */
/* SETUP FUNCTION */
/* ... */
// Setup vertex array object
glGenVertexArrays(1, &_vertex_array_object_id);
glBindVertexArray(_vertex_array_object_id);
// Setup vertex buffers
glGenBuffers(1, &_vertex_buffer_object_id);
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id);
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(vertex), &_vertices[0], GL_STATIC_DRAW);
// Setup vertex attributes
glEnableVertexAttribArray(e_aid_position);
glEnableVertexAttribArray(e_aid_normal);
glEnableVertexAttribArray(e_aid_color);
glEnableVertexAttribArray(e_aid_tex);
glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, pos));
glVertexAttribPointer(e_aid_normal, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, norm));
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, col));
glVertexAttribPointer(e_aid_tex, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, tex));
/* ... */
/* DRAW FUNCTION */
/* ... */
glBindVertexArray(_vertex_array_object_id);
glDrawArrays(GL_TRIANGLES, 0, _vertices.size());
Now that I'm about to start lighting I wanted to get some debug drawing up so I could verify all my normals are correct. Currently I just store all lines to be rendered for a frame in a vector. Since this data will likely change every frame, I'm using GL_DYNAMIC_DRAW and specify the data right before I render it.
Initially when I did this I would get garbage lines that would just point off into infinity. The offending code is below:
// DEBUG DRAW LINE RENDERING
/* ... */
/* SETUP FUNCTION */
/* ... */
// Setup vertex array object
glGenVertexArrays(1, &_vertex_array_object_id);
glBindVertexArray(_vertex_array_object_id);
// Setup vertex buffers
glGenBuffers(1, &_vertex_buffer_object_id);
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id);
// Note: no buffer data supplied here!!!
// Setup vertex attributes
glEnableVertexAttribArray(e_aid_position);
glEnableVertexAttribArray(e_aid_color);
glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, pos));
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, col));
/* ... */
/* DRAW FUNCTION */
/* ... */
glBindVertexArray(_vertex_array_object_id);
// Specifying buffer data here instead!!!
glBufferData(GL_ARRAY_BUFFER, _line_vertices.size() * sizeof(line_vertex), &_line_vertices[0], GL_DYNAMIC_DRAW);
glDrawArrays(GL_LINES, 0, _line_vertices.size());
After a bit of hunting, as well as finding the detail I missed above, I found that if I call glBindBuffer before glBufferData in the draw function, everything works out fine.
I'm confused as to why my mesh rendering worked in the first place given this. Do I only need to call glBindBuffer again if I change the data in the buffer? Or is behavior undefined if you don't bind the buffer and I was just unlucky and had it work?
Note that I am targeting OpenGL version 3.0.
Do I only need to call glBindBuffer again if I change the data in the
buffer?
Yes, The VAO object remembers which buffers were bound each time you called glVertexAttribPointer whilst that VAO was bound, so you don't usually need to call glBindBuffer again. If you want to change the data in the buffer however, OpenGL needs to know which buffer you are changing, so you need to call glBindBuffer before calling glBufferData. It is irrelevant which VAO object is bound at this point.
A Vertex Array object holds the data set by glEnableVertexAttribArray, glDisableVertexAttribArray, glVertexAttribPointer, glVertexAttribIPointer, glVertexAttribDivisor and gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER)
To put it another way you could define a VAO as
struct VertexAttrib {
GLint size; // set by gVertexAttrib(I)Pointer
GLenum type; // set by gVertexAttrib(I)Pointer
GLboolean normalize; // set by gVertexAttrib(I)Pointer
GLsizei stride; // set by gVertexAttrib(I)Pointer
GLint buffer; // set by gVertexAttrib(I)Pointer (indirectly)
void* pointer; // set by gVertexAttrib(I)Pointer
GLint divisor; // set by gVertexAttribDivisor
GLboolean enabled; // set by gEnable/DisableVertexAttribArray
};
struct VertexArrayObject {
std::vector<VertexAttrib> attribs;
GLuint element_array_buffer; // set by glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ..)
};
How many attributes there are can be queried with
GLint num_attribs;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &num_attribs)
You can think of GL's global state has having a pointer to a VertexArrayObject that is set with glBindVertexArray
struct GLGlobalState {
VertexArrayObject default_vao;
VertexArrayObject* current_vao = &default_vao;
...
GLint current_array_buffer; // set by glBindBuffer(GL_ARRAY_BUFFER, ...)
}
GLGloalState gl_global_state;
void glBindVertexArray(GLint vao) {
gl_global_state.current_vao = vao == 0 ? &default_vao : getVAOById(vao);
}
And you can think of the other functions listed above working like this
void glEnableVertexAttribArray(GLuint index) {
gl_global_state.current_vao->attribs[index].enabled = GL_TRUE;
}
void glEnableVertexAttribArray(GLuint index) {
gl_global_state.current_vao->attribs[index].enabled = GL_FALSE;
}
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,
GLsizei stride, const void* pointer) {
VertexAttrib* attrib = &gl_global_state.current_vao->attribs[index];
attrib->size = size;
attrib->type = type;
attrib->normalized = normalized;
attrib->stride = stride;
attrib->pointer = pointer;
attrib->buffer = glGlobalState.current_array_buffer;
}
void glVertexAttribDivisor(GLuint index, GLuint divisor) {
gl_global_state.current_vao->attribs[index].divisor = divisor;
}
It might be easier to see it visually
from this diagram though the diagram above shows offset instead of pointer since it's from WebGL which doesn't allow client side arrays, only vertex buffers, therefore the pointer field is always interpreted as an offset.
In OpenGL pointer is a pointer to user memory if the buffer field for that attribute is 0 (set indirectly, see above). It's an offset into a buffer if the buffer for an attribute is non-zero.
One thing NOT stored in an VAO are the attribute's constant values when it's disabled. If an attribute is disabled (they default to disabled, or you call gl.disableVertexAttribArray) then that attribute will get a constant value. The constant value can be set with glVertexAttrib???. These values are global. They are not part of VAO state.