我正尝试在OpenGL中使用Assimp作为我的模型导入库来制作骨骼动画。
对于骨骼的offsetMatrix
变量,我到底需要什么?我需要把它乘以什么?
让我们以这段代码为例,我在工作的一个游戏中用它来制作角色的动画。我也使用了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]);
}
}
从本质上讲,GlobalTransform
(如教程"使用Assimp的骨骼动画"中所述),或者正确地说,根节点scene->mRootNode->mTransformation
的变换是从局部空间到全局空间的变换。举个例子,当在三维建模器(例如,让我们选择Blender)中创建网格或加载角色时,它通常位于(默认情况下)笛卡尔平面的原点,并且其旋转设置为单位四元数。
但是,您可以将网格/角色从原点(0,0,0)
平移/旋转到其他位置,并在单个场景中甚至具有多个不同位置的网格。加载它们时,尤其是在执行骨骼动画时,必须将它们平移回局部空间(即,平移回原点0,0,0
),这就是为什么必须将所有内容乘以InverseGlobal
(这将使网格返回到局部空间)的原因。
之后,您需要将其乘以节点变换,该变换是parentTransform
(树中一级以上的变换,这是整体变换)、transform
(以前的assimp_node->mTransformation
,它只是骨骼相对于节点父对象的变换)和您要应用的局部变换(任何T*R)的乘积:正向运动学,反向运动学插值或关键帧插值。
最后是boneOffset(ai_mesh->mBones[i]->mOffsetMatrix
),它在绑定姿势下从网格空间转换到骨骼空间,如文档中所述。
如果你想查看我的Skeleton类的整个代码,这里有一个指向GitHub的链接。
希望能有所帮助。
偏移矩阵定义了在网格空间中变换顶点的变换(平移、缩放、旋转),并将其转换为"骨骼"空间。例如,考虑以下顶点和具有以下特性的骨骼;
Vertex Position<0, 1, 2>
Bone Position<10, 2, 4>
Bone Rotation<0,0,0,1> // Note - no rotation
Bone Scale<1, 1, 1>
在这种情况下,如果我们将顶点乘以偏移矩阵,我们将得到<-10,-1,2>。
我们如何使用它?关于如何使用这个矩阵,您有两个选项,这取决于我们如何将顶点数据存储在顶点缓冲区中。选项包括:;
1) 将网格顶点存储在网格空间中2) 将网格顶点存储在骨骼空间中
在#1的情况下,我们将获取offsetMatrix,并在构建顶点缓冲区时将其应用于受骨骼影响的顶点。然后,当我们为网格设置动画时,我们稍后会为该骨骼应用动画矩阵。
在#2的情况下,当转换存储在顶点缓冲区中的顶点时,我们将使用offsetMatrix与该骨骼的动画矩阵相结合。所以它可能是这样的(注意:您可能需要在这里切换矩阵连接);
anim_vertex = (offset_matrix * anim_matrix) * mesh_vertex
这有帮助吗?
正如我已经假设的,mOffsetMatrix
是反绑定姿态矩阵。本教程介绍了线性混合蒙皮所需的正确变换:
首先需要评估动画状态。这将为每个骨骼提供从动画骨骼空间到世界空间的系统变换(教程中的GlobalTransformation
)。mOffsetMatrix
是从世界空间到绑定姿势骨骼空间的系统变换。因此,蒙皮操作如下(假设特定顶点受单个骨骼的影响):使用mOffsetMatrix
变换顶点到骨骼空间。现在假设一个动画骨骼,并将中间结果从动画骨骼空间变换回世界空间。因此:
boneMatrix[i] = animationMatrix[i] * mOffsetMatrix[i]
如果顶点受到多个骨骼的影响,LBS只需对结果取平均值。这就是重量发挥作用的地方。蒙皮通常在顶点着色器中实现:
vec4 result = vec4(0);
for each influencing bone i
result += weight[i] * boneMatrix[i] * vertexPos;
通常,影响骨骼的最大数量是固定的,您可以展开for
循环。
本教程为boneMatrix
使用了一个附加的m_GlobalInverseTransform
。然而,我不知道他们为什么这么做。基本上,这会取消整个场景的整体变换。它可能用于使模型在视图中居中。