我不确定如何解释这个,但希望你能理解我的意思。
基本上我画了一个立方体,想要拖动鼠标来查看所有边。 只能水平或垂直旋转很好,但如果我尝试将它们组合起来,那么事情就会变得有些奇怪。
e.g。如果我垂直旋转180度(以“倒置”)然后水平拖动鼠标,那么立方体将以与鼠标运动相反的方向旋转。
这是相关代码:
double camera_angle_h = 0;
double camera_angle_v = 0;
int drag_x_origin;
int drag_y_origin;
int dragging = 0;
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0.0, 0.0, 25.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glRotated(camera_angle_v, 1.0, 0.0, 0.0);
glRotated(camera_angle_h, 0.0, 1.0, 0.0);
draw_cube();
glFlush();
glutSwapBuffers();
}
void mouse_click(int button, int state, int x, int y) {
if(button == GLUT_LEFT_BUTTON) {
if(state == GLUT_DOWN) {
dragging = 1;
drag_x_origin = x;
drag_y_origin = y;
}
else
dragging = 0;
}
}
void mouse_move(int x, int y) {
if(dragging) {
camera_angle_v += (y - drag_y_origin)*0.3;
camera_angle_h += (x - drag_x_origin)*0.3;
drag_x_origin = x;
drag_y_origin = y;
}
}
答案 0 :(得分:4)
您正在使用欧拉角,因此存在万向节锁的问题。
一个简单的解决方案是将旋转存储在模型矩阵内并旋转此矩阵,而不是仅存储2个角度(通过使用矩阵乘法)。
查看此答案以获取更多信息: Will this cause gimbal-lock?
更复杂的解决方案是存储四元数
答案 1 :(得分:4)
正如其他人所说,使用四元数是解决方案。 Ken Shoemake提供了在图形宝石IV中转换四元数和欧拉角的优秀代码(参见code samples here,参见“欧拉角转换”)。它还具有与旋转矩阵的转换。
如果你想使用鼠标进行旋转,可以说“黄金标准”是Shoemake在图形宝石IV中描述的“Arcball”界面(目前可用的here)。改进版的Arcball与Glut库一起作为“轨迹球”分发,当点击发生在旋转球体外时,它提供了更直观的界面。它由Gavin Bell撰写,可用here和here。 Bell的轨迹球是Blender project使用的方法,我认为商业软件包使用类似的东西。
答案 2 :(得分:2)
听起来好像您的应用程序遇到了gimbal lock。有几种方法可以解决这个问题,最简单的方法就是限制允许的旋转。
答案 3 :(得分:2)
大多数应用程序仅允许最多90度的上/下旋转;否则,视图是颠倒的,是从左到右反转。对于大多数应用来说,旋转到目前为止你没有意义,因为你正在颠倒世界。
此外,这不像其他两位回答者说的那样是万向节锁;万向节锁需要三个(或更多?)旋转轴。简而言之,万向节锁定是指一个轴向任一方向旋转90度,使另外两个轴对齐;然后围绕其他两个轴中的任何一个旋转会产生相同的效果。维基百科页面中间的飞机图像很好地显示了它。
无论如何,最好的办法是将camera_angle_v
限制在范围内(-90,90);换句话说,每当你加或减时,检查它是否大于90并将其设置为90,或者如果它小于-90,则将其设置为-90。
另外需要注意的是,过去当v角度正好是90或-90时,我确实遇到了问题,所以我会把它夹紧到+/- 89.9。
答案 4 :(得分:0)
由于您使用的是GLUT,因此您可能需要在系统上处理此问题的代码。查看trackball.c和trackball.h源文件。谷歌搜索他们也会找到来源。这是一个简单的库,可以帮助您解决这个问题。一些使用它们的GLUT例子是dinospin,bounce等。