【问题标题】:OpenGL(in Qt ) - problem in rotationOpenGL(在 Qt 中) - 旋转问题
【发布时间】:2011-06-19 13:42:03
【问题描述】:

我在openGL中做了一个简单的代码。你必须选择一张图片,就是这样。现在您可以使用这些键进行旋转

  • a,s -> 绕 x 轴旋转
  • d,f -> 绕 y 轴旋转
  • b,n -> 绕 z 轴旋转。

问题是 z 轴旋转始终可以正常工作。但是,x,y 旋转并不总是正确的。

测试: 按下任何(一个)按钮,然后您可以看到一个轴根本没有移动,另一个轴正在移动。您可以检查所有三个轴。但是一段时间后,即使您尝试围绕 x 轴旋转对象,您也可以看到所有三个轴都在移动。奇怪的是,围绕 z 轴的旋转总是正常工作。只有另外两个让人头疼。

这里是“main.cpp”

#include <QApplication>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QMessageBox>
#include <QPainter>
#include <QTextStream>
#include <QtOpenGL/QGLWidget>
#include <QVector3D>
#include <QWidget>

class MyMessageBox:public QMessageBox
{
public:
    MyMessageBox(std::string message,QWidget *parent=0):QMessageBox(QMessageBox::NoIcon,QString("ErrorMessage"),QString(message.c_str()),QMessageBox::Ok,parent,Qt::Widget)
    {
    }
};

class MyOpenGL:public QGLWidget
{
    double x_Rot;
    double y_Rot;
    double z_Rot;
    QVector<GLuint *> textures;  // it does nothing. It got added just for the sake of the program run
    QVector<QImage> openGL_Images;
public:
    MyOpenGL(QWidget * parent);
    ~MyOpenGL();
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();
    void drawCube(QPoint upper_Left_Point,int length,int width,int height,QVector<GLuint *> textures);
    void drawAxis();
    QVector3D get_In_OpenGL_Coordinates(QPoint qwidget_Point);
    void keyPressEvent(QKeyEvent * event);
    void mousePressEvent(QMouseEvent * event);
};

MyOpenGL::MyOpenGL(QWidget *parent):QGLWidget(QGLFormat(QGL::SampleBuffers),parent)
{
    setAutoFillBackground(false);
}

MyOpenGL::~MyOpenGL()
{

}

void MyOpenGL::initializeGL()
{
    //textures.push_back(new GLuint);
    //textures.push_back(new GLuint);

    QString fileName=QFileDialog::getOpenFileName();
    openGL_Images.push_back(convertToGLFormat(QImage(fileName).scaled(QSize(256,256))));
    openGL_Images.push_back(convertToGLFormat(QImage(fileName).scaled(QSize(256,256))));
    openGL_Images.push_back(convertToGLFormat(QImage(fileName).scaled(QSize(256,256))));
    openGL_Images.push_back(convertToGLFormat(QImage(fileName).scaled(QSize(256,256))));
    openGL_Images.push_back(convertToGLFormat(QImage(fileName).scaled(QSize(256,256))));
    openGL_Images.push_back(convertToGLFormat(QImage(fileName).scaled(QSize(256,256))));

    //glGenTextures(1,textures[0]);
    //glBindTexture(GL_TEXTURE_2D,*textures[0]);

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

    glEnable(GL_TEXTURE_2D);

    glShadeModel(GL_SMOOTH);
    glClearColor(0.0f,0.0f,0.0f,0.0f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
}

void MyOpenGL::resizeGL(int w, int h)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glViewport(45,0,w,h);
    gluPerspective(45.0f,((double)width())/height(),1.0f,100.0f);
    //gluOrtho2D(-10.0f,10.0f,-10.0f,10.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    paintGL();
}

void MyOpenGL::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
    glTranslatef(0.0,0.0,-10.0);
    glRotatef(x_Rot,1.0f,0.0f,0.0f);
    glRotatef(y_Rot,0.0f,1.0f,0.0f);
    glRotatef(z_Rot,0.0f,0.0f,1.0f);

    drawAxis();

    //drawCube(QPoint(0,0),1,1,1,textures);
}

