gpt4 book ai didi

c++ - OpenGL 中的 3 轴四元数旋转

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:24:13 24 4
gpt4 key购买 nike

我正在尝试创建一个 OpenGL 程序,其中一只鸟的模型应该沿着定义的路径沿着由 Seiffert 球形螺旋描述的球体表面移动。然而,我已经坚持正确的旋转已经有一段时间了。

作为第一步,我让小鸟在 x-z 平面中沿着圆形路径运动:

// 1. Circle in x-z plane
float phi = TWO_PI * t; // t = [0..1]

float x = boundingSphereRadius * cos(phi);
float y = 0.0f;
float z = boundingSphereRadius * sin(phi);

float rotationAngle = glm::orientedAngle(glm::vec3(0.0f, 0.0f, 1.0f),
glm::normalize(glm::vec3(x, 0, z)),
glm::vec3(0.0f, 1.0f, 0.0f)) - HALF_PI;
glm::fquat rotation = glm::angleAxis(rotationAngle, glm::vec3(0.0f, 1.0f, 0.0f));

固定的 -HALF_PI 是必需的,这样鸟才能正确对齐。这工作得很好,同样我可以在 x-y 和 y-z 平面上实现圆形旋转。

当我尝试累积所有不同的旋转时出现问题。我尝试遵循的路径如下所示:

enter image description here enter image description here

根据要求,小鸟的腹部应该始终面向球体表面,小鸟应该向前飞行。

我目前的方法是这样的,它只是组合三个方向四元数:

glm::fquat rotationX  = glm::angleAxis(glm::orientedAngle(glm::normalize(glm::vec3(0.0f, 0.0f, 1.0f)), glm::normalize(glm::vec3(x, 0, z)), glm::vec3(0.0f, 1.0f, 0.0f)) - HALF_PI, glm::vec3(0.0f, 1.0f, 0.0f));
glm::fquat rotationY1 = glm::angleAxis(-HALF_PI, glm::vec3(0.0f, 1.0f, 0.0f));
glm::fquat rotationY2 = glm::angleAxis(glm::orientedAngle(glm::vec3(0.0f, 1.0f, 0.0f), glm::normalize(glm::vec3(x, y, 0)), glm::vec3(0.0f, 0.0f, 1.0f)), glm::vec3(0.0f, 0.0f, 1.0f));
glm::fquat rotationY = rotationY2 * rotationY1;
glm::fquat rotationZ = glm::angleAxis(glm::orientedAngle(glm::vec3(0.0f, 0.0f, 1.0f), glm::normalize(glm::vec3(0, y, z)), glm::vec3(1.0f, 0.0f, 0.0f)) + HALF_PI, glm::vec3(1.0f, 0.0f, 0.0f));
glm::fquat rotation = rotationZ * rotationY * rotationX;

然而,方向的变化是完全错误的,在某些角度上会发生跳跃。

编辑:

我现在正在球体上尝试不同的圆圈,其中需要多次旋转。对于 beta = gamma = 0.0falpha = HALF_PI 圆再次位于 x-z 平面中并且 rotationAngleXZ 的值正在改变,同时rotationAngleXYHALF_PI-HALF_PI 并且 rotationAngleYZ0.0fPI。我想我在这里遇到了万向节锁,我已经阅读了大量关于它的文章,但我仍然不确定在这种情况下如何防止它。

// 10. `Arbitrary` circles on sphere surface
// http://math.stackexchange.com/questions/643130/circle-on-sphere
//
// Parameters:
// alpha = 0...HALF_PI - For alpha = 0, the circle is just a point - For alpha = HALF_PI, the circle is a Great Circle
// (beta, gamma) = center of circle in spherical coordinates
float phi = TWO_PI * t;

float x = boundingSphereRadius * ( (sin(alpha) * cos(beta) * cos(gamma)) * cos(phi) + (sin(alpha) * sin(gamma)) * sin(phi) - (cos(alpha) * sin(beta) * cos(gamma)));
float y = boundingSphereRadius * ( (sin(alpha) * sin(beta)) * cos(phi) + cos(alpha) * cos(beta));
float z = boundingSphereRadius * (-(sin(alpha) * cos(beta) * sin(gamma)) * cos(phi) + (sin(alpha) * cos(gamma)) * sin(phi) + (cos(alpha) * sin(beta) * sin(gamma)));

float rotationAngleXZ = glm::orientedAngle(glm::normalize(glm::vec3(0.0f, 0.0f, 1.0f)), glm::normalize(glm::vec3(x, 0, z)), glm::vec3(0.0f, 1.0f, 0.0f));
std::cout << "Rotation Angle XZ = " << rotationAngleXZ << std::endl;
glm::fquat rotationXZ = glm::angleAxis(rotationAngleXZ - HALF_PI, glm::vec3(0.0f, 1.0f, 0.0f));

float rotationAngleXY = glm::orientedAngle(glm::vec3(0.0f, 1.0f, 0.0f), glm::normalize(glm::vec3(x, y, 0)), glm::vec3(0.0f, 0.0f, 1.0f));
std::cout << "Rotation Angle XY = " << rotationAngleXY << std::endl;
glm::fquat rotationXY_Y = glm::angleAxis(-HALF_PI, glm::vec3(0.0f, 1.0f, 0.0f));
glm::fquat rotationXY_Z = glm::angleAxis(rotationAngleXY, glm::vec3(0.0f, 0.0f, 1.0f));
glm::fquat rotationXY = rotationXY_Z * rotationXY_Y;

float rotationAngleYZ = glm::orientedAngle(glm::vec3(0.0f, 0.0f, 1.0f), glm::normalize(glm::vec3(0, y, z)), glm::vec3(1.0f, 0.0f, 0.0f));
std::cout << "Rotation Angle YZ = " << rotationAngleYZ << std::endl;
glm::fquat rotationYZ = glm::angleAxis(rotationAngleYZ + HALF_PI, glm::vec3(1.0f, 0.0f, 0.0f));

glm::fquat rotation = glm::normalize(rotationXZ) * glm::normalize(rotationXY) * glm::normalize(rotationYZ);

最佳答案

您的代码使用欧拉角(轴对齐旋转)。摆动和跳跃是因为欧拉角是 3D 旋转空间的错误参数化。相反,这里有两种替代方法。

通过框架构建旋转矩阵

假设鸟在它自己的局部坐标系中指向 x 轴下方和上方。

p = [x y z] 为鸟的位置。令 v 为其速度 vector 。让

f = v/|v|
up = p/|p|
s = cross(f, up)

现在构建包含行 f、up、s 的矩阵。具体来说:

[  f[0]   f[1]  f[2] ]
[ up[0] up[1] up[2] ]
[ s[0] s[1] s[2] ]

然后通过 GLM 的 quat_cast 函数生成一个四元数。

避免使用 gluLookAt,因为它使用已弃用的固定函数矩阵堆栈。

通过旋转(四元数)构建

R0 为从if 的旋转。 (角度是 acos(dot(i,f)) 轴是 cross(i,f))

R1 为从R0*jup 的旋转。 (使用矩阵乘法符号,因为在这种情况下它更容易)

R2 为从 R1*R0*ks 的旋转。

最后的旋转应该是R2*R1*R0。检查这个旋转是否等于上面的矩阵。

关于c++ - OpenGL 中的 3 轴四元数旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27696205/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com