Jump to content

  • Log In with Google      Sign In   
  • Create Account

Skeletal Animation Shader for an Assimp Model

  • You cannot reply to this topic
5 replies to this topic

#1 Chicktopus   Members   -  Reputation: 126

Like
0Likes
Like

Posted 28 August 2014 - 03:24 PM

Hi guys
 
I'm having some trouble getting my skeletal animation working. I've imported the model with Assimp, created the bone hierarchy, calculated all the bone transforms, so on and so forth. I've debugged through the code and the bone information *looks* like it's updating as I'd expect. The issue I'm having seems to come from the shader. As soon as I start using the bone information to update the position, the model ceases to display. I'm not sure whether this is because the bone information hasn't been successfully passed to the shader, the multiplications are wrong, or for some other reason (such as the model is now positioned out-of-view of the camera). If required I can post the entire contents of the class so you can see the entire process. Any input would be ace.
 
Here's the vertex shader code:
 

    #version 330
    
    layout (location = 0) in vec3 inPosition;
    layout (location = 1) in vec2 inCoord;
    layout (location = 2) in vec3 inNormal;
    layout (location = 3) in ivec4 BoneIDs;
    layout (location = 4) in vec4 Weights;
    
    smooth out vec3 vNormal;
    smooth out vec2 vTexCoord;
    smooth out vec3 vWorldPos;
    smooth out vec4 vEyeSpacePos;
    
    uniform struct Matrices
    {
     mat4 projMatrix;
     mat4 modelMatrix;
     mat4 viewMatrix;                                                                           
     mat4 normalMatrix;
    } matrices;
    
    const int MAX_BONES = 100;
    uniform mat4 gBones[MAX_BONES];
    
    void main()
    {
      mat4 BoneTransform = gBones[BoneIDs[0]] * Weights[0];
      BoneTransform     += gBones[BoneIDs[1]] * Weights[1];
      BoneTransform     += gBones[BoneIDs[2]] * Weights[2];
      BoneTransform     += gBones[BoneIDs[3]] * Weights[3];
     
      mat4 m_MV = matrices.viewMatrix*matrices.modelMatrix;  
      mat4 m_MVP = matrices.projMatrix*matrices.viewMatrix*matrices.modelMatrix;
      vTexCoord = inCoord;
     
      vec4 m_transPos = BoneTransform * vec4(inPosition, 1.0);
      vEyeSpacePos = m_MV * m_transPos;
      gl_Position = m_MVP * m_transPos;
      
        vec4 m_normal = BoneTransform * vec4(inNormal, 1.0);
        vNormal      = (matrices.modelMatrix * m_normal).xyz;
        vWorldPos    = (matrices.modelMatrix * m_transPos).xyz;      
    }
Here's the Draw() function as it stands, in which the bone information and uniforms are passed to the shader:
 

    void Sprite::Draw()
    {
     glBindVertexArray(g_VAO);
     g_mainSP.UseProgram();
    
     g_mainSP.SetUniform("matrices.projMatrix", g_projMat);
     g_mainSP.SetUniform("matrices.viewMatrix", g_viewMat);
     g_mainSP.SetModelAndNormalMatrix("matrices.modelMatrix", "matrices.normalMatrix", g_modelMat);
     for (uint i = 0; i < g_transforms.size(); i++) {
     g_mainSP.SetBoneTransform(i, g_transforms[i]);
     }
    
     g_mainSP.SetUniform("gSampler", 0);
     g_mainSP.SetUniform("vColor", glm::vec4(1, 1, 1, 1));
     g_ambient.SetUniformData(&g_mainSP, "sunLight");
    
     if (!g_loaded)return;
     for (uint i = 0; i < g_subMeshes.size(); i++) 
     {
     const uint m_matIndex = g_subMeshes[i].materialIndex;
     g_textures[m_matIndex].BindTexture();
     aiMesh* m_mesh = g_scene->mMeshes[i];
     glDrawElementsBaseVertex(GL_TRIANGLES,
     g_subMeshes[i].numIndices,
     GL_UNSIGNED_INT,
     (void*)(sizeof(uint)* g_subMeshes[i].baseIndex),
     g_subMeshes[i].baseVertex);
     }
     glBindVertexArray(0);
    }
 
Finally:
 
  
  void ShaderProgram::SetBoneTransform(glm::uint p_index, const glm::mat4& p_transform)
    {
     glUniformMatrix4fv(g_boneLoc[p_index], 1, GL_TRUE, glm::value_ptr<GLfloat>(p_transform));
    }


