QGLWidget , Trackball



  • Ich brauche eine Trackball Steuerung für ein QGLWidget (Deshalb in dieser Rubrik, passt aber auch nach OpenGL).

    Habe mich an "E.Angel: Interactive Computer Graphics - A Top Down Aproach Using Open GL" langehangelt.

    Ich kanns drehen - aber ab der zweiten Drehung wird es un-Intuitiv.

    Wer mag helfen?

    Ich habe versucht ein Minimalbeispiel aus meinem Code zu machen, es ist aber immer noch recht groß ... sorry.

    .pro file

    TARGET = testtt
    TEMPLATE = app
    
    QT *= opengl
    
    SOURCES += main.cpp\
            mainwindow.cpp
    HEADERS  += mainwindow.h
    

    main.cpp

    #include <QtGui/QApplication>
    #include "mainwindow.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    

    mainwindow.h

    #ifndef MY_MAINWINDOW_H
    #define MY_MAINWINDOW_H
    
    #include <QGLWidget>
    
    #include <QtCore>
    #include <QtGui>
    #include <QtOpenGL>
    
    // cos,sin for trackball
    #include <math.h>
    
    class MainWindow : public QGLWidget
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = 0);
        virtual ~MainWindow();
    
    public slots: // trackball
        void setAngleAxis();
        void setXTranslation(int delta);
        void setYTranslation(int delta);
        void setZTranslation(int delta);
    
    protected:
        void initializeGL();
        void paintGL();
        void resizeGL(int width, int height);
    
        QSize sizeHint()    {return QSize(640,480);}
        QSize minimumSize() {return QSize(320,240);}
    
        // last mouse position
        QPoint lastPos;
    
        // trackball
        float angle, axis[3], trans[3], lastPosition[3];
        int curX, curY, startX, startY;
        bool tracking;
    
        // current modelview matrix
        GLdouble currentModelviewMatrix[16];
    
        void ptov(int x, int y, int width, int height, GLfloat v[3]);
        void mousePressEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
        void mouseMoveEvent(QMouseEvent *event);
    
    private: // OPEN GL RELATED
        GLuint makeGrid();
        void drawGrid();
    
    private: // members
        GLuint grid;
    };
    
    #endif // MAINWINDOW_H
    

    mainwindow.cpp

    #include "mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QGLWidget(parent),
        angle(0.0),
        curX(0),
        curY(0),
        startX(0),
        startY(0),
        tracking(false)
    {
        resize(sizeHint());
    
        // more trackball init stuff
    
        axis[0]=axis[1]=axis[2]=0.0;
        trans[0]=trans[1]=trans[2]=0.0;
        lastPosition[0]=lastPosition[1]=lastPosition[2]=0.0;
    }
    
    MainWindow::~MainWindow() {
        makeCurrent();
        glDeleteLists(grid,1);
    }
    
    // SLOTS
    void MainWindow::setAngleAxis() { 
        updateGL(); 
    }
    
    void MainWindow::setXTranslation(int delta) { 
        trans[0]=delta;   
        updateGL(); 
    }
    
    void MainWindow::setYTranslation(int delta) { 
        trans[1] = delta; 
        updateGL(); 
    }
    
    void MainWindow::setZTranslation(int delta) { 
        trans[2] = delta; 
        updateGL(); 
    }
    
    // GL INIT
    void MainWindow::initializeGL() {
        glClearColor(0.05f, 0.05f, 0.05f, 1.0f);
        glEnable(GL_DEPTH);
        glEnable(GL_DEPTH_TEST) ;
        // create list
        grid = makeGrid();
    }
    
    void MainWindow::paintGL() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadMatrixd(currentModelviewMatrix);
    
        glRotated (angle,axis[0],axis[1],axis[2]);
        glTranslated(trans[0] / 10.0 , trans[1] / 10.0, trans[2] / 15.0);
        drawGrid();
    }
    
    void MainWindow::resizeGL(int width, int height) {
        int side = qMin(width, height);
        glViewport((width - side) / 2, (height - side) / 2, side, side);
    
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(54.0f,(GLfloat)width/(GLfloat)height,1.0f,50.0f);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.0,  0.0, -3.0);
        glRotatef(60.0,1,0,0);
    
        glGetDoublev(GL_MODELVIEW_MATRIX, currentModelviewMatrix);
    }
    
    // point 2d to vector 3d
    void MainWindow::ptov(int x, int y, int width, int height, GLfloat v[3]) {
        GLfloat dist, angle;
        // project x,y on hemisphere centered within width, heigth
        v[0] = (2.0f * x - width) / width;
        v[1] = (height - 2.0f * y) / height;
        dist = (float) sqrt(v[0]*v[0]+v[1]*v[1]);
        // if outside hemisphere, trunc to 1
        v[2] = (float) (cos(M_PI_2 * ( dist < 1.0f) ? dist : 1.0f));
    
        angle = 1.0f / (float) sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
        v[0] *= angle;
        v[1] *= angle;
        v[2] *= angle;
    }
    
    // mouse handler
    void MainWindow::mousePressEvent(QMouseEvent *event) {
        lastPos = event->pos();
        int x = lastPos.x();
        int y = lastPos.y();
    
        // press left button starts trackball steering
        if (event->buttons() == Qt::LeftButton)
        {
            tracking = true;
            startX = curX = x;
            startY = curY = y;
    
            ptov(x, y, this->size().width(), this->size().height(), lastPosition);
    
            event->accept();
        } else event->ignore();
    }
    
    void MainWindow::mouseReleaseEvent(QMouseEvent *event) {
        // release left button stops trackball steering
        if (tracking)
        {
            glGetDoublev(GL_MODELVIEW_MATRIX, currentModelviewMatrix);
            event->accept();
            tracking = false;
        } else event->ignore();
    }
    
    void MainWindow::mouseMoveEvent(QMouseEvent *event) {
        int x = lastPos.x();
        int y = lastPos.y();
        int mousedx = event->x() - lastPos.x();
        int mousedy = event->y() - lastPos.y();
    
        GLfloat curPos[3], dx,dy,dz;
        ptov(x,y, this->size().width(), this->size().height(), curPos);
    
        // DRAG
        if ( (event->buttons() == Qt::MidButton) ||
             (event->buttons() == (Qt::LeftButton + Qt::RightButton)))
            {
                setXTranslation(trans[0] + mousedx);
                setYTranslation(trans[1] - mousedy);
    
                event->accept();
            }
        // ROTATE
        else if (event->buttons() == Qt::LeftButton)
        {
            dx= curPos[0] - lastPosition[0];
            dy= curPos[1] - lastPosition[1];
            dz= curPos[2] - lastPosition[2];
    
            if (dx || dy || dz)
            {
                angle = 90.0f * sqrt(dx*dx+dy*dy+dz*dz);
                axis[0] = lastPosition[1]*curPos[2] - lastPosition[2]*curPos[1];
                axis[1] = lastPosition[2]*curPos[0] - lastPosition[0]*curPos[2];
                axis[2] = lastPosition[0]*curPos[1] - lastPosition[1]*curPos[0];
    
                setAngleAxis();
            }
    
            event->accept();
        }
        // ZOOM
        else if (event->buttons() == Qt::RightButton)
        {
            setZTranslation(trans[2] - mousedy);
            event->accept();
        }
        else event->ignore();
    
        lastPos = event->pos();
    
    }
    
    GLuint MainWindow::makeGrid() {
        GLuint list = glGenLists(1);
        glNewList(list, GL_COMPILE);
        {
            glPushMatrix();
            {
                glColor3f(0.4f,0.8f,0.2f);
                glBegin(GL_QUADS);
                glVertex3f(-1,0,-1);
                glVertex3f(-1,0,1);
                glVertex3f(1,0,1);
                glVertex3f(1,0,-1);
                glEnd();
    
                glColor3f(0.8f,0.2f,0.4f);
                glBegin(GL_QUADS);
                glVertex3f(-1,0.001f,-1);
                glVertex3f(-1,0.001f,1);
                glVertex3f(1,0.001f,1);
                glVertex3f(1,0.001f,-1);
                glEnd();
            }
            glPopMatrix();
        }
        glEndList();
    
        return list;
    }
    
    void MainWindow::drawGrid() {
        glCallList(grid);
    }
    


  • Ohne jetzt den Code compiled zu haben etc. nehm ich mal an das du trotzdem (trackball) nur den cursor bewegst und deswegen irgendwann an den Bildschirmrand stösst und sich deswegen die Cursorkoordinaten auf einer Achse nicht mehr ändern wenn du weiterdrehst.

    Du könntest wohl versuchen die Maus nach jedem Event wieder an die Stelle zu setzen wo er sich vor dem Event befunden hat. So kannst du jedesmal die Abweichung messen und reagieren.(Natürlich nur wenn die Tasten die Die Translation aktivieren aktiv sind, sonst kommst ja nimmer raus ;D).

    OnRotationModeActivate
       saveCuror(event->x(),event->y());
       setCursor(GLWidgetCenter);
    
    OnRotationModeDeactivate
       restoreCursor();
    

    oder sowas, natürlich nur falls ich das Problem richtig vermutet habe



  • Die erste Drehung tut ... nur folgende sind nicht intuitiv. Ich stell auf 3 Slider um, das ist einfacher und kümmere mich später um die Maus.



  • Mit der ersten Drehung dreht sich auch dein Koordinatensystem und deshalb erfolgen alle weiteren rotationen um dieses und nicht um das Globale.


Anmelden zum Antworten