【发布时间】:2014-12-29 21:22:36
【问题描述】:
我正在尝试创建一个 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 平面上实现圆形旋转。
当我尝试累积所有不同的旋转时,就会出现问题。我试图遵循的路径如下所示:
作为一项要求,鸟的腹部应该始终面向球体表面,并且鸟应该向前飞行。
我目前的方法是这样的,它只包含三个方向四元数的组合:
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.0f 和alpha = HALF_PI,圆再次位于xz 平面中,rotationAngleXZ 的值正在发生变化,而rotationAngleXY 是-HALF_PI 或HALF_PI,rotationAngleYZ 是0.0f 或PI。我想我在这里遇到了 Gimbal Lock 并且我已经阅读了大量关于它的文章,但是我仍然不确定在这种情况下如何防止它。
// 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);
【问题讨论】:
标签: c++ opengl rotation geometry quaternions