首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >四元数旋转对y/z旋转很好,但是当我加x旋转时就会搞砸了。

四元数旋转对y/z旋转很好,但是当我加x旋转时就会搞砸了。
EN

Stack Overflow用户
提问于 2021-09-06 13:18:36
回答 2查看 445关注 0票数 1

因此,我最近一直在学习四元数,并决定自己实现。我试图使它简单,但我仍然找不出我的错误。x/y/z轴旋转本身工作得很好,y/z旋转功也很好,但是第二次我把x轴加到其他任何一个,我得到一个奇怪的拉伸输出。我将附上以下轮转的重要代码:(请注意,我对cpp非常陌生)。

下面是我对四元数的描述(据我理解,因为它们是单位四元数,所以不需要虚数):

代码语言:javascript
复制
struct Quaternion {
    float w, x, y, z;
};

四元数的乘法规则:

代码语言:javascript
复制
Quaternion operator* (Quaternion n, Quaternion p) {
    Quaternion o;

    // implements quaternion multiplication rules:
    o.w = n.w * p.w - n.x * p.x - n.y * p.y - n.z * p.z;
    o.x = n.w * p.x + n.x * p.w + n.y * p.z - n.z * p.y;
    o.y = n.w * p.y - n.x * p.z + n.y * p.w + n.z * p.x;
    o.z = n.w * p.z + n.x * p.y - n.y * p.x + n.z * p.w;

    return o;
}

生成旋转四元数,使整个旋转乘以:

代码语言:javascript
复制
Quaternion rotate(float w, float x, float y, float z) {
    Quaternion n;

    n.w = cosf(w/2);
    n.x = x * sinf(w/2);
    n.y = y * sinf(w/2);
    n.z = z * sinf(w/2); 

    return n;
}

最后,将四元数转换为x/y/z位置的矩阵计算:

代码语言:javascript
复制
inline vector<float> quaternion_matrix(Quaternion total, vector<float> vec) {
    float x = vec[0], y = vec[1], z = vec[2];

    // implementation of 3x3 quaternion rotation matrix:
    vec[0] = (1 - 2 * pow(total.y, 2) - 2 * pow(total.z, 2))*x + (2 * total.x * total.y - 2 * total.w * total.z)*y + (2 * total.x * total.z + 2 * total.w * total.y)*z;
    vec[1] = (2 * total.x * total.y + 2 * total.w * total.z)*x + (1 - 2 * pow(total.x, 2) - 2 * pow(total.z, 2))*y + (2 * total.y * total.z + 2 * total.w * total.x)*z;
    vec[2] = (2 * total.x * total.z - 2 * total.w * total.y)*x + (2 * total.y * total.z - 2 * total.w * total.x)*y + (1 - 2 * pow(total.x, 2) - 2 * pow(total.y, 2))*z;

    return vec;
}

差不多就是这样了(我还有一个规范函数来处理浮点错误),我将所有对象初始化为:W= 1,x= 0,y= 0,z= 0。我使用这样的表达式旋转四元数:

代码语言:javascript
复制
obj.rotation = rotate(angle, x-axis, y-axis, z-axis) * obj.rotation

其中obj.rotation是对象的总四元数旋转值。

如果有人知道出了什么问题,或者以前也经历过这个问题,我很感激能在这个问题上得到任何帮助。谢谢

编辑:乘以这些四元数输出预期的旋转:

代码语言:javascript
复制
rotate(angle,1,0,0)
rotate(angle,0,1,0)
rotate(angle,0,0,1)
rotate(angle,0,1,1)

然而,任何这样的旋转都会使模型奇怪地伸展开来:

代码语言:javascript
复制
rotate(angle,1,1,0)
rotate(angle,1,0,1)

EDIT2:这里是我用来规范四元数的规范化函数:

代码语言:javascript
复制
Quaternion normalize(Quaternion n, double tolerance) {
    // adds all squares of quaternion values, if normalized, total will be 1:
    double total = pow(n.w, 2) + pow(n.x, 2) + pow(n.y, 2) + pow(n.z, 2);
    if (total > 1 + tolerance || total < 1 - tolerance) {
        // normalizes value of quaternion if it exceeds a certain tolerance value:
        n.w /= (float) sqrt(total);
        n.x /= (float) sqrt(total);
        n.y /= (float) sqrt(total);
        n.z /= (float) sqrt(total);
    }
    return n;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-15 22:15:41

要按顺序实现两个旋转,您需要两个基本旋转的四元数乘积。每个初等旋转由一个轴和一个角度指定。但是,在您的代码中,您没有确保您有一个单位向量(方向向量)的轴线。

做下面的修改

代码语言:javascript
复制
Quaternion rotate(float w, float x, float y, float z) {
    Quaternion n;
    float f = 1/sqrtf(x*x+y*y+z*z)

    n.w = cosf(w/2);
    n.x = f * x * sinf(w/2);
    n.y = f * y * sinf(w/2);
    n.z = f * z * sinf(w/2); 

    return n;
}

然后按以下方式使用

代码语言:javascript
复制
Quaternion n = rotate(angle1,1,0,0) * rotate(angle2,0,1,0)

angle1与x轴的组合旋转,y轴的angle2旋转.

票数 1
EN

Stack Overflow用户

发布于 2021-09-15 21:19:21

正如注释中所指出的,您没有正确地初始化您的四元数。

下列四元数不是轮调:

代码语言:javascript
复制
rotate(angle,0,1,1)
rotate(angle,1,1,0)
rotate(angle,1,0,1)

原因是轴没有归一化,例如,向量(0,1,1)没有归一化。也要确保你的角度是弧度。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69075254

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档