【问题标题】:Problems rotating objects using eulers - quaternions使用欧拉旋转物体的问题 - 四元数
【发布时间】:2018-08-25 15:30:09
【问题描述】:

我在引擎中旋转游戏对象时遇到问题。我正在尝试以两种方式旋转。 我正在使用MathGeoLib 来计算引擎中的数学。

第一种方式:绕轴正确旋转,但如果我想向后旋转,如果我不按照相反的顺序进行旋转,则旋转无法正常工作。

例如:

X 轴旋转 50 度,Y 轴旋转 30 度 -> Y 轴旋转 -50 度,X 轴旋转 -30 度。有效。

X 轴旋转 50 度,Y 轴旋转 30 度 -> X 轴旋转 -50 度,Y 轴旋转 -30 度。没有。

代码:

void ComponentTransform::SetRotation(float3 euler_rotation)
{
    float3 diff = euler_rotation - editor_rotation;
    editor_rotation = euler_rotation;

    math::Quat mod = math::Quat::FromEulerXYZ(diff.x * DEGTORAD, diff.y * DEGTORAD, diff.z * DEGTORAD);

    quat_rotation = quat_rotation * mod;
    UpdateMatrix(); 
}

第二种方式:开始围绕轴旋转良好,但在旋转了几次后,它会停止围绕轴正确旋转,但是如果我不管旋转顺序如何都将它旋转回来,它会起作用,不像第一种方式。

代码:

void ComponentTransform::SetRotation(float3 euler_rotation)
{
    editor_rotation = euler_rotation;

    quat_rotation = math::Quat::FromEulerXYZ(euler_rotation.x * DEGTORAD, euler_rotation.y * DEGTORAD, euler_rotation.z * DEGTORAD);

    UpdateMatrix(); 
}

其余代码:

#define DEGTORAD 0.0174532925199432957f

void ComponentTransform::UpdateMatrix()
{
    if (!this->GetGameObject()->IsParent())
    {
        //Get parent transform component
        ComponentTransform* parent_transform = (ComponentTransform*)this->GetGameObject()->GetParent()->GetComponent(Component::CompTransform);

        //Create matrix from position, rotation(quaternion) and scale
        transform_matrix = math::float4x4::FromTRS(position, quat_rotation, scale);

        //Multiply the object transform by parent transform
        transform_matrix = parent_transform->transform_matrix * transform_matrix;

        //If object have childs, call this function in childs objects
        for (std::list<GameObject*>::iterator it = this->GetGameObject()->childs.begin(); it != this->GetGameObject()->childs.end(); it++)
        {
            ComponentTransform* child_transform = (ComponentTransform*)(*it)->GetComponent(Component::CompTransform);
            child_transform->UpdateMatrix();
        }
    }
    else
    {
        //Create matrix from position, rotation(quaternion) and scale
        transform_matrix = math::float4x4::FromTRS(position, quat_rotation, scale);

        //If object have childs, call this function in childs objects
        for (std::list<GameObject*>::iterator it = this->GetGameObject()->childs.begin(); it != this->GetGameObject()->childs.end(); it++)
        {
            ComponentTransform* child_transform = (ComponentTransform*)(*it)->GetComponent(Component::CompTransform);
            child_transform->UpdateMatrix();
        }
    }
}

MathGeoLib:
Quat MUST_USE_RESULT Quat::FromEulerXYZ(float x, float y, float z) { return (Quat::RotateX(x) * Quat::RotateY(y) * Quat::RotateZ(z)).Normalized(); }

Quat MUST_USE_RESULT Quat::RotateX(float angle)
{
    return Quat(float3(1,0,0), angle);
}

Quat MUST_USE_RESULT Quat::RotateY(float angle)
{
    return Quat(float3(0,1,0), angle);
}

Quat MUST_USE_RESULT Quat::RotateZ(float angle)
{
   return Quat(float3(0,0,1), angle);
}

Quat(const float3 &rotationAxis, float rotationAngleRadians) { SetFromAxisAngle(rotationAxis, rotationAngleRadians); }

void Quat::SetFromAxisAngle(const float3 &axis, float angle)
{
    assume1(axis.IsNormalized(), axis);
    assume1(MATH_NS::IsFinite(angle), angle);
    float sinz, cosz;
    SinCos(angle*0.5f, sinz, cosz);
    x = axis.x * sinz;
    y = axis.y * sinz;
    z = axis.z * sinz;
    w = cosz;
}

有什么帮助吗?

谢谢。

【问题讨论】:

  • 这就是轮换的工作方式。你有什么问题?
  • 那么这两种方法中哪一种是正确的?因为你可以看到结果不相等
  • 在什么意义上正确?
  • 我的意思是。第一个在一些旋转后没有正确地围绕轴旋转,但我可以不管顺序旋转,第二个总是围绕轴旋转,但如果我想旋转回来,需要遵循一个顺序。似乎两者都是正确的,但都有问题。我应该使用哪一个?

标签: c++ math rotation quaternions euler-angles


【解决方案1】:

使用欧拉角和/或四元数会增加一些限制,因为它会产生奇点,如果处理不当,就会产生愚蠢的结果。可悲的是,几乎所有新的 3D 游戏都错误地使用了它。您可以通过以下众所周知的事情来检测它们:

  • 有时您的视图会出现不应该存在的非常不同的角度
  • 对象无法再向某个方向旋转
  • 对象开始围绕不同的轴旋转,而不是应有的情况
  • 视图围绕奇点跳转
  • 视图一直在旋转或翻转,直到您再次移动/转动(不是由光学鼠标错误引起的)

我使用的是累积变换矩阵:

阅读全部内容(尤其是局部和全局旋转之间的差异),然后在最后 3 个链接中,您会看到如何执行此操作的 C++ 示例(还请阅读所有 3 个内容,尤其是保留精度……)。

这个想法是让矩阵代表您的对象坐标系。当你旋转(通过鼠标、键盘、NAV、AI……)时,你会旋转矩阵(增量)。运动也是如此。这样,它们就没有限制或奇点。但这种方法也有其问题:

  • 随着时间的推移失去准确性(阅读保留准确性示例以处理此问题)
  • 不知道欧拉角(但是可以从矩阵中计算出角)

两者都比较容易解决。

现在,当您围绕局部轴旋转时,您需要考虑到每次围绕某个轴旋转时都会更改另外两个轴。因此,如果您想恢复到原始状态,则需要颠倒旋转顺序,因为:

rotate around x by 30deg
rotate around y by 40deg 

不等于:

rotate around y by 40deg 
rotate around x by 30deg

如果你想返回累积矩阵,你可以迭代地驾驶你的船直到它面向所需的方向,或者记住原始矩阵并计算一次需要完成一个轴的旋转。或者将矩阵差异转换为四元数并迭代该单次旋转...

【讨论】:

    猜你喜欢
    • 2012-08-16
    • 1970-01-01
    • 2013-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多