2016-02-15 4 views
0

Я пытаюсь реализовать базовое решение для трекбола с openGL.Вращение трекбола в OpenGL

Есть 2 оборота: - вокруг оси x (вправо), связанной с перемещением мыши вверх/вниз. - вокруг оси y (направление вверх), связанное с движением правой/левой мыши. Куб центрирован на 0, камера находится на оси z. Ось рисуется: x в синем, y - зеленым, z - красным.

2 различные группы вращений:

  1. 90 ° вокруг х, перемещая мышь вниз. Z вниз, x справа, y впереди. Затем другое вращение: 90 ° вокруг z (z, как показано), движение мыши справа. z вправо, x вверх и y впереди.

  2. Я обрабатываю снова, положение начинаю с нуля. 90 ° вокруг y. y: вверх, z: правый, x: впереди Другой поворот на 90 ° вокруг z. x: вверх, z: справа: y: впереди.

Я определяю другое поведение между вторыми вращениями.

Для обеспечения согласованности я ждал, что для первой операции второе вращение было около z Или для второй операции второе вращение было вокруг оси x. Почему?

Для меня вторая операция имеет повороты goood, это поведение, которое я хотел бы иметь. Благодарим вас за помощь.

Ниже кода

cube.cpp:

#include <SDL/SDL.h> 
    #include <GL/gl.h> 
    #include <GL/glu.h> 
    #include <cstdlib> 
    #include <iostream> 

    #include "sdlglutils.h" 
    #include "trackballcamera.h" 

    using namespace std; 

    void Dessiner(); 
    double angleZ = 0; 
    double angleX = 0; 
    double angleY = 0; 

    TrackBallCamera * camera; 

    int main(int argc, char *argv[]) 
    { 
    cout<<"in main cube"<<endl; 
    freopen("CON", "w", stdout); 
    freopen("CON", "r", stdin); 
    freopen("CON", "w", stderr); 


    SDL_Event event; 

    SDL_Init(SDL_INIT_VIDEO); 
    atexit(SDL_Quit); 
    SDL_WM_SetCaption("SDL GL Application", NULL); 
    SDL_SetVideoMode(640, 480, 32, SDL_OPENGL); 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    gluPerspective(70,(double)640/480,1,1000); 

    glEnable(GL_DEPTH_TEST); 

    camera = new TrackBallCamera(); 
    camera->setScrollSensivity(10); 

    Dessiner(); 

    Uint32 last_time = SDL_GetTicks(); 
    Uint32 current_time,ellapsed_time; 
    Uint32 start_time; 

    GLUquadric* params; 
    params = gluNewQuadric(); 

    for (;;) 
    { 
     start_time = SDL_GetTicks(); 
     while (SDL_PollEvent(&event)) 
     { 

      switch(event.type) 
      { 
       case SDL_QUIT: 
       exit(0); 
       break; 

       case SDL_MOUSEBUTTONUP: 
       cout<<"SDL_MOUSEBUTTONUP"<<endl; 
       camera->OnMouseButton(event.button); 
       break; 

       case SDL_MOUSEBUTTONDOWN: 
       cout<<"SDL_MOUSEBUTTONDOWN"<<endl; 
       camera->OnMouseButton(event.button); 
       break; 

       case SDL_MOUSEMOTION: 
       camera->OnMouseMotion(event.motion); 
       break; 


      } 
     } 

     current_time = SDL_GetTicks(); 
     ellapsed_time = current_time - last_time; 
     last_time = current_time; 

     //angleZ += 0.05 * ellapsed_time; 
     //angleX += 0.05 * ellapsed_time; 

     Dessiner(); 

     ellapsed_time = SDL_GetTicks() - start_time; 
     if (ellapsed_time < 10) 
     { 
      SDL_Delay(10 - ellapsed_time); 
     } 

    } 

    return 0; 
} 

void dessinerRepere(unsigned int echelle = 10) 
{ 
    //glPushMatrix(); 
    glScalef(echelle,echelle,echelle); 
    glBegin(GL_LINES); 
    glColor3ub(0,0,255); 
    glVertex3i(0,0,0); 
    glVertex3i(1,0,0); 
    glColor3ub(0,255,0); 
    glVertex3i(0,0,0); 
    glVertex3i(0,1,0); 
    glColor3ub(255,0,0); 
    glVertex3i(0,0,0); 
    glVertex3i(0,0,1); 
    glEnd(); 
    //glPopMatrix(); 
} 


