我正在尝试使用openGL实现轨迹球的基本解决方案。
有2次轮换: - 围绕x轴(右方向),与上/下鼠标移动相关联。 - 围绕y轴(向上方向),与鼠标左右移动相关联。 立方体以0为中心,相机位于z轴上。绘制轴:x为蓝色,y为绿色,z为红色。
2个不同的轮换组:
通过向下移动鼠标在x周围90°。 Z朝下,x右,y在前面。 然后另一个旋转:z周围90°(显示z),鼠标右移。 z朝向正确的方向,x向上和向前y。
我再次处理,位置从头开始。 y°90°。 y:up,z:right,x:在前面 绕z旋转90°。 x:up,z:right:y:在前面。
我确定了第二次轮换之间的不同行为。
为了连贯性,我等待第一次操作,第二次旋转在z附近 或者对于第二次操作,第二次旋转是围绕x轴。 为什么?
对我来说,第二次操作有旋转,这是我想要的行为。 谢谢您的帮助。
代码
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 :(得分:0)
您似乎遇到了Euler Angles的经典问题,增量轮换的顺序很重要。
此外,对于3D旋转的直观轨迹球行为,您需要考虑模型和全局旋转轴未对齐,因此当您将轨迹球增量应用于全局轴时,旋转可能处于意外方向。要解决此问题,您需要将用户输入坐标转换为全局空间,或者在用户空间中计算旋转矩阵,并将旋转矩阵从模型空间转换为全局空间,以便渲染做正确的事情。