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.
However in vulkan in comes out like this:
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.