void Dessiner() 
{ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 

    //gluLookAt(20,20,20,0,0,0,0,0,1); 

    camera->look(0,0,camera->getDistance() 
       ,0,0,0 
       ,0,1,0); 

    //glRotated(angleZ,0,0,1); 
    //glRotated(angleX,1,0,0); 

    glBegin(GL_QUADS); 

    glColor3ub(255,0,0); //face rouge 
    glVertex3d(1,1,1); 
    glVertex3d(1,1,-1); 
    glVertex3d(-1,1,-1); 
    glVertex3d(-1,1,1); 

    glColor3ub(0,255,0); //face verte 
    glVertex3d(1,-1,1); 
    glVertex3d(1,-1,-1); 
    glVertex3d(1,1,-1); 
    glVertex3d(1,1,1); 

    glColor3ub(0,0,255); //face bleue 
    glVertex3d(-1,-1,1); 
    glVertex3d(-1,-1,-1); 
    glVertex3d(1,-1,-1); 
    glVertex3d(1,-1,1); 

    glColor3ub(255,255,0); //face jaune 
    glVertex3d(-1,1,1); 
    glVertex3d(-1,1,-1); 
    glVertex3d(-1,-1,-1); 
    glVertex3d(-1,-1,1); 

    glColor3ub(0,255,255); //face cyan 
    glVertex3d(1,1,-1); 
    glVertex3d(1,-1,-1); 
    glVertex3d(-1,-1,-1); 
    glVertex3d(-1,1,-1); 

    glColor3ub(255,0,255); //face magenta 
    glVertex3d(1,-1,1); 
    glVertex3d(1,1,1); 
    glVertex3d(-1,1,1); 
    glVertex3d(-1,-1,1); 

    glEnd(); 
    //glLoadIdentity(); 
    dessinerRepere(); 

    glFlush(); 
    SDL_GL_SwapBuffers(); 
} 

trackballcamera.cpp:

#include "trackballcamera.h" 

#include <GL/gl.h> 
#include <GL/glu.h> 
#include <cmath> 
#include "trackballcamera.h" 
#include "sdlglutils.h" 

void TrackBallCamera::setDistance(const double & newDistance) 
{ 
    _distance = newDistance; 
} 

const double & TrackBallCamera::getDistance() const 
{ 
    return _distance; 
} 

TrackBallCamera::TrackBallCamera() 
{ 
    const char *hand1[] = 
     { 
      /* width height num_colors chars_per_pixel */ 
      " 16 16 3 1 ", 
      /* colors */ 
      "X C#000000", 
      ". C#ffffff", 
      " c None", 
      /* pixels */ 
      "  XX  ", 
      " XX X..XXX ", 
      " X..XX..X..X ", 
      " X..XX..X..X X ", 
      " X..X..X..XX.X", 
      " X..X..X..X..X", 
      " XX X.......X..X", 
      "X..XX..........X", 
      "X...X.........X ", 
      " X............X ", 
      " X...........X ", 
      " X..........X ", 
      " X.........X ", 
      " X.......X ", 
      "  X......X ", 
      "  X......X ", 
      "0,0" 
     }; 

    const char *hand2[] = 
     { 
      /* width height num_colors chars_per_pixel */ 
      " 16 16 3 1 ", 
      /* colors */ 
      "X C#000000", 
      ". C#ffffff", 
      " c None", 
      /* pixels */ 
      "    ", 
      "    ", 
      "    ", 
      "    ", 
      " XX XX XX ", 
      " X..X..X..XX ", 
      " X........X.X ", 
      " X.........X ", 
      " XX.........X ", 
      " X...........X ", 
      " X...........X ", 
      " X..........X ", 
      " X.........X ", 
      " X.......X ", 
      "  X......X ", 
      "  X......X ", 
      "0,0" 
     }; 
    _hand1 = cursorFromXPM(hand1); 
    _hand2 = cursorFromXPM(hand2); 
    SDL_SetCursor(_hand1); 
    _holdRotation = false; 
    _holdTranslation = false; 
    _angleX = 0; 
    _angleY = 0; 
    _angleZ = 0; 
    _transX = 0; 
    _transY = 0; 
    _transZ = 0; 
    _distance = 50; 
    _motionSensivity = 0.3; 
    //_scrollSensivity = 1; 
    _scrollSensivity = 10; 
} 

