Анимация OpenGl и C++

С++ OpenGL

Мы уже научились создавать окно средствами библиотеки OpenGl на С++. Так же разобрали возможности данной связки на форуме. Однако, мы везде рисовали статическую картинку. Пришло время научиться анимации.

Возьмем код из прошлой статьи. В нем нам нужно сделать некоторые изменения. Первое это поменять режим буфера. Для анимации нужно два буфера: буфер графики и буфер расчета. Следовательно в параметрах функции glutInitDisplayMode(); необходимо указать GLUT_DOUBLE|GLUT_RGB. Теперь нас не устраивает функция отображения на экране glFlush();. Она может работать только со статической картинкой. Заменим её на glutSwapBuffers();. На этом настройка окна закончилась. Приступаем к анимации.

[code]
#include<glut.h>
#include<math.h>
#include<stdlib.h>
#include<math.h>

float Wid=600.0;
float Hei=600.0;

void Draw()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINES);
for(float i=-Wid/2; i<=Wid/2; i+=20.0)
{
glVertex2f(i, -Hei/2);
glVertex2f(i, Hei/2);
}
for(float i=-Hei/2; i<=Hei/2; i+=20.0)
{
glVertex2f(-Wid/2, i);
glVertex2f(Wid/2, i);
}
glEnd();
glutSwapBuffers();
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(Wid, Hei);
glutInitWindowPosition(100, 200);
glutCreateWindow("Анимация");
glutDisplayFunc(Draw);
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-Wid/2, Wid/2, -Hei/2, Hei/2, -200.0, 200.0);
glMatrixMode(GL_MODELVIEW);
glutMainLoop();
return 0;
}[/code]

Сетка графика C++

Данный код выводит на белый экран черную сетку. Для анимации нужна отдельная функция.

Создадим её с именем Timer. (void Timer(int value){}) Далее, пропишем её в основной программе glutTimerFunc(50, Timer, 0); первый аргумент — время в миллисекундах, второй — указатель на функцию и 0. Суть анимации это обновление экрана. Мы будем обновлять экран при каждом вызове функции Timer. Можно перерисовывать весь экран функцией  glutPostRedisplay() или можно вызвать просто нашу функцию Draw(). А так же, запустим таймер снова glutTimerFunc(50, Timer, 0);.

Теперь рассмотрим самый простой способ анимации. Пропишем вращение на 1 градус по оси  Z в теле функции Timer (glRotatef(1, 0.0, 0.0, 1.0);).  Все, ваша первая анимация готова.

Но какие же мы программисты, если не усложним себе задачу. И точно такое же вращение зададим другим способом. Удаляем нашу анимацию. Создаем глобальную  переменную float A=0.0; В функции анимации увеличиваем данное значение ++A; .

Сохраняем матрицу glPushMatrix(); после отрисовки восстанавливаем матрицу glPopMatrix(); . Ну и не забываем задать вращение все в той же функции рисования glRotatef(A,0,0,1);.

[code]#include
#include
#include

float Wid=600.0;
float Hei=600.0;
float A=0.0;

void Draw()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 0.0, 0.0);
glPushMatrix();
glRotatef(A,0,0,1);
glBegin(GL_LINES);
for(float i=-Wid/2; i<=Wid/2; i+=20.0)
{
glVertex2f(i, -Hei/2);
glVertex2f(i, Hei/2);
}
for(float i=-Hei/2; i<=Hei/2; i+=20.0)
{
glVertex2f(-Wid/2, i);
glVertex2f(Wid/2, i);
}
glEnd();
glPopMatrix();
glutSwapBuffers();
}

void Timer(int value){
++A;
glutPostRedisplay();
glutTimerFunc(50, Timer, 0);
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(Wid, Hei);
glutInitWindowPosition(100, 200);
glutCreateWindow("Анимация");
glutDisplayFunc(Draw);
glutTimerFunc(50, Timer, 0);
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-Wid/2, Wid/2, -Hei/2, Hei/2, -200.0, 200.0);
glMatrixMode(GL_MODELVIEW);
glutMainLoop();
return 0;
}[/code]

Давайте, еще изменим масштаб нашей фигуры. Создадим переменную s=1.0; в функции рисования запешим такую вот формулу s=1-abs(sin(3.14*A/90)/sqrt(3.0)/1.5); и начнем масштабировать glScalef(s,s,1); по осям Х и У.

