【问题标题】:How are quaternion rotations supposed to behave?四元数旋转应该如何表现?
【发布时间】:2013-04-21 10:01:03
【问题描述】:

在过去的几天里,我一直在慢慢弄清楚四元数,但遇到了一个意想不到的问题。在终于让代码工作后,我发现我传递给我的旋转函数的数字没有产生与度数或弧度相关的旋转。

这是我的旋转功能

void solveRotation(Quaternion* q, float pitch, bool localx, float yaw, bool localy, float roll, bool localz)
{
    Quaternion temp;
    if(yaw !=0.f)
    { 
        if(localy==true)
        {
            //quaternionMultBA(q, yaw, 0.f, 1.f, 0.f);
            temp.w = q->w*yaw - q->y;
            temp.x = q->x*yaw + q->z;
            temp.y = q->y*yaw + q->w;
            temp.z = q->z*yaw - q->x;
        }
        else
        {
            //quaternionMultAB(q, yaw, 0.f, 1.f, 0.f);
            temp.w = q->w*yaw - q->y;
            temp.x = q->x*yaw - q->z;
            temp.y = q->w + q->y*yaw;
            temp.z = q->z*yaw + q->x;
        }
        q->w=temp.w;
        q->x=temp.x;
        q->y=temp.y;
        q->z=temp.z;
    }
    if(pitch != 0.f)
    {
        if(localx==true)
        {

            //quaternionMultBA(q, pitch, 1.f, 0.f, 0.f);
            temp.w = q->w*pitch - q->x;
            temp.x = q->x*pitch + q->w;
            temp.y = q->y*pitch - q->z;
            temp.z = q->z*pitch + q->y;
        }
        else
        {
            //quaternionMultAB(q, pitch, 1.f, 0.f, 0.f);
            temp.w = q->w*pitch - q->x;
            temp.x = q->w + q->x*pitch;
            temp.y = q->y*pitch + q->z;
            temp.z = q->z*pitch - q->y;
        }
        q->w=temp.w;
        q->x=temp.x;
        q->y=temp.y;
        q->z=temp.z;
    }
    if(roll != 0.f)
    {
        if(localz==true)
        {

            //quaternionMultBA(q, roll, 0.f, 0.f, 1.f);
            temp.w = q->w*roll - q->z;
            temp.x = q->x*roll - q->y;
            temp.y = q->y*roll + q->x;
            temp.z = q->z*roll + q->w;
        }
        else
        {
            //quaternionMultAB(q, roll, 0.f, 0.f, 1.f);
            temp.w = q->w*roll - q->z;
            temp.x = q->x*roll + q->y;
            temp.y = q->y*roll - q->x;
            temp.z = q->z*roll + q->w;
        }
        q->w=temp.w;
        q->x=temp.x;
        q->y=temp.y;
        q->z=temp.z;
    }

    normalize(q);
}

上面的代码会根据循环迭代期间按下的键来传递一个值。起初我将值设置为 0.1 并预计旋转缓慢。 相反,我看到每次迭代都有一个大转弯,这在 60 fps 时看起来非常奇怪。当我将传递的值更改为 1.0 时,我正在处理的立方体似乎做了完美的 90 度转弯(颜色移动但几何形状没有)

当我将传递量增加到 5 以上时,我开始看到我所期望的平滑旋转,并注意到随着我增加值,它变慢了。我想了这么多,但它真的对我没有帮助,因为我不能用它来旋转特定的数量。我读过的任何四元数教程都没有提到这类问题,因为它们都提到了弧度。我不确定我是否犯了错误,或者我是否错过了额外的步骤,或者我是否搞砸了整个该死的事情。

提前感谢您的帮助, 也可能反应慢

【问题讨论】:

  • 我不明白这段代码的用途。如果俯仰、滚动和偏航应该是欧拉角,我希望看到一些 sin 和 cos 调用来生成相应的四元数。
  • @Jim Lewis,所以这可能是问题所在。我写这篇文章的假设是为了让一个四元组旋转欧拉角,你可以将它与另一个四元组相乘,这个四元组的角度为 w,轴为 xyz。因此,在查看了以正确方式将 Euler 转换为 quat 的长期缓慢方法之后,我想知道您是否可以推荐另一种方式。毕竟四元数不应该很简单吗?

标签: rotation quaternions


【解决方案1】:

所以我进行了更多搜索并修改了我的函数以包含我缺少的 sin 和 cos 函数。由于我在 GPwiki 上看到的代码示例,我认为我可以在没有触发的情况下进行旋转。不管怎样,这个功能现在已经修复了,如果有人想使用它——即使那里可能有更好的——这里是:

void solveRotation(Quaternion* q, float pitch, bool localx, float yaw, bool localy, float roll, bool localz)
{
    Quaternion temp;
    float s;
    float c;
    if(yaw !=0.f)
    { 
        yaw*=0.5f;
        s = sin(yaw);
        c = cos(yaw);
        if(localy==true)
        {
            temp.w = q->w*c - q->y*s;
            temp.x = q->x*c + q->z*s;
            temp.y = q->y*c + q->w*s;
            temp.z = q->z*c - q->x*s;
        }
        else
        {
            temp.w = q->w*c - q->y*s;
            temp.x = q->x*c - q->z*s;
            temp.y = q->y*c + q->w*s;
            temp.z = q->z*c + q->x*s;
        }
        q->w=temp.w;
        q->x=temp.x;
        q->y=temp.y;
        q->z=temp.z;
    }
    if(pitch != 0.f)
    {
        pitch*=0.5f;
        s = sin(pitch);
        c = cos(pitch);
        if(localx==true)
        {
            temp.w = q->w*c - q->x*s;
            temp.x = q->x*c + q->w*s;
            temp.y = q->y*c - q->z*s;
            temp.z = q->z*c + q->y*s;
        }
        else
        {
            temp.w = q->w*c - q->x*s;
            temp.x = q->x*c + q->w*s;
            temp.y = q->y*c + q->z*s;
            temp.z = q->z*c - q->y*s;
        }
        q->w=temp.w;
        q->x=temp.x;
        q->y=temp.y;
        q->z=temp.z;
    }
    if(roll != 0.f)
    {
        roll*=0.5f;
        s = sin(roll);
        c = cos(roll);
        if(localz==true)
        {
            temp.w = q->w*c - q->z*s;
            temp.x = q->x*c - q->y*s;
            temp.y = q->y*c + q->x*s;
            temp.z = q->z*c + q->w*s;
        }
        else
        {
            temp.w = q->w*c - q->z*s;
            temp.x = q->x*c + q->y*s;
            temp.y = q->y*c - q->x*s;
            temp.z = q->z*c + q->w*s;
        }
        q->w=temp.w;
        q->x=temp.x;
        q->y=temp.y;
        q->z=temp.z;
    }

    normalize(q);
}

顺便感谢吉姆·刘易斯

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多