我在OpenGL中绘制一个对象(比如一个立方体),用户可以通过在窗口上单击/拖动鼠标来旋转它。立方体的绘制方式如下:
void CubeDrawingArea::redraw()
{
Glib::RefPtr gl_drawable = get_gl_drawable();
gl_drawable->gl_begin(get_gl_context());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
{
glRotated(m_angle, m_rotAxis.x, m_rotAxis.y, m_rotAxis.z);
glCallList(m_cubeID);
}
glPopMatrix();
gl_drawable->swap_buffers();
gl_drawable->gl_end();
}
并使用此功能旋转:
bool CubeDrawingArea::on_motion_notify_event(GdkEventMotion* motion) { if (!m_leftButtonDown) return true;
_3V cur_pos; get_trackball_point((int) motion->x, (int) motion->y, cur_pos); const double dx = cur_pos.x - m_lastTrackPoint.x; const double dy = cur_pos.y - m_lastTrackPoint.y; const double dz = cur_pos.z - m_lastTrackPoint.z; if (dx || dy || dz) { // Update angle, axis of rotation, and redraw m_angle = 90.0 * sqrt((dx * dx) + (dy * dy) + (dz * dz)); // Axis of rotation comes from cross product of last / cur vectors m_rotAxis.x = (m_lastTrackPoint.y * cur_pos.z) - (m_lastTrackPoint.z * cur_pos.y); m_rotAxis.y = (m_lastTrackPoint.z * cur_pos.x) - (m_lastTrackPoint.x * cur_pos.z); m_rotAxis.z = (m_lastTrackPoint.x * cur_pos.y) - (m_lastTrackPoint.y * cur_pos.x); redraw(); } return true;
_3V cur_pos; get_trackball_point((int) motion->x, (int) motion->y, cur_pos); const double dx = cur_pos.x - m_lastTrackPoint.x; const double dy = cur_pos.y - m_lastTrackPoint.y; const double dz = cur_pos.z - m_lastTrackPoint.z; if (dx || dy || dz) { // Update angle, axis of rotation, and redraw m_angle = 90.0 * sqrt((dx * dx) + (dy * dy) + (dz * dz)); // Axis of rotation comes from cross product of last / cur vectors m_rotAxis.x = (m_lastTrackPoint.y * cur_pos.z) - (m_lastTrackPoint.z * cur_pos.y); m_rotAxis.y = (m_lastTrackPoint.z * cur_pos.x) - (m_lastTrackPoint.x * cur_pos.z); m_rotAxis.z = (m_lastTrackPoint.x * cur_pos.y) - (m_lastTrackPoint.y * cur_pos.x); redraw(); } return true;
那里有一些GTK +的东西,但它应该是非常明显的。 get_trackball_point()函数将窗口坐标X Y投影到半球(虚拟“轨迹球”)上,该半球用作旋转对象的参考点。无论如何,这或多或少都有效,但是在我完成旋转后,我再次旋转,立方体快速回到原始位置,显然,因为m_angle将在下次旋转时重置为接近0。反正是为了避免这种情况并保持旋转吗?
答案 0 :(得分:0)
是的,我也遇到了这个问题。
你需要做的是保持一个旋转矩阵,“累积”当前的旋转状态,并使用它除了当前拖动操作的旋转矩阵。
假设您有两个矩阵,lastRotMx和currRotMx。如果你愿意,让他们成为CubeDrawingArea的成员。
您没有向我们展示过这一点,但我认为只要鼠标按钮停止拖动就会初始化m_lastTrackPoint。发生这种情况时,将currRotMx复制到lastRotMx。
然后在on_motion_notify_event()
中,在计算m_rotAxis和m_angle之后,根据m_rotAxis和m_angle创建一个新的旋转矩阵draggingRotMx;然后通过draggingRotMx乘以lastRotMx并将结果放在currRotMx中。
最后,在redraw()
中,而不是
glRotated(m_angle, m_rotAxis.x, m_rotAxis.y, m_rotAxis.z);
通过currRotMx旋转。
更新:或者不是所有...... 我没有测试过这个,但我认为它会起作用:
使cur_pos成为一个类成员,使其保持不变,但它被初始化为零,m_lastTrackPoint也是如此。 然后,每当启动新的拖动动作时,在初始化m_lastTrackPoint之前,让_3V dpos = cur_pos - m_lastTrackPoint(伪代码)。 最后,当您根据鼠标事件坐标初始化m_lastTrackPoint时,从中减去dpos。
这样,你的cur_pos已经从m_lastTrackPoint偏移了一个数量,该数量是基于过去的arcball drags积累的偏移量。
错误也可能累积,但它应该是渐进的,以免引起注意。但是我想测试它以确定......组合旋转很棘手,我不相信它们而没有看到它们。
P.S。您的用户名是失去动力的。建议选择另一个。
P.P.S。对于稍后搜索此问题的答案的用户,要搜索的关键字为“arcball rotation”。最新文章是Ken Shoemake在Graphical Gems IV中的部分。另请参阅此arcball tutorial for JOGL。