Думаю, что еще можно рассказать о том как менять цвет. Удаляем строчку, где мы задавали цвет линий. В функции таймера передаем рандомное число от 0 до 3, вместо 0 (glutTimerFunc(50, Timer, rand() %3);) и ставим конструкцию выбора в функцию таймера.

switch(value){
case 0:glColor3f(1,0,0);
break;
case 1:glColor3f(0,1,0);
break;
case 2:glColor3f(0,0,1);

}

Целиком наш код выглядит так:

[code]#include
#include
#include
#include

float Wid=600.0;
float Hei=600.0;
float A=0.0, s=1.0;

void Draw()
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(A,0,0,1);
s=1-abs(sin(3.14*A/90)/sqrt(3.0)/1.5);
glScalef(s,s,1);
glBegin(GL_LINES);
for(float i=-Wid/2; i<=Wid/2; i+=20.0)
{
glVertex2f(i, -Hei/2);
glVertex2f(i, Hei/2);
}
for(float i=-Hei/2; i<=Hei/2; i+=20.0)
{
glVertex2f(-Wid/2, i);
glVertex2f(Wid/2, i);
}
glEnd();
glPopMatrix();
glutSwapBuffers();
}

void Timer(int value){

switch(value){
case 0:glColor3f(1,0,0);
break;
case 1:glColor3f(0,1,0);
break;
case 2:glColor3f(0,0,1);

}
++A;
glutPostRedisplay();
glutTimerFunc(50, Timer, rand() %3);
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(Wid, Hei);
glutInitWindowPosition(100, 200);
glutCreateWindow("Анимация");
glutDisplayFunc(Draw);
glutTimerFunc(50, Timer, rand() %2);
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-Wid/2, Wid/2, -Hei/2, Hei/2, -200.0, 200.0);
glMatrixMode(GL_MODELVIEW);
glutMainLoop();
return 0;
}
[/code]

Если, нам необходимо делать какие то изменения в другой такт времени. То можно вызвать еще одну функцию таймера.  Описывать изменения в коде не буду. Так как их достаточно много, но все они уже были описаны выше. По сути, мы просто перетащили некоторые части кода, в другой таймер.

[code]
#include<glut.h>
#include<math.h>
#include<stdlib.h>
#include<math.h>

float Wid=600.0;
float Hei=600.0;
float A=0.0, s=1.0;

void Draw()
{
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glRotatef(A,0,0,1);
s=1-abs(sin(3.14*A/90)/sqrt(3.0)/1.5);
glScalef(s,s,1);
glBegin(GL_LINES);
for(float i=-Wid/2; i<=Wid/2; i+=20.0)
{
glVertex2f(i, -Hei/2);
glVertex2f(i, Hei/2);
}
for(float i=-Hei/2; i<=Hei/2; i+=20.0)
{
glVertex2f(-Wid/2, i);
glVertex2f(Wid/2, i);
}
glEnd();
glPopMatrix();
glutSwapBuffers();
}

void Timer(int){
++A;
glutPostRedisplay();
glutTimerFunc(50, Timer, 0);
}

void Timer1(int value){
switch(value){
case 0:glColor3f(1,0,0);
break;
case 1:glColor3f(0,1,0);
break;
case 2:glColor3f(0,0,1);
}
glutPostRedisplay();
glutTimerFunc(1000, Timer1, rand() %3);
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(Wid, Hei);
glutInitWindowPosition(100, 200);
glutCreateWindow("Анимация");
glutDisplayFunc(Draw);
glutTimerFunc(50, Timer, 0);
glutTimerFunc(1000, Timer1, rand() %3);
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-Wid/2, Wid/2, -Hei/2, Hei/2, -200.0, 200.0);
glMatrixMode(GL_MODELVIEW);
glutMainLoop();
return 0;
}
[/code]

 

На этой, достаточно не плохой картинке, думаю, можно закончить первое знакомство с анимацией в OpenGL и C++.

1 Star2 Stars3 Stars4 Stars5 Stars (1 голосов, средний:5,00 из 5)
Вы можете пропустить чтение записи и оставить комментарий. Размещение ссылок запрещено.
Оставить комментарий