Understanding the concept of vertex arrays

From what I understand, the array in vertex array (object) refers to the array of different attributes (inputs/uniform) that are entries for vertes data into the vertex shader. So if my vertex shader looked like this:

#version 430 core
layout (location=0) in vec4 vertex_position;
layout (location=2) in vec3 vertex_color;
out vec3 pass_through_color;

void main()
{
     gl_Position = vertex_position;
     pass_through_color = vertex_color;
}

, then the “array” of the VAO is defined by the list of inputs to the shader, namely vertex_position and vertex_color, and their locations in this array can be specified by the location specifier of the layout descriptor (locations 0 and 2 respectively).

And I imagine for a particular implementation of the GL, MAX_VERTEX_ATTRIBS defines the maximum number of distinct input parameters that a vertex shader can have.

Is this understanding correct? Thanks for your help

From what I understand, the array in vertex array (object) […]

… is merely used to state that a VAO mainly captures vertex array state. You can have multiple vertex arrays - don’t get confused by the term array. You define how data is layed out in the buffer’s data store and how data is pulled from this data store.

[…]refers to the array of different attributes (inputs/uniform)

The value of a uniform is never sourced from an array buffer and is thus not associtated to vertex attributes whatsoever. You can, however, source uniform values from uniform buffer objects. As I said, there is not “the array”, there may be multiple arrays, each of which is identifed with a separate index in [0 … MAX_VERTEX_ATTRIBS - 1].

then the “array” of the VAO is defined by the list of inputs to the shader, namely vertex_position and vertex_color

No, each input is sourced from a different array with a different index and different memory layout, where usually at least the offset into the buffer’s data store will differ. An array in this context is not necessarily the whole data store, but most of the time portions of it. For instance, if you have a packed buffer with positions and normals, the position (e.g. n components, float) array will start at offset 0 and the normal array will start at numVertices numComponents sizeof(float). The inputs defined in the shader are sourced from the vertex array whose index matches the explicit location, if existent and enabled. I’m not quite sure at which point you tread undefined ground with input locations but if you have an attrib without a corresponding, enabled array I assume values for the attribute are undefined.

Another, actually better layout, is to iterleave attributes, i.e. instead of a packed layout (e.g. n positions, n normals -> PPPP … PPPP NNNN … NNNN) you can store them like this: PPPP NNNN PPPP NNNN …
Now you can see why the term “array” as used in C does not apply here, since data is not stored consecutively - the data store is a consecutive storage, a vertex array need not point to completely consecutive elements. This is where the stride parameter, i.e. the distance between one particular attribute in an array and the next is located in memory. The stride in our case is trivially 4 * sizeof(float) for both arrays and the offset for the normal array is the same as the stride since you have to start after the first 4 position components.

and their locations in this array can be specified by the location specifier of the layout descriptor (locations 0 and 2 respectively).

If you’ve got GL_ARB_explicit_attrib_location available or, I think GL3.1+, then yes. Note, if you assign explicit locations, you have to make sure that indices in the application actually correspond to the locations in the shader. This also works vice versa: if you impose certain attrib indices on certain shader inputs, you need to use the correct explicit location in the shader. There’s also glBindAttribLocation which could be used to explicitly assign locations before above mentiond extension was available. I’m not sure how both features interact as I’ve never tried to use them together - and frankly, if you can do it in the shader, you don’t need the API anymore.

MAX_VERTEX_ATTRIBS defines the maximum number of distinct input parameters that a vertex shader can have

Yep. It wouldn’t make sense to allow the specification of more than MAX_VERTEX_ATTRIBS attributes if you can’t source them in a vertex shader and vice versa.