2.8 Анимация
Автор: zombieДавайте оживим нашего снеговика и добавим интерактивность. Для этого надо отрисовывать кадры и реагировать на внешние события от клавиатуры или мыши. Для отрисовки кадров их надо как-то различать. Для этого мы в функции display вводим переменную time типа int с модификатором static. Создайте новый проект и в функцию display введите следующее: "static int time=0;". Модификатор static означает, что значение переменной будет сохраняться при выходе из функции. Начальное значение мы устанавливаем в ноль. Если функция display не зависит от времени, то счетчик кадров можно и не вести. Теперь добавьте следующие строчки:
glPushMatrix(); glTranslated( ((double)time)/100.0 ,0,0); ... // здесь код из предыдущего упражнения "Cнеговик" glPopMatrix();
Запустив приложение, вы увидите, что снеговик пополз вдоль оси Х. Вот так вы можете делать анимацию. Т.е. теперь координаты объектов вычисляются в зависимости от времени. Я привел простой пример. Вообще говоря, для программирования сложной графики вам понадобится вычислять координаты каждого отдельного объекта в зависимости от времени.
Далее мы рассмотрим пример с более сложной анимацией. Здесь вращается тор и его ось вращения. Я приведу исходный текст с подробными комментариями. Пример программы "Гироскоп":
Исходный файл смотрите здесь. Исполняемый файл здесь.
glPushMatrix(); // сохраняем текущие координаты, т.к. при выходе // из функции нам нужно вернуться к абсолютным // координатам // попробуйте закомментировать вызов glPushMatrix // здесь и glPopMatrix в конце и вы увидите, что // из этого получится glRotated(time/2, 0.0, 1.0, 0.0); // поворачиваем координаты glLineWidth(5); // устанавливаем толщину линии - пять glColor3f(1,0,0); // устанавливаем текущий цвет - красный glBegin(GL_LINES); // рисуем красную ось glVertex3d(-0.3,0,0); // т.к. мы повернули координаты, glVertex3d(1.5,0,0); // ось будет повернута в абсолютных glEnd(); // координатах, и т.к. функция display // вызывается в цикле, и переменная // time увеличивается на единицу // при каждом вызове display, мы // получаем анимацию - вращающуюся ось glPushMatrix(); // теперь относительно повернутых координат // мы переходим к новым координатам glRotated(2*time, 1,0,0); // поворачиваем их на угол // 2*time вокруг красной оси glTranslated(-0.3,0,0); // и сдвигаем на край оси glColor3f(0,0,1); // устанавливаем синий цвет glPushMatrix(); // теперь еще раз переходим к // новым координатам, glRotated(90,0,1,0); // чтобы развернуть тор на // 90 градусов // у вас крыша еще не поехала? // немного? // то-то же, тут не так все просто, // но если понять что и как, то // очень удобно // программировать графику glLineWidth(1); auxWireTorus(0.2, 0.7); glPopMatrix(); // нарисовав тор, мы возвращаемся // к предыдущим // координатам, если забыли, // начало этих координат // лежит на конце красной оси glLineWidth(7); glColor3f(0,1,0); glBegin(GL_LINES); // теперь рисуем три зеленых линиии glVertex3d(0,0,0); // что тут и как рисуется, я поясню в glVertex3d(0,1,0); // следующей glVertex3d(0,0,0); // главе, сейчас это не так важно glVertex3d(0,-0.5,1); glVertex3d(0,0,0); glVertex3d(0,-0.5,-1); glEnd(); glPopMatrix(); // теперь возвращаемся к повернутым // координатам на угол time/2 glPopMatrix(); // ну и переходим к абсолютным координатам time++; // увеличиваем счетчик кадров или вермя, // называйте как хотите, // на единицу
Как вы, наверное, догадались, надо создать очередной проект, скопировать туда мой шаблон, добавить его в проект, указать библиотеки opengl32.lib glu32.lib glaux.lib в Project->Setting->Link->Settings->Link->Object/library modules:, вставить этот код в функцию display. Еще вам нужно в начале функции display вставить строку static int time=0; и закомментировать строчку glEnable(GL_LIGHTING) в функции main.
Запустив это приложение, вы увидите, как оно работает. Теперь закомментируйте соответсвующие друг другу вызовы glPushMatrix и glPopMatrix и посмотрите на результат. Я бы рекомендовал такой способ для изучения и понимания работы программы: вы комментируете куски кода и смотрите, что получается.
Для того, чтобы реагировать на клавиатуру или мышь, вы должны определить функцию, которая будет вызываться при поступление событий от клавиатуры или мыши. Для кнопки клавиатуры вы определяете функцию со следующим прототипом void CALLBACK FunctionName(void) и устанавливаете ее как обработчик определенной кнопки - auxKeyFunc(key_code, FunctionName); key_code смотри в glaux.h. Пример: auxKeyFunc(AUX_LEFT, FunctionName) Здесь вы устанавливаете FunctionName как функцию, которая будет вызываться при нажатии на клавиатуре клавиши "стрелка влево".
Для мыши вы устанавливаете свою функцию обработки событий мыши вызовом функции auxMouseFunc(int button,int action,AUXMOUSEPROC). Переменная button может принимать значения - AUX_LEFTBUTTON, AUX_MIDDLEBUTTON, AUX_RIGHTBUTTON. Переменная action принимает следующие значения - AUX_MOUSEDOWN, AUX_MOUSEUP, AUX_MOUSELOC. Функция AUXMOUSEPROC должна иметь прототип - void CALLBACK FunctionName(AUX_EVENTREC *event), где AUX_EVENTREC определено как
typedef struct _AUX_EVENTREC { GLint event; GLint data[4]; }AUX_EVENTREC;
Для более детальной информации смотрите справочные руководства и исходные тексты библиотеки OpenGL Auxiliary library. Эта книга об OpenGL, а не о программировании интерфейсов пользователя. Поэтому, за подобной информацией вам придется лезть в соответсвующие справочные руководства по Win API, MFC, Java и т.п.
В FunctionName вы можете изменить какую-нибудь глобальную переменную, и соответственно, функция display будет рисовать кадры в зависимости от этой переменной.