I'm using open asset importer to try and animate a model (Trying CPU animation).
While the file is being parsed, i build up a skeleton:
for (int i = 0; i < m_vSkeleton.size(); ++i) {
Joint& joint = m_vSkeleton;
if (joint.Parent() == -1) {
joint.Working() = BuildMatrix(joint.Rotation(), joint.Translation());
} else {
joint.Working() = BuildMatrix(joint.Rotation(), joint.Translation()) * m_vSkeleton[joint.Parent()].Working();
}
}
At this point if i render the skeleton it displays fine. I then load the translation and rotation frames
for (int i = 0; i < scene->mNumAnimations; ++i) {
aiAnimation* animation = scene->mAnimations;
for (int j = 0; j < animation->mNumChannels; ++j) {
aiNodeAnim* channel = animation->mChannels[j];
Joint& joint = m_vSkeleton[skeletonMap[channel->mNodeName.data]];
for (int k = 0; k < channel->mNumRotationKeys; ++k) {
aiQuatKey* rotationKey = &channel->mRotationKeys[k];
joint.RotationTrack().push_back(RotationFrame());
RotationFrame& frame = joint.RotationTrack()[joint.RotationTrack().size() - 1];
frame.time = float(rotationKey->mTime);
frame.rotation = Quaternion(rotationKey->mValue.w, rotationKey->mValue.x, rotationKey->mValue.y, rotationKey->mValue.z);
} // k
for (int k = 0; k < channel->mNumPositionKeys; ++k) {
aiVectorKey* positionKey = &(channel->mPositionKeys[k]);
joint.TranslationTrack().push_back(TranslationFrame());
TranslationFrame& frame = joint.TranslationTrack()[joint.TranslationTrack().size() - 1];
frame.time = float(positionKey->mTime);
frame.translation = Vector(positionKey->mValue.x, positionKey->mValue.y, positionKey->mValue.z);
frame.translation.w = 1.0f;
} // k
} // j
totalDuration += float(animation->mDuration);
numFrames += float(animation->mDuration * animation->mTicksPerSecond);
playbackSpeed += float(animation->mTicksPerSecond);
} // i
Finally, i animate the skeleton:
void Animation::ArticulateSkeletonToClip(float deltaTime) {
if (m_nPlayback > m_pCurrentAnimation->m_nDuration) {
if (m_pCurrentAnimation->m_nPlaybackMode == AnimationClip::kPlaybackLoop) {
m_nPlayback -= m_pCurrentAnimation->m_nDuration;
}
} else m_nPlayback += deltaTime;
m_nPlayback = 0.0f;
for (int i = 0; i < m_vSkeleton.size(); ++i) {
Joint& joint = m_vSkeleton;
if (joint.TranslationTrack().size() == 0 && joint.RotationTrack().size() == 0)
continue;
Matrix localTransform = BuildMatrix(joint.Rotation(), joint.Translation());
Vector animatedTranslation; Quaternion animatedRotation;
// Find the translation frame number
int frame = m_pCurrentAnimation->m_nStartFrame;
while (frame < m_pCurrentAnimation->m_nEndFrame &&
joint.TranslationTrack()[frame].time < m_nPlayback) ++frame;
if (frame > m_pCurrentAnimation->m_nEndFrame) frame = m_pCurrentAnimation->m_nEndFrame;
// Interpolate translation
if (frame == m_pCurrentAnimation->m_nStartFrame) { // No prev frame
animatedTranslation = joint.TranslationTrack()[m_pCurrentAnimation->m_nStartFrame].translation;
} else if (frame == m_pCurrentAnimation->m_nEndFrame) { // No "this" frame
animatedTranslation = joint.TranslationTrack()[frame - 1].translation;
} else { // Do the actual interpolation
TranslationFrame& curFrame = joint.TranslationTrack()[frame];
TranslationFrame& prevFrame = joint.TranslationTrack()[frame - 1];
float timeDelta = curFrame.time - prevFrame.time;
float interpValue = (float)((m_nPlayback - prevFrame.time) / timeDelta);
animatedTranslation = Lerp(prevFrame.translation, curFrame.translation, interpValue);
}
// Find the rotation frame
frame = 0;
while (frame < m_pCurrentAnimation->m_nEndFrame &&
joint.RotationTrack()[frame].time < m_nPlayback) ++frame;
if (frame > m_pCurrentAnimation->m_nEndFrame) frame = m_pCurrentAnimation->m_nEndFrame;
// Interpolate rotation
if (frame == m_pCurrentAnimation->m_nStartFrame) { // No prev frame
animatedRotation = joint.RotationTrack()[m_pCurrentAnimation->m_nStartFrame].rotation;
} else if (frame == m_pCurrentAnimation->m_nEndFrame) { // No "this" frame
animatedRotation = joint.RotationTrack()[frame - 1].rotation;
} else { // Do actual interpolation
RotationFrame& curFrame = joint.RotationTrack()[frame];
RotationFrame& prevFrame = joint.RotationTrack()[frame - 1];
float timeDelta = curFrame.time - prevFrame.time;
float interpValue = (float)((m_nPlayback - prevFrame.time) / timeDelta);
animatedRotation = Slerp(prevFrame.rotation, curFrame.rotation, interpValue);
}
// Animate the bone in local space
Matrix animationTransform = BuildMatrix(animatedRotation, animatedTranslation);
localTransform = animationTransform * localTransform;
if (joint.Parent() == -1) {
joint.Working() = localTransform;
} else {
joint.Working() = localTransform * m_vSkeleton[joint.Parent()].Working();
}
}
}
However, rendering at this point the skeleton looks way wrong. I think the rotation / translation tracks are not working the way i think they are. Maybe they are the absolute world position, or something like that? I'm having a super hard time finding any information on the topic. Does anyone have any experience with this?