Hi guys thanks for the support, I tried to understand what is the problem without success, so I decided to write a simple C test program, render only the skeleton as lines and nothing else.
I made a file with the bind pose joint positions and rotations:
3
-1 Bone01 0.0000 0.0000 0.0000 / -90.0000 0.0000 0.0000
0 Bone02 25.0000 0.0000 0.0000 / 0.0000 0.0000 0.0000
1 Bone03 25.0000 0.0000 0.0000 / 0.0000 0.0000 0.0000
the number in the first line is the number of joints and like before, from the second line we have the parent index, the name, positions and rotations.
I filled a global array of joints(I use glm and glew):
struct JOINT {
GLchar sName[30];
GLint nParent;
vec3 vPosition;
quat quatRotations;
mat4 matLocal, //to parent
matGlobal; //to root
};
[...]
JOINT *g_pBindPose;
GLuint g_uiJointsNum;
[...]
int BuildBindPose()
{
[...]
g_pBindPose = new JOINT[g_uiJointsNum];
[...]
}
For the bind pose calculation I do:
int BuildBindPose()
{
[...]
for (GLuint j = 0; j < g_uiJointsNum; j++) {
g_pBindPose[j].matLocal = translate(mat4(), g_pBindPose[j].vPosition);
g_pBindPose[j].matLocal *= mat4(g_pBindPose[j].quatRotations);
if (g_pBindPose[j].nParent == -1)
g_pBindPose[j].matGlobal = g_pBindPose[j].matLocal;
else
g_pBindPose[j].matGlobal = g_pBindPose[g_pBindPose[j].nParent].matGlobal * g_pBindPose[j].matLocal;
[...]
}
[...]
Now, I have also an animation file with 3 keyframes, is a simple animation where the skeleton starts from the bind pose, then rotates every joint by 30°, then back again to the bind pose, I show you only the second keyframe:
1666.0000 -90.0000 0.0000 30.0000 / 0.0000 -30.0000 -0.0000 / 0.0000 -30.0000 0.0000
the first is the key time in milliseconds, then we have the rotations of the 3 joints.
I just want to render the skeleton in that pose, so in the file loading part I added:
[...]
JOINT *g_pKeyframe;
mat4 *g_pmatTransformations; //final joints transformation
[...]
int LoadAnimations()
{
[...]
g_pKeyframe = new JOINT[g_uiJointsNum];
for (GLuint j = 0; j < g_uiJointsNum; j++) {
g_pKeyframe[j].matLocal = translate(mat4(), g_pBindPose[j].vPosition);
g_pKeyframe[j].matLocal *= mat4(g_pKeyframe[j].quatRotations);
if (g_pKeyframe[j].nParent == -1)
g_pKeyframe[j].matGlobal = g_pKeyframe[j].matLocal;
else
g_pKeyframe[j].matGlobal = g_pKeyframe[g_pKeyframe[j].nParent].matGlobal * g_pKeyframe[j].matLocal;
g_pmatTransformations[j] = g_pKeyframe[j].matGlobal * inverse(g_pBindPose[j].matGlobal);
[...]
}
In the animation there are only rotations so I use the position of the bind pose, is this correct?
I get the quaternion for the rotations in the loading part, with this:
quat GetQuaternionRotation(vec3 vAxis, GLfloat fAngle)
{
quat quatRotation;
quatRotation.x = sin(radians(fAngle / 2.0f)) * vAxis.x;
quatRotation.y = sin(radians(fAngle / 2.0f)) * vAxis.y;
quatRotation.z = sin(radians(fAngle / 2.0f)) * vAxis.z;
quatRotation.w = cos(radians(fAngle / 2.0f));
return quatRotation;
}
for the 3 axis (I know there is already a function for that, but I was learning quaternions and I wrote one):
[...]
g_pKeyframe[j].quatRotations = GetQuaternionRotation(vec3(0.0f, 0.0f, 1.0f), fZAngle) *
GetQuaternionRotation(vec3(0.0f, 1.0f, 0.0f), fYAngle) *
GetQuaternionRotation(vec3(1.0f, 0.0f, 0.0f), fXAngle);
[...]
For rendering the skeleton I use the same type of vertex I use for the meshes:
struct VERTEX {
GLfloat x, y, z, //position
nx, ny, nz, //normal
tu, tv, //texture coord.
tx, ty, tz, //tangent
bx, by, bz, //binormal
w[4]; //weights
GLint j[4]; //joints indices
};
here my simple vertex shader:
#version 330 core
layout (location = 0) in vec3 vVertexPos;
layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec2 vTexCoords;
layout (location = 3) in vec3 vTangent;
layout (location = 4) in vec3 vBitangent;
layout (location = 5) in vec4 vWeight;
layout (location = 6) in ivec4 vJoint;
uniform mat4 matTransforms[30]; //final transformations
uniform mat4 matProjection;
uniform mat4 matView;
uniform mat4 matModel;
out vec3 vColor;
void main()
{
vColor = vec3(1.0, 0.5, 0.7);
vec4 vNewVertex = (matTransforms[vJoint[0]] * vec4(vVertexPos, 1.0)) * vWeight[0]; //only one joint
gl_Position = matProjection * matView * matModel * vec4(vNewVertex.xyz, 1.0);
}
The idea, is that I have six vertices, 2 for joint, skinned to the skeleton, like my above post, the vertices are the global joint positions in bind pose, I couple a joint with his parent to form a line (bone).
The same formula I use in the shader, works if I calculate the position outside of it, everything is correct even if I don’t understand the rotations of the root node (I extracted these from the fbx file) it works like in the modelling software I use.
I took the formula from here.
The vertex array creation:
glGenVertexArrays(1, &g_uiVAO);
glGenBuffers(1, &g_uiVBO);
glGenBuffers(1, &g_uiEBO);
glBindVertexArray(g_uiVAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_uiEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*g_uiIndicesNum, g_puiIndices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, g_uiVBO);
glBufferData(GL_ARRAY_BUFFER, g_uiVerticesNum * sizeof(VERTEX), &g_pVertices[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (GLvoid*)0);//vertices
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (GLvoid*)(3 * sizeof(GLfloat)));//normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (GLvoid*)(6 * sizeof(GLfloat)));//texture coord.
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (GLvoid*)(8 * sizeof(GLfloat)));//tangent
glEnableVertexAttribArray(3);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (GLvoid*)(11 * sizeof(GLfloat)));//binormal
glEnableVertexAttribArray(4);
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(VERTEX), (GLvoid*)(14 * sizeof(GLfloat)));//weights
glEnableVertexAttribArray(5);
glVertexAttribPointer(6, 4, GL_INT, GL_FALSE, sizeof(VERTEX), (GLvoid*)(18 * sizeof(GLfloat)));//joints indices
glEnableVertexAttribArray(6);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
g_puiIndices is an array of 6 unsigned int ordered from 0 to 5.
I send the final matrices with this:
[...]
for (GLuint m = 0; m < g_uiJointsNum; m++)
glUniformMatrix4fv(glGetUniformLocation(g_uiShaderProgram, ("matTransforms[" + to_string(m) + "]").c_str()), 1, GL_FALSE,
value_ptr(g_pmatTransformations[m]));
[...]
and this is the render pass:
glBindVertexArray(g_uiVAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_uiEBO);
glDrawElements(GL_LINES, g_uiIndicesNum, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
I tried all the week reading many times and changing stuff, but I can’t get out of it.
Maybe you can see something I can’t, or advise me.:o
(How can I upload images?)
Thank you in advance.