Hello everyone. I have been trying to get a model into a pose other than its bind pose. Currently I’m using the first frame out of an animation file and trying to set the model into that initial pose.
I believe my math equations are now correct. Transforming a single bone works perfectly (the children follow like it should). However, with Compound Transformations (where a child is transformed, and its parent has also been transformed), very young children seem to be highly deformed. (For example, the fingers of the model when the wrist, elbow, and shoulder bones have also been transformed.)
int targetFrame = CONST_TEST_FRAME_NUMBER;
// root bone
PMXBone *b = pmxInfo.bones[0];
BoneFrame *bf = getBoneFrame(targetFrame, b->name);
b->absoluteForm = b->relativeForm;
if(bf!=NULL)
{
b->finalRotation = bf->quaternion;
glm::vec4 homoPosition=glm::vec4(b->position + bf->translation,1.0); //position in homogeneous coordinates
glm::vec4 localPosition=glm::rotate(b->finalRotation,homoPosition);
b->relativeForm[3][0]=localPosition[0];
b->relativeForm[3][1]=localPosition[1];
b->relativeForm[3][2]=localPosition[2];
b->relativeForm[3][3]=localPosition[3];
}
Bone[0] = b->absoluteForm * invBindPose[0];
// other bones
for (size_t i = 1; i < pmxInfo.bone_continuing_datasets; i++)
{
b = pmxInfo.bones[i];
PMXBone *parent = pmxInfo.bones[b->parentBoneIndex];
bf = getBoneFrame(targetFrame, b->name);
if(bf!=NULL)
{
b->finalRotation = glm::normalize(bf->quaternion * parent->finalRotation);
glm::vec4 homoPosition=glm::vec4(b->position + bf->translation,1.0); //position in homogeneous coordinates
glm::vec4 localPosition=glm::rotate(glm::normalize(parent->finalRotation),homoPosition);
b->relativeForm[3][0]=localPosition[0];
b->relativeForm[3][1]=localPosition[1];
b->relativeForm[3][2]=localPosition[2];
b->relativeForm[3][3]=localPosition[3];
b->absoluteForm = b->relativeForm * glm::toMat4(bf->quaternion) * parent->absoluteForm;
Bone[i] = b->absoluteForm * invBindPose[i];
}
else
{
b->finalRotation = glm::normalize(parent->finalRotation);
glm::vec4 homoPosition=glm::vec4(b->translation,1.0); //position in homogeneous coordinates
glm::vec4 localPosition=glm::rotate(b->finalRotation,homoPosition);
b->relativeForm[3][0]=localPosition[0];
b->relativeForm[3][1]=localPosition[1];
b->relativeForm[3][2]=localPosition[2];
b->relativeForm[3][3]=localPosition[3];
b->absoluteForm = b->relativeForm * parent->absoluteForm;
Bone[i] = b->absoluteForm * invBindPose[i];
}
}
To help clarify the code some:
[ul]
[li]b->position is a glm::vec3 containing the position of the Bone in its Local/Bone-space, relative to the Parent Bone. [/li][li]bf contains the transformation information for one bone in one frame. In other words, you must get multiple Bone Frames to get the transformation information for all the bones in one frame. [/li][li]bf->quaternion is a 4-float glm::quat containing the rotational information for bone-frame in the animation. In other words, it contains information on how the bone must be rotated to get the model from its bind pose to the current pose. [/li][li]Similarly, bf->translation, a glm::vec3, contains the translational information for the bone-frame. Because human skeletons are rigid, most of the values for bf->translation are set to (0,0,0). [/li][li]relativeForm and absoluteForm refer to the Local and Global matrices of the transformed bones, respectively. Before this code snippet is run, relativeForm is simply b->position converted to a matrix, and absoluteForm is the Bind Pose matrix for the bone. [/li][li]Bone[] is the Final Skinning Matrix, which is sent to the shader. [/li][/ul]
Here is an image of how the model appears with this code: imgur.com/tbur5Lf
As an extra, here is an image of a single bone in the model being transformed using this code (Instead of bf, a keyboard-controlled quaternion was used): t.co/wf38ibGoyc
Here is a video that demonstrates my problem: youtu.be/8Cv3jMYcz64
It took me a good two weeks to get this far, so I greatly appreciate any help. Thanks, and let me know if there is any other information I need to provide.