-1

I am trying to render a 3D object, but not animated. Just in a single pose. However, the results are not good.

See in blender, I have a cube with 3 bones and I twisted it. I am trying to render this exact same posed cube in vulkan.

enter image description here

However in vulkan in comes out like this:

enter image description here

Model Data:

   vertex v0 = { glm::vec3(-1.0000f, -1.0000f, -1.0000f), glm::vec3(-0.5774f, -0.5774f, -0.5774f), glm::vec2(0.3750f, 0.0000f),{0} };
   v0.weights[0] = 0.851375f;
   v0.weights[1] = 0.062667f;
   v0.weights[2] = 0.085958f;
   v0.jointIDs = { 0, 1, 2, 0 };

   vertex v1 = { glm::vec3(-1.0000f, -1.0000f, 1.0000f), glm::vec3(-0.5774f, -0.5774f, 0.5774f), glm::vec2(0.6250f, 0.0000f),{0} };
   v1.weights[0] = 0.051895f;
   v1.weights[1] = 0.449438f;
   v1.weights[2] = 0.498667f;
   v1.jointIDs = { 0, 1, 2, 0 };

   vertex v2 = { glm::vec3(-1.0000f, 1.0000f, -1.0000f), glm::vec3(-0.5774f, 0.5774f, -0.5774f), glm::vec2(0.6250f, 0.2500f),{0} };
   v2.weights[0] = 0.856987f;
   v2.weights[1] = 0.143013f;
   v2.jointIDs = { 0, 2, 0, 0 };

   vertex v3 = { glm::vec3(-1.0000f, 1.0000f, 1.0000f), glm::vec3(-0.5774f, 0.5774f, 0.5774f), glm::vec2(0.3750f, 0.2500f),{0} };
   v3.weights[0] = 0.071875f;
   v3.weights[1] = 0.023990f;
   v3.weights[2] = 0.904135f;
   v3.jointIDs = { 0, 1, 0, 0 };

   vertex v4 = { glm::vec3(1.0000f, -1.0000f, -1.0000f), glm::vec3(0.5774f, -0.5774f, -0.5774f), glm::vec2(0.3750f, 0.2500f),{0} };
   v4.weights[0] = 0.824344f;
   v4.weights[1] = 0.075163f;
   v4.weights[2] = 0.100492f;
   v4.jointIDs = { 0, 1, 2, 0 };

   vertex v5 = { glm::vec3(1.0000f, -1.0000f, 1.0000f), glm::vec3(0.5774f, -0.5774f, 0.5774f), glm::vec2(0.6250f, 0.2500f),{0} };
   v5.weights[0] = 0.044990f;
   v5.weights[1] = 0.456830f;
   v5.weights[2] = 0.498181f;
   v5.jointIDs = { 0, 1, 2, 0 };

   vertex v6 = { glm::vec3(1.0000f, 1.0000f, -1.0000f), glm::vec3(0.5774f, 0.5774f, -0.5774f), glm::vec2(0.6250f, 0.5000f),{0} };
   v6.weights[0] = 0.862886f;
   v6.weights[1] = 0.137114f;
   v6.jointIDs = { 0, 2, 0, 0 };

   vertex v7 = { glm::vec3(1.0000f, 1.0000f, 1.0000f), glm::vec3(0.5774f, 0.5774f, 0.5774f), glm::vec2(0.3750f, 0.5000f),{0} };
   v7.weights[0] = 0.106811f;
   v7.weights[1] = 0.056511f;
   v7.weights[2] = 0.836678f;
   v7.jointIDs = { 0, 1, 2, 0 };

For reference, Joint IDs:

    0 = Bone
    1 = Bone.001
    2 = Bone.002

This means thats v6 is affected by Bone with a weight of 0.862886f and Bone.002 with a weight of 0.137114f.

What I have established above is the geometry data, as well as the number of joints that affect a vertex, and the weight of each joint that affects the vertex. I also have a jointID array to tie a vertex's weight at index i to a specific joint.

So with that out of the way, I was under the impression that the only other thing I needed in addition to the joint/weight data above was just the inverse bind pose matrix?

   //Bone Inverse Bind Pose Matrix
   glm::mat4 gMatrix1 = glm::mat4(
   glm::vec4(1.0000f, -0.0000f, 0.0000f, -0.0000f),
   glm::vec4(-0.0000f, 1.0000f, -0.0000f, 0.0000f),
   glm::vec4(0.0000f, -0.0000f, 1.0000f, -0.0000f),
   glm::vec4(-0.0000f, 0.0000f, -0.0000f, 1.0000f));

   //Bone.001 Inverse Bind Pose Matrix
   glm::mat4 gMatrix2 = glm::mat4(
   glm::vec4(0.2870f, -0.6995f, -0.6544f, -0.0000f),
   glm::vec4(0.2725f, 0.7146f, -0.6443f, 0.0000f),
   glm::vec4(0.9184f, 0.0066f, 0.3957f, -0.0000f),
   glm::vec4(-0.0000f, 0.0000f, -0.0000f, 1.0000f));

   //Bone.002 Inverse Bind Pose Matrix
   glm::mat4 gMatrix3 = glm::mat4(
   glm::vec4(0.9936f, -0.0703f, 0.0883f, -0.0000f),
   glm::vec4(0.0454f, 0.9651f, 0.2578f, 0.0000f),
   glm::vec4(-0.1034f, -0.2522f, 0.9621f, -0.0000f),
   glm::vec4(-0.0000f, 0.0000f, -0.0000f, 1.0000f));

For context, gMatrix1, 2 and 3 are sent to the shader from the CPU as index 0, 1 and 2.

Then in the shader is where I calculate the bone transforms:

   void main() 
   {    
    mat4 BoneTransformation = mat4(0.0);
    for (int i = 0; i < 4; i++)
    {
        if (inWeights[i] == 0.0)
            break;
        BoneTransformation += uboTransformations.gBones[inJointIDs[i]] * inWeights[i];        
    }
    
    vec4 PosL = BoneTransformation * vec4(inPosition, 1.0);

    gl_Position = uboTransformations.projectionViewMatrix * PosL;
   
    fragTexCoord = vec2(inTexCoord);
    fragNormals = mat3(transpose(inverse(uboTransformations.model))) * vec3(inNormals);
    outMeshID = inMeshID;
   }

As you can see, I create an initial mat4 then add to it the following: gMatrix @ jointID * weight @ boneIndex.

Then multiply that by the vertex attribute, then multiply that by the projectionviewmatrix.

If you're wondering why I have i < 4, it's just because I limit my joints/weights for now to 4.

layout(location = 3) in vec4 inWeights;
layout(location = 4) in ivec4 inJointIDs;

Am I correct in assuming that this all the data I need? Or do I need anything else? Because I am not sure where my problem lies. Either my code is wrong, or the data I am harvesting is incorrect.

genpfault
  • 51,148
  • 11
  • 85
  • 139

0 Answers0