0

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 ??

genpfault
  • 51,148
  • 11
  • 85
  • 139
peterk
  • 5,136
  • 6
  • 33
  • 47
  • Depending on what you want to do, you can use uniforms to pass arrays (just google it) but it might be better (faster) to pass them as vertex attribute. In that case you'd usually have either single values or vec2/3/4s depending on what your data 'logically' looks like (you usually dont pass 8 arbitrary floats to your shader but something like pos (vec2/3), tex-coords (vec2), etc in which case naming and separating them makes working with it much easier). I don't think its possible to pass an array as attribute but I might be mistaken here. – Kami Kaze Feb 22 '21 at 22:09
  • @KamiKaze yes am aware of people using multi-element primitive types. But wondering if there was a way to declare and use an array of primitives as that in a shader as vertex attributes. This is specifically for per vertex data, and of a fixed size for all vertices in the buffer. – peterk Feb 22 '21 at 22:57
  • It's probably because you're making a reference to the first element of that array. – John Feb 22 '21 at 23:17
  • Basically what @Nicol Bolas said. Also answered here I think: https://stackoverflow.com/questions/9043845/glsl-per-vertex-fixed-size-array Besides that you still have uniforms as i said in my first comment, or the 'usual' way with primitives (eg 2 vec4s) or using a texture to pass data. – Kami Kaze Feb 23 '21 at 00:22

1 Answers1

1

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Alas this is what seems to be the case. A deficiency in GLSL - I can understand rounding locations to 4 floats for efficiencies but this could be easily overcome The language supports mat4 ( 16 elements ) and mat3 (9 elements ) - the lack of an array declaration - even with caveats for alignment and padding - confuses a lot of people and of course the crowd sourced madness of un-curated howtos and blogs makes finding answers difficult - I had to use two vec4 and two ivec4 to get what was needed as you described. – peterk Feb 25 '21 at 00:54
  • @peterk: "*A deficiency in GLSL*" What's the deficiency exactly? As I showed, you can have arrays of inputs. There is no "lack of an array declaration;" there is simply a lack of automagically packing them into as few locations as possible. Each array element is its own location, *period*. That's not a "deficiency"; that's just its *behavior*. – Nicol Bolas Feb 25 '21 at 00:59
  • @peterk: "*the crowd sourced madness of un-curated howtos and blogs makes finding answers difficult*" Yeah, wouldn't it make more sense if there was an entire page dedicated to explaining how vertex shaders work, which [includes a section on how input variables can generate multiple locations.](https://www.khronos.org/opengl/wiki/Vertex_Shader#Multiple_attributes) But that's just crowd sourcing; it's not on Khronos's OpenGL website or anything. – Nicol Bolas Feb 25 '21 at 01:02
  • I did read the Khronos docs - a language is a tool to be understandable by programmers for defining what they want code to do. Many many people do not understand the nuances of GLSL array declarations and it would be perfectly reasonable to allow declaring an array of sub 8 byte (vec2) entities and have the compiler nicely generate the code to reserve the space for it rounded to 16 bytes and addressable in the source code using an index. and have the offsets all calculated by the compiler. Even simple assemblers do this well. – peterk Feb 25 '21 at 06:16
  • @peterk: "*I did read the Khronos docs*" So... what's the "makes finding answers difficult" about? If you read the docs, then you learned how array declarations for inputs work. You may not *like* the answer, but you shouldn't act like the answer is being hidden from you. "*have the compiler nicely generate the code to reserve the space for it rounded to 16 bytes and addressable in the source code using an index*" That might make sense... until you remember that the byte size for these things is *not defined in GLSL*. It's part of the VAO. – Nicol Bolas Feb 25 '21 at 06:33
  • yes it is all an internal structure - not about bytes but they are numeric representation elements, which no matter what size they are internally it is a collection of elements accessible by an index (or representation of an index) as far as the software writer is concerned. The Khronos docs do not give you the "tricks" and they are not particularly friendly - more like comittee driven RFC papers :) And yes "automagic" is what compilers are designed to do. And of course nice to dissassemble what they create too. – peterk Feb 27 '21 at 23:00