2
$\begingroup$

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, 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.

$\endgroup$
0

1 Answer 1

5
$\begingroup$

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));
$\endgroup$
1
  • $\begingroup$ Hey thanks a lot! I just have a question, how do I pass the weights as normalized shorts/bytes? $\endgroup$ Oct 14, 2020 at 18:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.