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.