void TrackBallCamera::OnMouseMotion(const SDL_MouseMotionEvent & event) 
{ 
    printf("OnMouseMotion; _holdRotation:%d; _holdTranslation:%d\n", _holdRotation, _holdTranslation); 
    if (_holdRotation) 
    { 
     _angleY += event.xrel*_motionSensivity; 
     _angleX += event.yrel*_motionSensivity; 
     printf("_angleX:%lf; _angleY:%lf\n",_angleX,_angleY); 
//  if (_angleY > 90) 
//   _angleY = 90; 
//  else if (_angleY < -90) 
//   _angleY = -90; 
    } 

    if (_holdTranslation) 
    { 
     _transX += event.xrel*_motionSensivity; 
     _transY += event.yrel*_motionSensivity; 
     printf("_transZ:%lf, _transY:%lf\n",_transZ, _transY); 
    } 

} 

void TrackBallCamera::OnMouseButton(const SDL_MouseButtonEvent & event) 
{ 
    printf("OnMouseButton\n"); 

    if (event.button == SDL_BUTTON_LEFT) 
    { 
     if ((_holdRotation)&&(event.type == SDL_MOUSEBUTTONUP)) 
     { 
      _holdRotation = false; 
      SDL_SetCursor(_hand1); 
     } 
     else if ((!_holdRotation)&&(event.type == SDL_MOUSEBUTTONDOWN)) 
     { 
      _holdRotation = true; 
      SDL_SetCursor(_hand2); 
     } 
     printf("_holdRotation:%d\n",_holdRotation); 
    } 

    else if (event.button == SDL_BUTTON_RIGHT) 
    { 
     if ((_holdTranslation)&&(event.type == SDL_MOUSEBUTTONUP)) 
     { 
      _holdTranslation = false; 
      SDL_SetCursor(_hand1); 
     } 
     else if ((!_holdTranslation)&&(event.type == SDL_MOUSEBUTTONDOWN)) 
     { 
      _holdTranslation = true; 
      SDL_SetCursor(_hand2); 
     } 
    } 

    else if ((event.button == SDL_BUTTON_WHEELUP)&&(event.type == SDL_MOUSEBUTTONDOWN)) 
    { 
     printf("OK WHEELUP, _scrollSensivity:%lf; _distance:%lf\n", _scrollSensivity,_distance); 
     _distance -= _scrollSensivity; 
     //if (_distance < 0.1) 
      //_distance = 0.1; 
     printf("APRES WHEELUP, _distance:%lf\n", _distance); 
    } 
    else if ((event.button == SDL_BUTTON_WHEELDOWN)&&(event.type == SDL_MOUSEBUTTONDOWN)) 
    { 
      printf("OK WHEELDOWN, _distance:%lf\n",_distance); 
      _distance += _scrollSensivity; 
    } 
} 

void TrackBallCamera::OnKeyboard(const SDL_KeyboardEvent & event) 
{ 
    if ((event.type == SDL_KEYDOWN)&&(event.keysym.sym == SDLK_HOME)) 
    { 
     _angleY = 0; 
     _angleX = 0; 
    } 
} 

void TrackBallCamera::setMotionSensivity(double sensivity) 
{ 
    _motionSensivity = sensivity; 
} 

void TrackBallCamera::setScrollSensivity(double sensivity) 
{ 
    _scrollSensivity = sensivity; 
} 

TrackBallCamera::~TrackBallCamera() 
{ 
    SDL_FreeCursor(_hand1); 
    SDL_FreeCursor(_hand2); 
    SDL_SetCursor(NULL); 
} 

//camera->look(cloud.pointPosition[lastElement*3],0,75,cloud.pointPosition[lastElement*3],0,0,0,1,0); 
void TrackBallCamera::look(const GLfloat& xPointOfView 
          ,const GLfloat& yPointOfView 
          ,const GLfloat& zPointOfView 
          ,const GLfloat& xCenter 
          ,const GLfloat& yCenter 
          ,const GLfloat& zCenter 
          ,const GLfloat& xVerticalVector 
          ,const GLfloat& yVerticalVector 
          ,const GLfloat& zVerticalVector 
          ) 

//void TrackBallCamera::look() 
{ 
    //gluLookAt(_distance,0,0, 
       //0,0,0, 
       //0,0,1); 
    //printf("look, xPointOfView:%lf\n",xPointOfView); 
    gluLookAt(xPointOfView,yPointOfView,zPointOfView, 
       xCenter,yCenter,zCenter, 
       xVerticalVector,yVerticalVector,zVerticalVector); 

    glRotated(_angleX,1,0,0); 
    glRotated(_angleY,0,1,0); 
    //glRotated(_angleZ,0,0,1); 
    //glTranslated(_transX,0,0); 
    //glTranslated(0,_transY,0); 
    //glTranslated(0,0,_transZ); 
} 

trackballcamera.h:

#ifndef TRACKBALLCAMERA_H 
#define TRACKBALLCAMERA_H 

