OpenGL中的轨迹球旋转

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL中的轨迹球旋转相关的知识,希望对你有一定的参考价值。

我无法在OpenGL上实现轨迹球旋转。当我使用轨迹球沿X轴向右旋转90度来旋转立方体(在屏幕上从左向右拖动鼠标),然后尝试旋转它时,将鼠标从屏幕的顶部拖动到屏幕的底部,我希望立方体沿我的透视图的y轴旋转。相反,它在旋转后沿ITS y轴旋转,从我的角度来看向侧面旋转。

有人可以告诉我我可能做错了什么吗?

答案

听起来您没有使用四元数来表示旋转。如果您使用Google搜索“ Arcball Graphics Gems”,那么应该可以在Kenshoemake的Graphic Gems IV中找到代码。

或者,如果您只想要代码,则为go here

另一答案

+ 1为Daniel关于四元数和Arcball的建议。您应该始终使用四元数来表示方向和旋转。

另一个提示:Gavin Bell实现了Arcball的扩展,使鼠标在旋转球体之外的点击更加直观。它在Glut库的示例herehere中分发。

NeHe实现类似,但是球体内部和外部之间的过渡是平滑的。 Bell的方法已在许多开源3D库中使用,包括:

另一答案

我找到了一种非常便宜又肮脏的方法。所以OpenGL中的矩阵是这样的0 1 2 34 5 6 78 9 10 1112 13 14 15

如果您将3个垂直数字用作旋转矢量,则将获得所需的效果。例如:

如果绕矢量(0,4,8)旋转,则将绕x轴旋转。同样(1,5,9)将为y,(3,6,10)将为z。为什么行得通?....好吧,当您取垂直数字时,您制作了原始矩阵的转置副本,与旋转的矩阵相比,它为您提供了某种原始矩阵....对不起,我不知道数学家,但有效。相信我 ;)。我在OpenGL ES上的示例代码:

        Matrix.rotateM(Settings.anchorMatrix, 0, rX, Settings.anchorMatrix[0], Settings.anchorMatrix[4], Settings.anchorMatrix[8]);
        Matrix.rotateM(Settings.anchorMatrix, 0, rY, Settings.anchorMatrix[1], Settings.anchorMatrix[5], Settings.anchorMatrix[9]);
        Matrix.rotateM(Settings.anchorMatrix, 0, rZ, Settings.anchorMatrix[2], Settings.anchorMatrix[6], Settings.anchorMatrix[10]);

anchorMatrix从技术上讲是我在侧面创建的用于跟踪的主要矩阵。 android OpenGL ES不允许我从状态机中获取当前矩阵。

另一答案

这是一个非常老的问题,但是我碰到了[[完全相同的问题,我不想转向四元数,因为使用它们完成的任何操作都可以使用标准的线性代数完成。

我发现的解决方案是将弓形球的坐标转换为摄影机坐标(我认为-好像弓形球与摄影机一起旋转)。

我还使用Rodrigues公式旋转了相机的位置,前向和上向矢量,然后诉诸glm:LookAt返回最终的ViewMatrix(将顶点着色器相乘的那个)。

我的代码如下:

// Processes input received from a mouse input system. void ProcessMouseMovement(glm::vec2 prevMouse, glm::vec2 curMouse) glm::vec3 p1 = screen_to_arcball( prevMouse ); glm::vec3 p2 = screen_to_arcball( curMouse ); // Rotate arcball to camera coordinates p1 = glm::vec3( ViewMatrix * glm::vec4(p1, 0.0)); p2 = glm::vec3( ViewMatrix * glm::vec4(p2, 0.0)); glm::vec3 axis = glm::cross(p1, p2); float angle = std::acos(glm::dot(p1,p2)); if ( angle > 0.001f) // Rotate Position = rotate_axis_angle(Position, axis, angle); Front = rotate_axis_angle(Front, axis, angle); Up = rotate_axis_angle(Up, axis, angle); ViewMatrix = glm::lookAt(Position, Position + Front, Up); // Get Arcball coordinates from screen glm::vec3 screen_to_arcball(const glm::vec2 &p) const float dist = glm::dot(p, p); if (dist < 0.999f) // If we're on/in the sphere return the point on it return glm::vec3(p.x, p.y, std::sqrt(1.f - dist)); else // otherwise we project the point onto the sphere const glm::vec2 proj = glm::normalize(p); return glm::vec3(proj.x, proj.y, 0.f); // Rotate vector given (angle,axis) using Rodrigues' formula glm::vec3 rotate_axis_angle(glm:: vec3 &vec, glm:: vec3 axis, float angle) axis = glm::normalize(axis); glm::vec3 cross_axis = glm::cross(axis, vec); vec = vec * std::cos(angle) + axis * glm::dot(axis,vec) * (1.0f - std::cos(angle)) + cross_axis * std::sin(angle); return vec;

以上是关于OpenGL中的轨迹球旋转的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 链式平移/旋转

Arcball轨迹球

带有 Qt 和 OpenGL 的轨迹球控件

2D 中的 OpenGL 旋转

OpenGL中的3D旋转

如何避免 OpenGL 中的光旋转?