【发布时间】:2013-07-31 07:33:11
【问题描述】:
(可能重复:Rotating a 4x4 Matrix Causes Scaling Over Time)
大家好。我一直在尝试让模型进入绑定姿势以外的姿势。目前我正在使用动画文件中的第一帧并尝试将模型设置为初始姿势。
我相信我的数学方程式现在是正确的。改造单根骨头效果很好(孩子们应该跟着做)。然而,通过复合变换(其中一个孩子被变换,其父母也被变换),非常年幼的孩子似乎高度畸形。 (比如模型的手指当手腕、肘部和肩部骨骼也进行了变形。)
int targetFrame = CONST_TEST_FRAME_NUMBER;
// root bone
PMXBone *b = pmxInfo.bones[0];
BoneFrame *bf = getBoneFrame(targetFrame, b->name);
b->absoluteForm = b->relativeForm;
Bone[0] = b->absoluteForm * invBindPose[0];
// other bones
for (size_t i = 1; i < pmxInfo.bone_continuing_datasets; i++)
{
b = pmxInfo.bones[i];
PMXBone *parent = pmxInfo.bones[b->parentBoneIndex];
bf = getBoneFrame(targetFrame, b->name);
if(bf!=NULL)
{
b->finalRotation = bf->quaternion * parent->finalRotation;
glm::vec4 homoPosition=glm::vec4(b->position + bf->translation, 1.0); //position in homogeneous coordinates
glm::vec4 localPosition=glm::rotate(parent->finalRotation,homoPosition);
b->relativeForm[3][0]=localPosition[0];
b->relativeForm[3][1]=localPosition[1];
b->relativeForm[3][2]=localPosition[2];
b->relativeForm[3][3]=localPosition[3];
b->absoluteForm = (b->relativeForm * glm::toMat4(bf->quaternion)) * parent->absoluteForm;
Bone[i] = b->absoluteForm * invBindPose[i];
}
else
{
b->finalRotation = parent->finalRotation;
glm::vec4 homoPosition=glm::vec4(b->position,1.0); //position in homogeneous coordinates
glm::vec4 localPosition=glm::rotate(b->finalRotation,homoPosition);
b->relativeForm[3][0]=localPosition[0];
b->relativeForm[3][1]=localPosition[1];
b->relativeForm[3][2]=localPosition[2];
b->relativeForm[3][3]=localPosition[3];
b->absoluteForm = b->relativeForm * parent->absoluteForm;
Bone[i] = b->absoluteForm * invBindPose[i];
}
}
}
为了帮助澄清代码:
- b->position 是一个 glm::vec3,包含 Bone 在其 局部/骨骼空间,相对于父骨骼。
- bf 包含 1 中 1 骨骼的变换信息 框架。换句话说,您必须获得多个 Bone Frames 才能获得 1 帧中所有骨骼的变换信息。
- bf->quaternion 是一个 4-float glm::quat 包含旋转 动画中骨骼框架的信息。换句话说,它 包含有关必须如何旋转骨骼以获得模型的信息 从其绑定姿势到当前姿势。
- 类似地,bf->translation,一个 glm::vec3,包含平移 骨骼框架的信息。因为人的骨骼是僵硬的, bf->translation 的大部分值都设置为 (0,0,0)。
- relativeForm 和 absoluteForm 指的是局部和全局矩阵 分别是转换后的骨骼。在此代码之前 sn-p 是 运行,relativeForm 只是将 b->position 转换为矩阵,并且 absoluteForm 是骨骼的绑定姿势矩阵。
这是使用此代码显示模型的图像: http://imgur.com/tbur5Lf
另外,这是使用此代码转换的模型中单个骨骼的图像(使用键盘控制的四元数代替 bf):http://t.co/wf38ibGoyc
我花了整整两个星期才走到这一步,所以我非常感谢任何帮助。谢谢,如果我需要提供任何其他信息,请告诉我。
编辑: 我正在上传一个视频,展示我的程序在单骨转换方面的成功,以及复合转换的问题。上传完成后会在:http://youtu.be/8Cv3jMYcz64
【问题讨论】:
-
我不太确定你的矩阵是如何设置的,但你不应该在左边乘以
parent->absoluteForm吗?所以b->absoluteForm = parent->absoluteForm * (glm::toMat4(bf->quaternion * b->relativeForm * )) ;而不是b->absoluteForm = (b->relativeForm * glm::toMat4(bf->quaternion)) * parent->absoluteForm;和其他诸如“先本地旋转然后本地翻译”之类的东西,而不是相反?换句话说,您确定矩阵乘法中操作数的顺序是正确的吗? -
在 OpenGL 中,应用矩阵的顺序是从右到左。因此,以从左到右的典型数学顺序(例如,'Bone[i]=invBindPose * absoluteForm')编写函数会导致混乱。同样,此代码适用于任何单独的骨骼旋转;仅当您尝试组合多个骨骼变换时才会失败,并且变换后的骨骼彼此之间存在层次关系。
-
嗯,是的。顶点通常在右侧相乘(不是必须以这种方式完成,这是一个固定功能的管道构造)。但这意味着您将在最右侧进行局部旋转,然后进行局部平移,然后进行其余的全局变换。
标签: c++ opengl 3d transformation