我从 learnopengl.com(链接)完成了骨骼动画教程。
当我播放另一个动画时,它会以非常不和谐的方式“跳转”到该动画的第一帧,而不是平滑过渡到它。
这是我到目前为止写的:
// Recursive function that sets interpolated bone matrices in the 'm_FinalBoneMatrices' vector
void CalculateBlendedBoneTransform(
Animation* pAnimationBase, const AssimpNodeData* node,
Animation* pAnimationLayer, const AssimpNodeData* nodeLayered,
const float currentTimeBase, const float currentTimeLayered,
const glm::mat4& parentTransform,
const float blendFactor)
{
const std::string& nodeName = node->name;
glm::mat4 nodeTransform = node->transformation;
Bone* pBone = pAnimationBase->FindBone(nodeName);
if (pBone)
{
pBone->Update(currentTimeBase);
nodeTransform = pBone->GetLocalTransform();
}
glm::mat4 layeredNodeTransform = nodeLayered->transformation;
pBone = pAnimationLayer->FindBone(nodeName);
if (pBone)
{
pBone->Update(currentTimeLayered);
layeredNodeTransform = pBone->GetLocalTransform();
}
// Blend two matrices
const glm::quat rot0 = glm::quat_cast(nodeTransform);
const glm::quat rot1 = glm::quat_cast(layeredNodeTransform);
const glm::quat finalRot = glm::slerp(rot0, rot1, blendFactor);
glm::mat4 blendedMat = glm::mat4_cast(finalRot);
blendedMat[3] = (1.0f - blendFactor) * nodeTransform[3] + layeredNodeTransform[3] * blendFactor;
const glm::mat4 globalTransformation = parentTransform * blendedMat;
const auto& boneInfoMap = pAnimationBase->GetBoneInfoMap();
if (boneInfoMap.find(nodeName) != boneInfoMap.end())
{
const int index = boneInfoMap.at(nodeName).id;
const glm::mat4& offset = boneInfoMap.at(nodeName).offset;
const glm::mat4& offsetLayerMat = pAnimationLayer->GetBoneInfoMap().at(nodeName).offset;
// Blend two matrices... again
const glm::quat rot0 = glm::quat_cast(offset);
const glm::quat rot1 = glm::quat_cast(offsetLayerMat);
const glm::quat finalRot = glm::slerp(rot0, rot1, blendFactor);
glm::mat4 blendedMat = glm::mat4_cast(finalRot);
blendedMat[3] = (1.0f - blendFactor) * offset[3] + offsetLayerMat[3] * blendFactor;
m_FinalBoneMatrices[index] = globalTransformation * blendedMat;
}
for (size_t i = 0; i < node->children.size(); ++i)
CalculateBlendedBoneTransform(pAnimationBase, &node->children[i], pAnimationLayer, &nodeLayered->children[i], currentTimeBase, currentTimeLayered, globalTransformation, blendFactor);
}
下一个函数每帧运行:
pAnimator->BlendTwoAnimations(pVampireWalkAnim, pVampireRunAnim, animationBlendFactor, deltaTime);
其中包含:
void BlendTwoAnimations(Animation* pBaseAnimation, Animation* pLayeredAnimation, float blendFactor, float dt)
{
static float currentTimeBase = 0.0f;
currentTimeBase += pBaseAnimation->GetTicksPerSecond() * dt;
currentTimeBase = fmod(currentTimeBase, pBaseAnimation->GetDuration());
static float currentTimeLayered = 0.0f;
currentTimeLayered += pLayeredAnimation->GetTicksPerSecond() * dt;
currentTimeLayered = fmod(currentTimeLayered, pLayeredAnimation->GetDuration());
CalculateBlendedBoneTransform(pBaseAnimation, &pBaseAnimation->GetRootNode(), pLayeredAnimation, &pLayeredAnimation->GetRootNode(), currentTimeBase, currentTimeLayered, glm::mat4(1.0f), blendFactor);
}
这就是它的样子:https ://imgur.com/a/pcxDhut
当“混合因子”为 0.0 和 1.0 时,奔跑和行走动画看起来非常好,但介于两者之间的任何东西都有一种不连续性......有整毫秒看起来他在同时抬起双脚奔跑. 我怎样才能让它们正确混合?我期待看到步行和跑步之间的平稳过渡,就像在大多数第三人称游戏中逐渐移动控制器上的模拟摇杆时一样。
动画来自 mixamo.com(与模型相同),采用 FBX 格式,使用 Assimp 5.1.0rc1 加载。我在虚幻引擎 4 中使用混合空间对它们进行了测试,它们之间的“交叉淡入淡出”看起来很棒。所以不是动画文件本身,它们是正确的。