我正在开发一个 FLTK 项目(我第一次尝试 GUI 和 opengl:请多多包涵!)并且有一个 Fl_Gl_Window,它根据其他一些小部件显示各种内容。选项之一是以 3D 显示屏幕内容并让用户能够使用鼠标以 3D 旋转它。原则上一切都很好(我在窗口处理程序中使用 Fl::event 函数来实现鼠标/窗口位置,并简单地更新了按给定顺序应用的 x、y 和 z 旋转角度),但是我正在做的方式这是不直观的(因为非通勤轮换等)所以我正在实现一个轨迹球(类似于这里的那个:http ://www.csee.umbc.edu/~squire/download/trackball.c)。我了解这一切是如何工作的,并且可以通过第一次鼠标拖动使其沿正确的轴按预期旋转。但...
问题是,据我所知,为了正常工作(即多次鼠标拖动),必须维护模型视图矩阵,以便相对于当前显示的方向旋转对象,以便应用 glRotatef每次鼠标拖动它。现在,我用 FLTK 学习了一些基本的 openGL 的方法是有一个 draw() 函数,每当有任何变化时都会调用它,但这(据我在 FLTK 和对我来说)每次都必须从头开始该窗口的内容会根据用户选项而变化(他们可能会选择 2D 视图等),并且稍后还会绘制不打算旋转的内容。因此,我看不到如何对其进行编码,以便模型视图矩阵随着每次重绘而连续更新为
a) 在某些重绘时,它需要默认恢复为无旋转(例如 2D 选项)(但我仍然想“记住”3D 对象的旋转)
b) 场景的其余部分不会被旋转,所以我必须将矩阵弹出回之前的 glOrtho...
我能看到的直接方法是
1)构建所有鼠标拖动的数组并相应地记录,例如,在第 10 次鼠标拖动时,通过 glRotatef 应用 10 次旋转(我不喜欢这样的解决方案,它很难看!)
2)记录模型视图矩阵的状态,并在适当的时候保存和加载。(我读过的东西表明这不是 openGL 应该如何使用的?)
3)找到一个能够减少的数学变换
glRotatef(ang1,ax1_1,ax2_1,ax3_1);
glRotatef(ang2,ax1_2,ax2_2,ax3_2);
进入
glRotatef(ang_tot,ax1_tot,ax2_tot,ax3_tot);
这个解决方案将是最......令人愉悦的。
(伪)代码:
class MyGl : public Fl_Gl_Window {
void draw();
int handle(int);
void map_to_trackball(double*);
void calc_rotation();
//data including:
double old_vec[3];//old mouse position on hemisphere
double new_vec[3];//new mouse position on hemisphere
double ang; //rotation amount;
double rot[3]; //axis of rotation information
public:
MyGl(int X, int Y, int W, int H, const char *L): Fl_Gl_Window(X, Y, W, H, L) {
//constructor...
ang=0;rot[0]=0;rot[1]=0;rot[2]=0;
}
}
void MyGl::draw(){
if (3D){
glLoadIdentity();
glViewport(0,0,w(),h());
glOrtho(minx,maxx,miny,maxy,minz,maxz);
glPushMatrix();
glRotatef(ang,rot[0],rot[1],rot[2]);
//could save previous rotations and put them here ie:
// glRotatef(ang_old,rot_old[0],rot_old[1],rot_old[2]);
// seems clunky and would require a limitless number of rotations and memory if
// the user keeps tracking
draw_object(); //including glBegin(), glVertex3f() and glEnd() etc.
glPopMatrix();
// draw other non rotated things
}
}
int MyGl::handle(int e){
switch(e){
case: MOUSE_DOWN
map_to_trackball(old_vec);//projects starting mouse position onto hemisphere
//if recording all old rotations for successive implementation in draw()
// would save them here.
return 1; //<-- needed in FLTK to recognise drag event
case: DRAG (//pseudocode
map_to_trackball(new_vec);//projects current dragged mouse
//position onto hemisphere
calc_rotation(); //calculates and sets ang and rot[3]
//using old_vec and new_vec
break;
}
return Fl_Gl_Window::handle(e);
}
void map_to_trackball(double* v){
// basically trackball_ptov() from http://www.csee.umbc.edu/~squire/download/trackball.c
}
void calc_rotation(){
// basically mouseMotion() from http://www.csee.umbc.edu/~squire/download/trackball.c
}