如何使用 assimp 在 C++ 中旋转蒙皮模型的骨骼?
Posted
技术标签:
【中文标题】如何使用 assimp 在 C++ 中旋转蒙皮模型的骨骼?【英文标题】:How to rotate a skinned model's bones in c++ using assimp? 【发布时间】:2015-05-24 21:53:14 【问题描述】:我可以使用 assimp 通过在关键帧之间进行插值来加载蒙皮模型的动画。现在,我一直在尝试从用户定义的变换矩阵中定向或定位骨骼,而不仅仅是从动画文件中加载它。例如,将手臂旋转一定角度,该角度将由用户指定。我将模型加载为绑定姿势:
void recursion(aiNode* gNode)
std::string gNodeName(gNode->mName.data);
if(boneMapping.find(gNodeName) != boneMapping.end())
//if node corresponds to a bone,
Matrix4f boneMatrix = IdentityMatrix;
aiNode* tempNode = gNode;
//find combined transform of a bone
while(tempNode != NULL)
Matrix4f NodeMatrix(tempNode->mTransformation);
boneMatrix = NodeMatrix * boneMatrix;
tempNode = tempNode->mParent;
pBoneData[boneId].FinalTransform = GlobalInverseTransform * boneMatrix * pBoneData[boneId].OffsetMatrix;
for(int i = 0; i < gNode->mNumChildren; i++)
//repeat this process for child nodes
recursion(gNode->mChildren[i]);
为了使用变换矩阵定位模型的其中一个网格,我尝试搜索与网格的父骨骼对应的骨骼名称,然后将其节点矩阵替换为所需的矩阵。然而,这根本不起作用,因为它在不同的网格上使骨骼变形。
右侧的模型处于 T 姿势,我打算通过将颈部骨骼旋转 45 度角来修改它,但它保持不变,并且腿部变形,如左侧模型所示。因此,任何指向现有文章或答案的链接都可能非常有用。
【问题讨论】:
'boneId' 是骨骼的 boneIndex,如果有人想知道的话 运气好吗?如果有效,请将问题标记为已回答。 【参考方案1】:我认为这一行中乘法矩阵的顺序是错误的:
boneMatrix = NodeMatrix * boneMatrix;
应该是:
boneMatrix = boneMatrix * NodeMatrix;
在 OpenGL 中,乘法的顺序是相反的。
虽然我觉得这种方法不合适:
while(tempNode != NULL)
Matrix4f NodeMatrix(tempNode->mTransformation);
boneMatrix = NodeMatrix * boneMatrix;
tempNode = tempNode->mParent;
您将局部变换乘以骨骼空间中的骨骼矩阵,而不是世界空间中的骨骼矩阵。这就是你的角色出现变形的原因。
我使用 assimp 和 OpenGL 为我的动画项目解决了这个问题。我使用了一种稍微不同的方法,将所有 assimp 信息保存到我自己的数据结构中。 (骨骼和骨头)。从你的代码和你使用的数据结构来看,我猜你的代码是基于这个tutorial。
这是我使用的代码,我相信你可以用它来与你的实现进行比较:
glm::mat4 getParentTransform()
if (this->parent)
return parent->globalTransform;
else
return glm::mat4(1.0f);
void updateSkeleton(Bone* bone = NULL)
bone->globalTransform = 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->globalTransform //defined above
* bone->boneOffset; //which is ai_mesh->mBones[i]->mOffsetMatrix
for (int i = 0; i < bone->children.size(); i++)
updateSkeleton (&bone->children[i]);
编辑:
对于从 Assimp 到 glm 的矩阵转换,我使用了这个函数:
inline glm::mat4 aiMatrix4x4ToGlm(const aiMatrix4x4* from)
glm::mat4 to;
to[0][0] = (GLfloat)from->a1; to[0][1] = (GLfloat)from->b1; to[0][2] = (GLfloat)from->c1; to[0][3] = (GLfloat)from->d1;
to[1][0] = (GLfloat)from->a2; to[1][1] = (GLfloat)from->b2; to[1][2] = (GLfloat)from->c2; to[1][3] = (GLfloat)from->d2;
to[2][0] = (GLfloat)from->a3; to[2][1] = (GLfloat)from->b3; to[2][2] = (GLfloat)from->c3; to[2][3] = (GLfloat)from->d3;
to[3][0] = (GLfloat)from->a4; to[3][1] = (GLfloat)from->b4; to[3][2] = (GLfloat)from->c4; to[3][3] = (GLfloat)from->d4;
return to;
希望对你有帮助。
【讨论】:
感谢您的回复。是的,我遵循了您上面提到的教程,它使用了与您类似的方法。但是 assimp 矩阵是行主矩阵,而 opengl 使用列主矩阵。您是否在两者之间进行了转换以生成相同类型的所有矩阵? 是的,我做到了,我将编辑我的答案,添加来自 assimp 的转换矩阵,以便您进行比较 只是为了确定,您已将 node->mTranformation 更改为 glm::mat4 对吗? 是的,为了使用 glm,我转换了 assimp 矩阵。尽管您使用相同的方法将矩阵转换为 Matrix4f 另外,它不会将骨骼从当前的“骨骼”转换到层次结构的底部。例如,如果“骨骼”位于根骨骼附近,它不会转换层次结构中位于其下方的所有骨骼吗?以上是关于如何使用 assimp 在 C++ 中旋转蒙皮模型的骨骼?的主要内容,如果未能解决你的问题,请参考以下文章
一步步学OpenGL(38) -《Assimp库实现骨骼蒙皮动画》