Search code examples
c++openglglsl

How does one declare and use vertex attributes that are an array of primitive elements in OpenGL


In a shader I want to pass an array of primitives into it as a vertex attribute.

In the shader I declare

in float FloatItems[8]
in int IntItems[8]

IN the C++ code uses:

void glGetActiveAttrib(     GLuint program,
    GLuint index,
    GLsizei bufSize,
    GLsizei *length,
    GLint *size,
    GLenum *type,
    GLchar *name);

returns 
    name == "FloatItems[0]"
    size == 1
    type == 0x1406 (GL_FLOAT) - GL_INT for the int one.

when I try glVertexAttribPointer with the location to bind to it it fails with 0x0501 "invalid value"

Apparently gls is creating a single attribute with a name of "FloatItem[0]" instead of an array FloatItem with a size of 8 elements.

Is there a "proper" way to do this ??


Solution

  • This:

    in float FloatItems[8]
    

    Means the shader takes eight separate attributes, which the shader can access as an array of values. That's 8 attributes with 8 distinct attribute locations. The location of these attributes will be allocated contiguously, starting from the location for FloatItems[0].

    Obviously, consuming 8 attribute locations for 8 floats is a huge waste of locations and possibly other vertex input resources. As such, the best way to handle this is to work within the limitations of attributes themselves.

    Attribute locations are at most 4 elements long (this is why you got GL_INVALID_VALUE: the size can only be 1-4). This represents the number of components in a vector type: 2-4, with 1 being the scalar version.

    So if you want an "array of 8 floats", what you want is an array of two vec4s:

    layout(location = X) in vec4 FloatItems[2];
    

    To access an array element, you use multi-indexing. To get index Y from the array, you use FloatItems[Y / 4][Y % 4]. 4 is used because you're using a vec4.

    Of course, there are two attribute locations involved here. The first is at location X (the first 4 elements) and the next is at location X + 1. So you will need two glVertexAttribFormat or glVertexAttribPointer calls to set up the VAO for it.