Я работаю над проектом FLTK (моя первая попытка графического интерфейса и opengl: пожалуйста, потерпите меня!) И у меня есть Fl_Gl_Window, который отображает различные вещи в зависимости от некоторых других виджетов. Один из вариантов — отображать содержимое экрана в 3D и иметь возможность вращать его в 3D с помощью мыши. В принципе, все в порядке (я использую функции Fl::event в обработчике окна для достижения положения мыши/окна и просто обновляю угол поворота x, y и z, которые применялись в заданном порядке), но то, как я это делал это было неинтуитивно (из-за некоммутирующих вращений и т. д. и т. д.), поэтому я реализую трекбол (похожий на тот, что здесь: http://www.csee.umbc.edu/~squire/download/trackball.c). Я понимаю, как все это работает, и могу заставить его вращаться, как и ожидалось, вдоль правильной оси при первом перетаскивании мышью. Но...
Проблема, насколько я могу судить, заключается в том, что для работы в целом (т.е. с несколькими перетаскиваниями мыши) необходимо поддерживать матрицу просмотра модели, чтобы повернуть объект относительно текущей отображаемой ориентации, чтобы применить glRotatef к нему при каждом перетаскивании мышью. Итак, способ, которым я научился базовому openGL с FLTK, состоит в том, чтобы иметь функцию draw(), которая вызывается всякий раз, когда что-либо изменяется, но это (насколько я могу судить в FLTK и для меня) должно начинаться с нуля каждый раз, когда окно имеет содержимое, которое меняется в зависимости от параметров пользователя (они могут выбрать 2D-вид и т. д. и т. д.), а также позже рисует объекты, которые не предназначены для поворота. Таким образом, я не вижу, как его закодировать, чтобы матрица просмотра модели последовательно обновлялась при каждой перерисовке, как
а) при некоторых перерисовках потребуется по умолчанию вернуться к отсутствию вращения (например, вариант 2D) (но я все же хотел бы «запомнить» вращение 3D-объекта)
б) остальная часть сцены не должна вращаться, поэтому я должен вернуть матрицу к предыдущему glOrtho...
Непосредственные пути вокруг этого, которые я вижу,
1) построить массив всех перетаскиваний мыши и записать соответственно так, чтобы, например, на 10-й перетаскивание мыши применялось 10 вращений через glRotatef (мне это как решение не нравится, некрасиво!)
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
}