void MyOpenGL::drawCube(QPoint upper_Left_Back_Point, int length, int width, int height,QVector<GLuint *> textures1)
{
    //glGenTextures(1,textures[0]);
    //glBindTexture(GL_TEXTURE_2D,*textures[0]);

    QVector3D starting_Point = get_In_OpenGL_Coordinates(upper_Left_Back_Point);

    double x=starting_Point.x();
    double y=starting_Point.y();
    double z=starting_Point.z();

    //glGenTextures(1,textures[0]);
    //glBindTexture(GL_TEXTURE_2D,*textures[0]);

     glTexImage2D(GL_TEXTURE_2D,0,3,openGL_Images[0].width(),openGL_Images[0].height(),0,GL_RGBA,GL_UNSIGNED_BYTE,openGL_Images[0].bits());
     glBegin(GL_QUADS);
//   glColor3f(1.0f,0.0f,0.0f);
     glTexCoord2f(0,1);glVertex3f(x-width,y+height,z-length);
     glTexCoord2f(1,1);glVertex3f(x+width,y+height,z-length);
     glTexCoord2f(1,0);glVertex3f(x+width,y+height,z+length);
     glTexCoord2f(0,0);glVertex3f(x-width,y+height,z+length);
     glEnd();

     //glGenTextures(1,textures[1]);
     //glBindTexture(GL_TEXTURE_2D,*textures[1]);
     glTexImage2D(GL_TEXTURE_2D,0,3,openGL_Images[1].width(),openGL_Images[1].height(),0,GL_RGBA,GL_UNSIGNED_BYTE,openGL_Images[1].bits());
     glBegin(GL_QUADS);
     //glColor3f(0.0f,1.0f,0.0f);
     glTexCoord2f(0,1);glVertex3f(x+width,y+height,z-length);
     glTexCoord2f(1,1);glVertex3f(x+width,y-height,z-length);
     glTexCoord2f(1,0);glVertex3f(x+width,y-height,z+length);
     glTexCoord2f(0,0);glVertex3f(x+width,y+height,z+length);
     glEnd();

     glTexImage2D(GL_TEXTURE_2D,0,3,openGL_Images[2].width(),openGL_Images[2].height(),0,GL_RGBA,GL_UNSIGNED_BYTE,openGL_Images[2].bits());
     glBegin(GL_QUADS);
     //glColor3f(0.0f,0.0f,1.0f);
     glTexCoord2f(0,1);glVertex3f(x+width,y-height,z-length);
     glTexCoord2f(1,1);glVertex3f(x-width,y-height,z-length);
     glTexCoord2f(1,0);glVertex3f(x-width,y-height,z+length);
     glTexCoord2f(0,0);glVertex3f(x+width,y-height,z+length);
     glEnd();


     glTexImage2D(GL_TEXTURE_2D,0,3,openGL_Images[3].width(),openGL_Images[3].height(),0,GL_RGBA,GL_UNSIGNED_BYTE,openGL_Images[3].bits());
     glBegin(GL_QUADS);
     //glColor3f(1.0f,1.0f,0.0f);
     glTexCoord2f(0,1);glVertex3f(x-width,y+height,z+length);
     glTexCoord2f(1,1);glVertex3f(x-width,y+height,z-length);
     glTexCoord2f(1,0);glVertex3f(x-width,y-height,z-length);
     glTexCoord2f(0,0);glVertex3f(x-width,y-height,z+length);
     glEnd();

     glTexImage2D(GL_TEXTURE_2D,0,3,openGL_Images[4].width(),openGL_Images[4].height(),0,GL_RGBA,GL_UNSIGNED_BYTE,openGL_Images[4].bits());
     glBegin(GL_QUADS);
     //glColor3f(1.0f,0.0f,1.0f);
     glTexCoord2f(0,1);glVertex3f(x-width,y+height,z-length);
     glTexCoord2f(1,1);glVertex3f(x+width,y+height,z-length);
     glTexCoord2f(1,0);glVertex3f(x+width,y-height,z-length);
     glTexCoord2f(0,0);glVertex3f(x-width,y-height,z-length);
     glEnd();

     glTexImage2D(GL_TEXTURE_2D,0,3,openGL_Images[5].width(),openGL_Images[5].height(),0,GL_RGBA,GL_UNSIGNED_BYTE,openGL_Images[5].bits());
     glBegin(GL_QUADS);
     //glColor3f(0,1,1);
     glTexCoord2f(0,1);glVertex3f(x-width,y+height,z+length);
     glTexCoord2f(1,1);glVertex3f(x+width,y+height,z+length);
     glTexCoord2f(1,0);glVertex3f(x+width,y-height,z+length);
     glTexCoord2f(0,0);glVertex3f(x-width,y-height,z+length);
     glEnd();
}

