Вращение сцены
Когда построена сцена, наложены текстуры, включены источники света, присутствует анимация, кажется, что больше и желать нечего. Однако, вы наблюдаете сцену, все время из одной точки. Вы не видите ее с обратной стороны. Было бы интересно иметь возможность управлять положением камеры или вращать всю сцену целиком. На производительности это никак не скажется, т.к. каждый кадр рассчитывается заново. Для OpenGL все равно, где находится камера или как повернута сцена. В этом параграфе я продемонстрирую, как можно использовать мышь и клавиатуру для управления положением сцены в трехмерном пространстве.
Надо сразу отметить, что передвигать мышью объекты в трехмерном пространстве во всех направлениях с той же легкостью, с которой вы перебрасываете папки на рабочем столе Windows вам не удастся. Связано это с тем, что мышь на экране бегает в двумерном пространстве. И следовательно в вашу программу, как вы знаете, передается только два параметра передвижения мыши - х,у. Но для перемещения объектов в трехмерном пространстве требуется еще и z-координата. По хорошему, еще, конечно, нужен вектор нормали к объекту и угол поворота объекта вокруг вектора нормали. Объект в трехмерном пространстве может быть по-разному ориентирован относительно своего центра. Здесь мы ограничимся только вращением сцены вокруг двух осей координат. Для того чтобы можно было посмотреть на любую точку сцены этого вполне достаточно.
За основу мы возьмем нашего старого знакомого "Снеговика" из первых глав этой книги. Для работы с мышью и клавиатурой воспользуемся функциями библиотеки GLAUX, которая выступает связующим звеном между операционной системой Windows и библиотекой OpenGL. Нам потребуется две глобальных переменных для вращения сцены вокруг двух осей. Глобальными они сделаны потому, что к ним необходим доступ из нескольких разных функций, вообще же старайтесь избегать наличия глобальных переменных и сводите их количество к минимуму. Далее приведен исходный код с комментариями:
int alpha=0, beta=0; // объявляем переменные - углы поворота
// эта функция вызывается всякий раз, когда поступает сообщение от мыши //см. также функцию main, в ней будут установлены функции-обработчики //мыши и клавиатуры void CALLBACK mouse(AUX_EVENTREC *event) { // в этих двух переменных будем хранить старые положения мыши static int x0,y0=-12345; //если в x0, y0 содержаться предыдущие координаты мыши, //то прибавить переменным alpha и beta разницу между //положениями мыши if(y0!=-12345) { alpha += event->data[AUX_MOUSEX] - x0; beta += event->data[AUX_MOUSEY] - y0; } //сохраняем положение мыши x0 = event->data[AUX_MOUSEX]; y0 = event->data[AUX_MOUSEY]; } //функции-обработчики стрелок клавиатуры // с ними вы уже встречались в примерах arcanoid, fog, logicop void CALLBACK Key_LEFT(void) { alpha -= 5; } void CALLBACK Key_RIGHT(void) { alpha += 5; } void CALLBACK Key_UP(void) { beta += 5; } void CALLBACK Key_DOWN(void) { beta -= 5; } // рисуем снеговика void snowman() { glPushMatrix(); glColor3d(0.75,0.75,0.75); glTranslated(0,-3,0); auxSolidSphere(2.0); glTranslated(0,3,0); auxSolidSphere(1.5); glTranslated(0,2,0); auxSolidSphere(1); glColor3d(0,0,0); glTranslated(-0.3,0.3,1); auxSolidSphere(0.1); glTranslated(0.6,0,0); auxSolidSphere(0.1); glTranslated(-0.3,-0.3,0); glColor3d(1,0,0); auxSolidCone(0.3,0.5); glTranslated(0,0.75,-1); glColor3d(0,0,1); glRotated(-90,1,0,0); auxSolidCone(0.75,0.75); glPopMatrix(); } void CALLBACK display(void) { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // сохраняем старое положение сцены glPushMatrix(); //вращаемся вокруг осей Х и Y glRotated(alpha, 0,1,0); glRotated(beta, -1,0,0); snowman(); //возвращаем координату на место glPopMatrix(); auxSwapBuffers(); } void main() { float pos[4] = {3,3,3,1}; float dir[3] = {-1,-1,-1}; GLfloat mat_specular[] = {1,1,1,1}; auxInitPosition( 50, 10, 400, 400); auxInitDisplayMode( AUX_RGB | AUX_DEPTH | AUX_DOUBLE ); auxInitWindow( "Controls" ); auxIdleFunc(display); auxReshapeFunc(resize); glEnable(GL_DEPTH_TEST); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, pos); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialf(GL_FRONT, GL_SHININESS, 128.0); //устанавливаем функции-обработчик клавиатуры и мыши auxKeyFunc(AUX_LEFT, Key_LEFT); auxKeyFunc(AUX_RIGHT, Key_RIGHT); auxKeyFunc(AUX_UP, Key_UP); auxKeyFunc(AUX_DOWN, Key_DOWN); auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSELOC, mouse); auxMainLoop(display); }
Исходный файл смотрите . Исполняемый файл .