3
votes

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());
}
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
@Katianie yeah, the transformations are indeed valid values (I should add that to my question), thanks for noticing.Joey Dewd
@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
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
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... 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

1 Answers

1
votes

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.