void MyOpenGL::drawAxis()
{
    //int length = 1;
    //int height = 1;
    //int width = 1;

    //int x = 0;
    //int y=0;
    //int z = 0;


    glBegin(GL_LINES);
    glColor3f(1,0,0);
    glVertex3f(0,0,0);
    glVertex3f(3,0,0);

    glColor3f(0,1,0);
    glVertex3f(0,0,0);
    glVertex3f(0,3,0);

    glColor3f(0,0,1);
    glVertex3f(0,0,0);
    glVertex3f(0,0,3);
    //glVertex3f(x-width,y+height,z+length);
    //glVertex3f(x+width,y+height,z+length);
    //glVertex3f(x+width,y-height,z+length);
    //glVertex3f(x-width,y-height,z+length);
    glEnd();
}

QVector3D MyOpenGL::get_In_OpenGL_Coordinates(QPoint qwidget_Point)
{
    return QVector3D(0,0,0);
}

void MyOpenGL::keyPressEvent(QKeyEvent * event)
{
    switch(event->key())
    {
        case Qt::Key_A:
            x_Rot-=5;
            break;
        case Qt::Key_S:
            x_Rot+=5;
            break;
        case Qt::Key_D:
            y_Rot+=5;
            break;
        case Qt::Key_F:
            y_Rot-=5;
            break;
        case Qt::Key_B:
            z_Rot+=5;
            break;
        case Qt::Key_N:
            z_Rot-=5;
            break;
        default:
            break;
    }
    updateGL();
}

void MyOpenGL::mousePressEvent(QMouseEvent *event)
{
    double x = event->pos().x();
    double y = event->pos().y();
    double z=-1;

    glReadPixels(x,y,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&z);

    double projection[16];
    glGetDoublev(GL_PROJECTION_MATRIX,projection);
    double modelView[16];
    glGetDoublev(GL_MODELVIEW_MATRIX,modelView);

    int viewPort[4];
    glGetIntegerv(GL_VIEWPORT,viewPort);

    double x_Gl;
    double y_Gl;
    double z_Gl;
    gluUnProject(x,y,z,modelView,projection,viewPort,&x_Gl,&y_Gl,&z_Gl);

    QString ss;
    QTextStream ss_Text(&ss);
    ss_Text << x_Gl << " " << y_Gl << " " << z_Gl ;
    MyMessageBox mm(ss.toStdString());
    mm.exec();
}

int main(int argc,char * argv[])
{
    QApplication app(argc,argv);

    MyOpenGL * f = new MyOpenGL(NULL);
    f->show();

    return app.exec();
}

这里是 .pro 文件

SOURCES += \
    main.cpp

QT += opengl

请有人帮我解决这个问题。

【问题讨论】:

  • 您希望发生什么?
  • @Mikola 我期待 z 轴在其他两个轴上的行为。
  • 对不起,这不是很具体。 “z 轴行为”是什么意思?
  • @Mikola 上面的应用程序代码只是绘制了三个轴。当我围绕一个轴旋转轴时,一个应该留下,另外两个必须围绕它旋转。但是,在上面的代码中,所有三个轴都在旋转。当旋转大约是 z 轴时,它可以像我预期的那样完美地工作。
  • 好的,听起来您所描述的是您想要逐步应用旋转。因为 3D 中的旋转不通勤,所以您不能单独总结所有 x、y、z 旋转。如果您想要这种行为,您需要在客户端的矩阵/四元数中累积所有旋转;然后在绘制之前旋转该量。我的答案中的链接应该会有所帮助。

标签: c++ windows qt opengl


【解决方案1】:

首先对您的代码进行一些观察:

  1. 在哪里初始化 x_Rot、y_Rot 和 z_Rot?我看不出这是在哪里发生的。

接下来,一些更通用的cmets:

从技术上讲,您现在正在做的是围绕 x、y 和 z 旋转。如果您想做其他事情,例如每次按下按钮时逐渐旋转,那么您需要仔细考虑您正在尝试做什么。一种方法是在 OpenGL 中逐步应用旋转矩阵。另一种可能性是在客户端存储一个四元数/矩阵,然后每帧重置视图转换。还有一种可能性是淘汰一堆三角函数并计算每次旋转的 x/y/z 角度的正确偏差(不推荐)。一旦你了解了你真正想要做的事情,你就可以做这些事情中的任何一件,甚至更多。要达到这一点,您必须阅读一些内容(抱歉,这就是数学的工作原理)。作为起点,这里有一些基本的 wiki 页面可以帮助您开始:

http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29

http://en.wikipedia.org/wiki/Rotation_matrix

http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation

【讨论】:

    【解决方案2】:

    看来你的问题是Gimbal Lock

    使用四元数是解决此问题的最简单方法之一。

    【讨论】:

    • +1 表示万向节锁。请注意,只需将旋转存储在每帧的矩阵中,并不断更新可能会解决问题。四元数适用于插值旋转,但当您只想增量旋转某些东西时并不总是必要的。
    猜你喜欢
    • 2011-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多