gpu皮肤的矩阵计算

时间:2015-04-10 15:28:34

标签: c++ opengl matrix graphics assimp

我尝试使用 Assimp 作为我的模型导入库,在 OpenGL 中进行骨骼动画。

我到底需要什么? offsetMatrix变量?我需要将它乘以?

3 个答案:

答案 0 :(得分:6)

让我们以这个代码为例,我曾经在我工作的游戏中为角色制作动画。我也使用了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]);
    }
}

基本上是教程Skeletal Animation with Assimp中引用的GlobalTransform或正确地根节点scene->mRootNode->mTransformation的转换是从本地空间到全局空间的转换。举个例子,当你在3D建模器中(让我们选择Blender)你创建你的网格或加载你的角色时,它通常被定位(默认情况下)在笛卡尔平面的原点并且它的旋转被设置为身份四元数。

但是,您可以将网格/角色从原点(0,0,0)转换/旋转到其他位置,并在单个场景中具有不同位置的多个网格。加载它们时,尤其是在进行骨架动画时,必须将它们转换回局部空间(即返回原点0,0,0),这就是为什么必须将所有内容乘以{{1 (将网格带回到本地空间)。

之后你需要将它乘以节点变换,这是InverseGlobal的乘法(树中的变换一级,这是整体变换)parentTransform(以前的transform只是骨骼相对于节点父节点的变换)和你想要应用的局部变换(任何T * R):前向运动学,反向运动学或关键帧插值。

最终有一个boneOffset(assimp_node->mTransformation)在绑定姿势中从网格空间转换到骨骼空间,如文档中所述。

如果你想查看我的Skeleton类的整个代码,这里有GitHub的链接。

希望它有所帮助。

答案 1 :(得分:1)

偏移矩阵定义了在网格空间中转换顶点的变换(平移,缩放,旋转),并将其转换为“骨骼”空间。作为示例,请考虑以下顶点和具有以下属性的骨骼;

Vertex Position<0, 1, 2>

Bone Position<10, 2, 4>
Bone Rotation<0,0,0,1>  // Note - no rotation
Bone Scale<1, 1, 1>

如果我们在这种情况下将顶点乘以偏移矩阵,我们将得到顶点位置&lt; -10,-1,2&gt;。

我们如何使用它?关于如何使用此矩阵,您有两种选择,这取决于我们如何将顶点数据存储在顶点缓冲区中。选项是;

1)将网格顶点存储在网格空间中 2)将网格顶点存储在骨骼空间

在#1的情况下,我们将获取offsetMatrix,并在构建顶点缓冲区时将其应用于受骨骼影响的顶点。然后,当我们为网格设置动画时,我们稍后为该骨骼应用动画矩阵。

在#2的情况下,我们将在转换存储在顶点缓冲区中的顶点时将offsetMatrix与该骨骼的动画矩阵结合使用。所以它会是这样的(注意:你可能必须在这里切换矩阵连接);

anim_vertex = (offset_matrix * anim_matrix) * mesh_vertex

这有帮助吗?

答案 2 :(得分:1)

正如我已经假设的那样,mOffsetMatrix是反向绑定姿势矩阵。 This tutorial说明了线性混合蒙皮所需的正确变换:

首先需要评估动画状态。这将为您提供从动画骨骼空间到每个骨骼的世界空间的系统转换(教程中的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循环。

本教程为m_GlobalInverseTransform使用了额外的boneMatrix。但是,我不知道为什么他们这样做。基本上,这解除了整个场景的整体转变。可能它用于在视图中居中模型。