旋转中的小误差导致模型变形

时间:2013-07-30 23:21:42

标签: c++ opengl 3d transformation

(可能重复: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-&gt; position是一个glm :: vec3,其中包含Bone的位置 相对于父骨骼的局部/骨骼空间。
  • bf包含 1 1 骨骼的转换信息 帧。换句话说,您必须获得多个骨骼框架才能获得 所有 1 框架中骨骼的转化信息。
  • bf-&gt;四元数是一个包含旋转的4浮点glm :: quat 动画中骨骼框架的信息。换句话说,它 包含有关如何旋转骨骼以获取模型的信息 从其绑定姿势到当前姿势。
  • 类似地,bf->翻译,glm :: vec3,包含翻译 骨架的信息。因为人类骨骼是僵硬的, bf->翻译的大多数值都设置为(0,0,0)。
  • relativeForm和absoluteForm指的是Local和Global矩阵 分别是转化的骨骼。在此代码段之前 run,relativeForm只是b-&gt;位置转换为矩阵,和 absoluteForm是骨骼的Bind Pose矩阵。

以下是使用此代码显示模型的图像: http://imgur.com/tbur5Lf

作为额外的,这里是使用此代码转换的模型中单个骨骼的图像(而不是bf,使用了键盘控制的四元数):http://t.co/wf38ibGoyc

我花了两个星期才走到这一步,所以我非常感谢任何帮助。谢谢,如果我需要提供任何其他信息,请告诉我。

修改 我上传的视频演示了我的程序在单骨转换中的成功,以及复合转换的问题。完成上传后,它将位于:http://youtu.be/8Cv3jMYcz64

1 个答案:

答案 0 :(得分:0)

2ch为我节省了一天:

void setModelToKeyFrame(glm::mat4 Bone[], GLuint &shaderProgram, PMXInfo &pmxInfo, VMDInfo &vmdInfo)
{

    int targetFrame = CONST_TEST_FRAME_NUMBER;
    glm::mat4 aniMatrix;

    // root bone
    PMXBone   *b  = pmxInfo.bones[0];
    BoneFrame *bf = getBoneFrame(targetFrame, b->name);

    b->absoluteForm = b->relativeForm;
    if(bf!=NULL)
    {
        b->finalRotation = bf->quaternion;

        b->relativeForm = glm::translate( b->position ) * glm::toMat4(bf->quaternion);
        b->absoluteForm = glm::translate( bf->translation + b->position ) * glm::toMat4(bf->quaternion);
        Bone[i] = glm::translate( bf->translation + b->position ) * glm::toMat4(bf->quaternion) * glm::translate( -b->position );
    }
    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;

            b->relativeForm = glm::translate( bf->translation + b->position - parent->position ) * glm::toMat4(bf->quaternion);
            b->absoluteForm = parent->absoluteForm * glm::translate( bf->translation + b->position - parent->position ) * glm::toMat4(bf->quaternion);
            Bone[i] = parent->absoluteForm * glm::translate( bf->translation + b->position - parent->position ) * glm::toMat4(bf->quaternion) * glm::translate( -b->position );
        }
        else
        {
            b->finalRotation = parent->finalRotation;

            b->relativeForm = glm::translate( b->position - parent->position );
            b->absoluteForm = parent->absoluteForm * glm::translate( b->position - parent->position );
            Bone[i] = parent->absoluteForm * glm::translate( b->position - parent->position ) * glm::translate( -b->position );
        }

    }
}