Sponsor:

#2 Buckeye   Crossbones+   -  Reputation: 4932

Like
1Likes
Like

Posted 28 August 2014 - 06:49 PM


I'm not sure whether this is because the bone information hasn't been successfully passed to the shader, the multiplications are wrong, or for some other reason (such as the model is now positioned out-of-view of the camera)

 

What have you tried to determine those values? Staring at code isn't nearly as effective as looking at actual values. There are two pieces to debugging - the values have to be correct, and the code has to use them correctly.

 

Also, you're reserving 400 registers for just your bone matrices. Does your shader version/GPU support that? Do you seriously have models with 100 bones?


Edited by Buckeye, 28 August 2014 - 06:53 PM.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#3 Chicktopus   Members   -  Reputation: 126

Like
0Likes
Like

Posted 29 August 2014 - 02:37 AM

Hi, 

 

Thanks for the quick reply. This is the first time I've had to do skeletal animation, so I'm basing most things to do with the bones/animation side of things off the tutorial found here. Using the project included with that tutorial, I can debug both pieces of code at once to determine whether my values (bone location, indices, etc.) conform. Thus far the only difference I've been able to detect has been in the bone matrix transformations passed to glUniformMatrix4fv, but I'd expect that, considering the values are calculated from times and furthermore, the range of the matrix values seems correct.

 

You're quite right about the model not having 100 bones (it's around 30 I believe), however I'm hoping to use this shader for other models which may have more bones, in order to ensure that animations as a whole are working correctly. Once I'm certain they are, I'll be re-visiting the shader to only reserve the necessary number of bones for the model. Considering the project along with the tutorial works and that my computer has quite a reasonable spec, I don't see why similar code shouldn't work in my project.



#4 Buckeye   Crossbones+   -  Reputation: 4932

Like
1Likes
Like

Posted 29 August 2014 - 07:02 AM


Considering the project along with the tutorial works and that my computer has quite a reasonable spec, I don't see why similar code shouldn't work in my project.

 

But it doesn't work. ohmy.png

 

Skinned mesh animation is one of the most difficult subjects to get working in intermediate programming. If you just guess or assume things should work, it will likely take a long time to get your code running properly. You've asked for help and gotten a suggestion of something to look at which might take 2 minutes, but your response is to dismiss the oberservation, saying it shouldn't be the problem.

 

First: You have to want to find the problem. If you're program doesn't work properly, you're going to have to do something to the code to get it fixed.

 

Second: The suggestion wasn't frivolous. GPUs do have limitations. Why wouldn't you check that your shader version is compatible with your hardware?

 

Third: It might take you 2 minutes to change the buffer size (to, say, 40?), recompile and run the app. It's been over 12 hours that you've had the problem. Why wouldn't you take 2 minutes of that time for a quick test?

 

That being said, you can try using identity matrices for both the inverse bind pose and animation matrices. That should result in the vertices being rendered in bind pose without any change other than world-view-projection conversion to screen space. That will give you a good indication if the shader is working in that regard.


Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#5 Chicktopus   Members   -  Reputation: 126

Like
0Likes
Like

Posted 29 August 2014 - 10:58 AM

Sorry, at the time of that post I didn't have access to the code. I've just altered the MAX_BONES to 40, but sadly it hasn't made a difference. The shader version used above is the same as the other shaders in the project so I assumed this wasn't the issue. When I get a chance I'm going to try your suggestion and then have another thorough debug of both my project and the tutorial to see if I spot any discrepancies. Thanks for your help so far!



#6 Chicktopus   Members   -  Reputation: 126

Like
0Likes
Like

Posted 01 September 2014 - 01:50 PM

I've tried passing the identity matrix for the animation matrix / inverse bind pose doesn't make a difference either, the mesh still isn't rendering (even when passing the identity matrix directly to the shader). This being said, if in the shader itself I set the bone matrix to the identity, the mesh does indeed render in bind pose, so this suggests the bone information isn't being sent to the shader properly, although I can't pinpoint why as the VBO containing the bone information is in the same VAO as the VBO containing the vertex/texture/normal and IBO and the locations are correct.
 
One additional thing I noticed during my debug comparison is that the result of some matrix multiplications *are* different (as unlike the tutorial I'm using GLM as a maths library), so some issues could be from GLM's row-major vs. OpenGL's column major, but I'll deal with this once I have something displaying!
 
 
 
 
Thanks 






PARTNERS