让我们以这个代码为例,我曾经在我工作的游戏中为角色制作动画.我也使用了Assimp来加载骨骼信息,我自己读了Nico已经指出的OGL教程.
glm::mat4 getParentTransform()
{
if (this->parent)
return parent->nodeTransform;
else
return glm::mat4(1.0f);
}
void updateSkeleton(Bone* bone = NULL)
{
bone->nodeTransform = bone->getParentTransform() // This retrieve the transformation one level above in the tree
* bone->transform //bone->transform is the assimp matrix assimp_node->mTransformation
* bone->localTransform; //this is your T * R matrix
bone->finalTransform = inverseGlobal // which is scene->mRootNode->mTransformation from assimp
* bone->nodeTransform //defined above
* bone->boneOffset; //which is ai_mesh->mBones[i]->mOffsetMatrix
for (int i = 0; i < bone->children.size(); i++) {
updateSkeleton (&bone->children[i]);
}
}
Run Code Online (Sandbox Code Playgroud)
基本上GlobalTransform
是在教程中使用Assimp的Skeletal Animation中提到的,或者根节点scene->mRootNode->mTransformation
的转换是从本地空间到全局空间的转换.举个例子,当你在3D建模器中(让我们选择Blender)你创建你的网格或加载你的角色时,它通常被定位(默认情况下)在笛卡尔平面的原点并且它的旋转被设置为身份四元数.
但是,您可以将网格/角色从原点转换/旋转(0,0,0)
到其他位置,并在单个场景中具有不同位置的多个网格.加载它们时,尤其是在进行骨架动画时,必须将它们转换回局部空间(即返回原点0,0,0
),这就是为什么必须将所有内容乘以InverseGlobal
(将网格带回本地)的原因空间).
之后你需要将它乘以节点变换,节点变换是parentTransform
(树中的一个级别的变换,这是整体变换)的乘法transform
(以前assimp_node->mTransformation
只是骨骼相对于节点父级的变换))和你想要应用的局部变换(任何T*R):正向运动,反向运动或关键帧插值.
最终有一个boneOffset(ai_mesh->mBones[i]->mOffsetMatrix
)在绑定姿势中从网格空间转换到骨骼空间,如文档中所述.
如果你想查看我的Skeleton类的整个代码,这里有一个指向GitHub的链接.
希望能帮助到你.