<p>The standard solution is to reduce the amount of per-vertex data by only specifying the 4 indices that have the highest weights (and rescaling the weights to add up to 1.0). That way, you can pass 4 weights as a <code>vec4</code> and 4 indices as a <code>uvec4</code>. Also, you should pass the weights as normalized shorts (or bytes if you can accept the quality loss) and indices as bytes if at all possible, to further reduce the per-vertex data storage.</p>
<p>Most real-time rendering systems are happy with these limitations.</p>
<p>If that's not acceptable for your needs, then you're going to have to use multiple attributes to send the data. Each attribute can only have 4 components. And while attributes can be arrayed, arraying them like your C struct would waste a bunch of attribute locations, since each array element is considered a <em>separate</em> location.</p>
<p>So you need to send values in multiples of 4. Instead of sending 10 weights/indices, send 12, grouped into 4-element groupings. So the GLSL would look like this:</p>
<pre><code>layout(location = X) uvec4 indices[3];    //Stores 12 indices, consumes 3 locations.
layout(location = X + 3) vec4 weights[3]; //Stores 12 weights, consumes 3 locations.
</code></pre>
<p>The C data structure ought to also store 12 elements for each array.</p>
<p>To specify them in the vertex format, you would do this (where <code>X</code> is the location given above):</p>
<pre><code>glVertexAttribIPointer(3, 4, GL_INT, sizeof(Vertex), (void*)(offsetof(Vertex, groups) + 0));
glVertexAttribIPointer(4, 4, GL_INT, sizeof(Vertex), (void*)(offsetof(Vertex, groups) + 16));
glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), (void*)(offsetof(Vertex, groups) + 32));
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, weights) + 0));
glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, weights) + 16));
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, weights) + 32));
</code></pre>

CC BY-SA 4.0
2020-10-14T18:19:29.237Z
Hey thanks a lot! I just have a question, how do I pass the weights as normalized shorts/bytes?
Lenny White
CC BY-SA 4.0
2020-10-14T16:45:47.670Z
2021-05-01T18:31:11.870Z
2021-05-01T18:31:11.870Z
Nicol Bolas
<p>I want to load a vertex buffer with vertices of struct <code>Vertex</code>:</p>
<pre><code>struct Vertex {
   Vector3 position;
   Vector3 normal;
   Vector2 uv;
   int groups[10];
   float weights[10];
};
</code></pre>
<p>According to <a href="https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glVertexAttribPointer.xhtml" rel="nofollow noreferrer">khronos manual</a>, the number of elements in vertex attributes must be <code>1,2,3,4</code>. If that is the case how do I load the vertex attributes consisting of more elements, in this case 10?</p>
<p>Is this not valid?</p>
<pre><code>  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));  
  glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, uv));  
  glVertexAttribIPointer(3, 10, GL_INT, sizeof(Vertex), (void*)offsetof(Vertex, groups));   
  glVertexAttribPointer(4, 10, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, weights));
    
</code></pre>
<p>I need groups and weight vertex attributes for skeletal deformation.</p>

<opengl><c++>
Max number of elements in a vertex attribute
Lenny White
# Max number of elements in a vertex attribute

(Asked by: username_0 on 2020-10-13)

I want to load a vertex buffer with vertices of struct `Vertex`:

```
struct Vertex {
   Vector3 position;
   Vector3 normal;
   Vector2 uv;
   int groups[10];
   float weights[10];
};

```

According to [khronos manual](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glVertexAttribPointer.xhtml), the number of elements in vertex attributes must be `1,2,3,4`. If that is the case how do I load the vertex attributes consisting of more elements, in this case 10?

Is this not valid?

```
  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));  
  glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, uv));  
  glVertexAttribIPointer(3, 10, GL_INT, sizeof(Vertex), (void*)offsetof(Vertex, groups));   
  glVertexAttribPointer(4, 10, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, weights));
    

```

I need groups and weight vertex attributes for skeletal deformation.

**Tags:** opengl, c++


---

## 1 answers

### Answer by username_1 on 2020-10-14. Score: 5 | Accepted answer

The standard solution is to reduce the amount of per-vertex data by only specifying the 4 indices that have the highest weights (and rescaling the weights to add up to 1.0). That way, you can pass 4 weights as a `vec4` and 4 indices as a `uvec4`. Also, you should pass the weights as normalized shorts (or bytes if you can accept the quality loss) and indices as bytes if at all possible, to further reduce the per-vertex data storage.

Most real-time rendering systems are happy with these limitations.

If that's not acceptable for your needs, then you're going to have to use multiple attributes to send the data. Each attribute can only have 4 components. And while attributes can be arrayed, arraying them like your C struct would waste a bunch of attribute locations, since each array element is considered a *separate* location.

So you need to send values in multiples of 4. Instead of sending 10 weights/indices, send 12, grouped into 4-element groupings. So the GLSL would look like this:

```
layout(location = X) uvec4 indices[3];    //Stores 12 indices, consumes 3 locations.
layout(location = X + 3) vec4 weights[3]; //Stores 12 weights, consumes 3 locations.

```

The C data structure ought to also store 12 elements for each array.

To specify them in the vertex format, you would do this (where `X` is the location given above):

```
glVertexAttribIPointer(3, 4, GL_INT, sizeof(Vertex), (void*)(offsetof(Vertex, groups) + 0));
glVertexAttribIPointer(4, 4, GL_INT, sizeof(Vertex), (void*)(offsetof(Vertex, groups) + 16));
glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), (void*)(offsetof(Vertex, groups) + 32));
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, weights) + 0));
glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, weights) + 16));
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(offsetof(Vertex, weights) + 32));

```

> **Comments:**
> **username_0**: Hey thanks a lot! I just have a question, how do I pass the weights as normalized shorts/bytes?  

---

