3

I'm working on an ASSIMP skeletal animation loader and renderer and right now all the data is correctly loaded and interpolated at its current timeframe. However, there is still one part that isn't working as it should and that's the vertex shader stage.

Via a VBO I pass in two vec4s that contain the bone IDs and the weights for each vertex (up to a maximum of 4 bones/weights per vertex) and the vertex shader has a matrix array of 100 bone transformations (pre-calculated per frame) that are indexed via the bone IDs.

However, it seems that the bones uniform doesn't contain the proper transformations. For debugging purposes I colored the model with the weight values and the bone IDs value and they contain a color (and thus valid values). However, when I transform my vertex via the bone transformation and color the model with the result, the entire model is colored black, meaning the transformation matrices are all 0.0. So they're not initialized properly.

I think the problem is with passing the matrices to the uniform array, or perhaps the maximum size of uniforms allowed (I also tried setting the number of uniform matrices to 32 (number of bones on current model) but without effect)?

Before passing the information to the shader, the transformation matrices are indeed valid matrices (not identity/empty matrices) so the fault should probably be in the GLSL shader or the passing of the uniforms.

The following code is from the vertex shader:

#version 330
layout (location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 tangent;
layout(location = 3) in vec3 color;
layout(location = 4) in vec2 texCoord;
layout(location = 5) in ivec4 boneIDs;
layout(location = 6) in vec4 weights;

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 bones[100];

out vec2 TexCoord;
out vec4 colorz;

void main()
{
    vec4 newPos = vec4(position, 1.0);
    colorz = vec4(0.0, 1.0, 0.0, 1.0);
    if (weights != vec4(0.0, 0.0, 0.0, 0.0))
    {
        mat4 boneTransform = bones[boneIDs[0]] * weights[0];
        boneTransform += bones[boneIDs[1]] * weights[1];
        boneTransform += bones[boneIDs[2]] * weights[2];
        boneTransform += bones[boneIDs[3]] * weights[3];

        // newPos = boneTransform * vec4(position, 1.0);
        vec4 test = vec4(1.0);
        colorz = boneTransform * test;
        // newPos = boneTransform * newPos;
    }

    TexCoord = texCoord;
    gl_Position = projection * view * model * newPos;
}

The following snippet of code pass the matrix data to the GLSL shader:

// Sets bone transformation matrices
void Shader::SetBoneMatrix(GLint index, aiMatrix4x4 matrix)
{
    glm::mat4 mat = glm::transpose(glm::make_mat4(&matrix.a1));
    glUniformMatrix3fv(boneLocations[index], 1, GL_FALSE, glm::value_ptr(mat));  
}

Also the code that gets all the uniform locations of the bones array:

for(unsigned int i = 0; i < 100; i++)
{
    string name = "bones[";
    string number;
    stringstream ss;
    ss << i;
    ss >> number;
    name += number;
    name += ']';
    boneLocations[i] = glGetUniformLocation(this->program, name.c_str());
}
Kromster
  • 7,181
  • 7
  • 63
  • 111
Joey Dewd
  • 1,804
  • 3
  • 20
  • 43
  • 1
    @Katianie yeah, this is done at the last line of the vertex shader :) `gl_Position = projection * view * model * newPos;` the `newPos` variable is there multiplied by the MVP matrix. – Joey Dewd Dec 27 '13 at 15:48
  • Could it be a problem with lighting or normals since you said you can see the model but its all black? – Katianie Dec 27 '13 at 15:51
  • @Katianie if I just render the model normally it dissapears (probably because all the vertices become `0.0`) so I started coloring my model as a debugging tool. Since I passed in my transformation matrix data the model became black (so the transformation matrix data must be `0.0`), that's why it's black :). The rendering phase works just fine ^^ – Joey Dewd Dec 27 '13 at 15:53
  • Are you sure the model is not getting culled because its not in the view frustrum or if the near/far cliping planes are set up correctly(ie near >= 1)? – Katianie Dec 27 '13 at 15:57
  • @Katianie I'm sure the model is fine, because the model is rendering like it should (but with a special color) since I'm not multiplying the bone transformation with the vertex position at the moment (for debugging), but just pass the (unmodified by animation) position to the pipeline. – Joey Dewd Dec 27 '13 at 16:04
  • Are you able to look at the xml of the model itself? You might be able to see if the values are in there. – Katianie Dec 27 '13 at 16:05
  • 1
    @Katianie yeah, the transformations are indeed valid values (I should add that to my question), thanks for noticing. – Joey Dewd Dec 27 '13 at 16:07
  • I noticed that some shader code uses gl_ModelViewMatrix, gl_NormalMatrix, etc. Maby that's the way you have to get the matrices into the shader now? – Katianie Dec 27 '13 at 16:13
  • 1
    @Katianie that's for older versions of GLSL and is mainly used for old OpenGL programming (as far as I believe). No offense to you Katianie since I appreciate any help, but right now it looks like you're trying to help me without having any expertise on skeletal animation (or ASSIMP) which is not helping me out to be honest :p. – Joey Dewd Dec 27 '13 at 16:19
  • Please show us how you retrieve `boneLocations[]` array in C++ part. Can you use shader debugger, such as NVIDIA nSight? – Ivan Aksamentov - Drop Dec 27 '13 at 16:41
  • 1
    I'm not submitting this as an answer, as its just a workaround, but I never had much luck with large uniform arrays in OpenGL, so in my engine I encode N bone matrices in a 4N wide 1D texture of float4s and update that every frame (I store the 4 columns of each matrix in adjacent texels). It's fast and works on all hardware I've tested on; but it's a kludge. – MikeMx7f Dec 27 '13 at 17:05
  • @Drop: I will edit my question with the `boneLocations[]` code. I also have an ATI card, I will search if ATI has similar tools for debugging (not familiar with shader debugging). @MikeMx7f: Thanks! It's good to know that there are alternatives, if this thing really doesn't work out I will try and look up your implementation. – Joey Dewd Dec 27 '13 at 17:11
  • @JoeyDewd did you checked your `boneLocations[i]`? Did values seems to be correct? – Ivan Aksamentov - Drop Dec 27 '13 at 17:27
  • @Drop yeah, the values range from 0 to 99. (Other uniforms are done at a later stage) – Joey Dewd Dec 27 '13 at 17:29
  • 1
    A Uniform Buffer Object would be a much better alternative to a 1D texture. But more to the point, there is no point in querying the location for each of those uniforms in the array. You can check the size of the array with some code like I have in this [answer](http://stackoverflow.com/questions/19894839/opengl-uniform-array-of-structures/19918602#19918602)... each uniform location in an array is sequentially assigned, so you only need to know the location of the first uniform in the array. – Andon M. Coleman Dec 27 '13 at 19:23
  • Also, how are you supplying the vertex attribute for `boneIDs`? A common mistake is to use `glVertexAttribPointer (...)` for integer vertex attributes, which may work on some implementations but is not supposed to. – Andon M. Coleman Dec 27 '13 at 19:39
  • @Andon M. Coleman thanks! You're right, that's a Nice optimization :) I'm also using the integer version of the glVertexAttribPointer and when debugging the valies, the IDs and weights are fine (their values are shown as colors on the model) so that shouldn't be a problem. – Joey Dewd Dec 27 '13 at 21:32

1 Answers1

1

Oké, via glslDevil I came across a continous GL_INVALID_OPERATION error when setting the bone matrix to the shader via glUniformMatrix. The origin of the problem was indeed at the stage where the program passes the information along to the shader.

It is quite a stupid mistake actually since I'm using glUniformMatrix3f instead of glUniformMatrix4f. Changing this did indeed solve the problem and the animations are working perfectly right now.

Joey Dewd
  • 1,804
  • 3
  • 20
  • 43