#include <SDL/SDL.h> 
#include <GL/gl.h> 

class TrackBallCamera 
{ 
public: 
    TrackBallCamera(); 

    virtual void OnMouseMotion(const SDL_MouseMotionEvent & event); 
    virtual void OnMouseButton(const SDL_MouseButtonEvent & event); 
    virtual void OnKeyboard(const SDL_KeyboardEvent & event); 

    //virtual void look(); 
    virtual void look(const GLfloat& xPointOfView 
          ,const GLfloat& yPointOfView 
          ,const GLfloat& zPointOfView 
          ,const GLfloat& xCenter 
          ,const GLfloat& yCenter 
          ,const GLfloat& zCenter 
          ,const GLfloat& xVerticalVector 
          ,const GLfloat& yVerticalVector 
          ,const GLfloat& zVerticalVector 
          ); 
    virtual void setMotionSensivity(double sensivity); 
    virtual void setScrollSensivity(double sensivity); 

    void setDistance(const double & newDistance); 
    const double & getDistance() const ; 

    virtual ~TrackBallCamera(); 

protected: 
    double _motionSensivity; 
    double _scrollSensivity; 
    //bool _hold; 
    bool _holdRotation; 
    bool _holdTranslation; 
    double _distance; 
    double _angleX; 
    double _angleY; 
    double _angleZ; 
    double _transX; 
    double _transY; 
    double _transZ; 
    SDL_Cursor * _hand1; 
    SDL_Cursor * _hand2; 
}; 

#endif //TRACKBALLCAMERA_H 

sdlglutils.cpp:

#include "sdlglutils.h" 
#include <SDL/SDL.h> 
//#include <SDL/SDL_image.h> 
#include <GL/glu.h> 

#include <cstring> 
#include <cstdlib> 



SDL_Cursor * cursorFromXPM(const char * xpm[]) 
{ 
    int i, row, col; 
    int width, height; 
    Uint8 * data; 
    Uint8 * mask; 
    int hot_x, hot_y; 
    SDL_Cursor * cursor = NULL; 

    sscanf(xpm[0], "%d %d", &width, &height); 
    data = (Uint8*)calloc(width/8*height,sizeof(Uint8)); 
    mask = (Uint8*)calloc(width/8*height,sizeof(Uint8)); 

    i = -1; 
    for (row=0; row<height; ++row) 
    { 
     for (col=0; col<width; ++col) 
     { 
      if (col % 8) 
      { 
       data[i] <<= 1; 
       mask[i] <<= 1; 
      } 
      else 
      { 
       ++i; 
       data[i] = mask[i] = 0; 
      } 
      switch (xpm[4+row][col]) 
      { 
       case 'X': 
       data[i] |= 0x01; 
       mask[i] |= 0x01; 
       break; 
       case '.': 
       mask[i] |= 0x01; 
       break; 
       case ' ': 
       break; 
      } 
     } 
    } 
    sscanf(xpm[4+row], "%d,%d", &hot_x, &hot_y); 
    //printf("data :%" PRIu8 "; mask:%" PRIu8 ";width:%d; height:%d; hot_x:%d; hot_y:%d\n", *data, *mask, width, height, hot_x, hot_y); 
    cursor = SDL_CreateCursor(data, mask, width, height, hot_x, hot_y); 
    free(data); 
    free(mask); 
    return cursor; 
} 

sdlglutils.h:

#ifndef SDLGLUTILS_H 
#define SDLGLUTILS_H 

#include <GL/gl.h> 
#include <SDL/SDL.h> 

SDL_Cursor * cursorFromXPM(const char * xpm[]); 

#endif //SDLGLUTILS_H 

ответ

0

Вы, кажется, работает в классической задаче с Euler Angles, порядок дополнительных вопросов вращениями.

Кроме того, для интуитивного поведения трекбола для 3D-поворота необходимо учитывать, что ось модели и глобальная ось вращения не выровнены, и поэтому, когда вы применяете дельта трекбола к глобальным осям, вращение может быть в неожиданном направлении , Чтобы исправить это, вам необходимо выполнить преобразование координат пользовательского ввода в глобальное пространство или вычислить матрицу вращения в пользовательском пространстве и преобразовать эту матрицу вращения из пространства модели в глобальное пространство, чтобы рендеринг делал правильные вещи.

+0

Thank you dognotdog. Вы знаете, где я могу найти простой пример вашего предложения? –

+0

В этой статье рассматривается множество различных подходов: http: //www.diku.ком/~ каш/документы/DSAGM2002_henriksen.pdf – dognotdog