在OpenGL中保留旋转

时间:2010-10-01 02:34:01

标签: opengl

我在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。反正是为了避免这种情况并保持旋转吗?

1 个答案:

答案 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