Introdução à OpenGL
Professora Isabel Harb Manssour

[Anterior]  [Próxima]  [Principal]

 

11. Animação com OpenGL e GLUT

Para exemplificar como fazer uma animação, como por exemplo mover ou girar objetos, será retomado o exemplo do capítulo 8, que desenha um quadrado numa janela com fundo preto. Agora, o quadrado será movido numa direção até bater em uma das bordas da janela e então mudar de direção.

É possível criar um laço que continuamente altera as coordenadas do objeto antes de chamar a função "Desenha". Isto daria a impressão de que o quadrado se move na janela. Porém, a biblioteca GLUT fornece a possibilidade de registrar uma função callback que torna mais fácil o processo de fazer uma simples animação. A função glutTimerFunc pega o nome da função callback que deve ser chamada e o tempo que ela deve esperar antes de chamar a função. A seguir é apresentado o código do exemplo de animação, e na seqüência as novas funções utilizadas são descritas [Wright 2000].

// Anima.c - Isabel H. Manssour
// Um programa OpenGL simples que mostra a animação 
// de quadrado em  uma janela GLUT.
// Este código está baseado no Bounce.c, exemplo 
// disponível no livro "OpenGL SuperBible", 
// 2nd Edition, de Richard S. e Wright Jr.

#include <windows.h>
#include <gl/glut.h>

// Tamanho e posição inicial do quadrado
GLfloat x1 = 100.0f;
GLfloat y1 = 150.0f;
GLsizei rsize = 50;                                                    

// Tamanho do incremento nas direções x e y 
// (número de pixels para se mover a cada
// intervalo de tempo)
GLfloat xstep = 1.0f;
GLfloat ystep = 1.0f;

// Largura e altura da janela
GLfloat windowWidth;
GLfloat windowHeight;


// Função callback chamada para fazer o desenho
void Desenha(void)
{
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
                   
     // Limpa a janela de visualização com a cor de fundo especificada
     glClear(GL_COLOR_BUFFER_BIT);

     // Especifica que a cor corrente é vermelha
     //         R     G     B
     glColor3f(1.0f, 0.0f, 0.0f);
  
     // Desenha um quadrado preenchido com a cor corrente
     glBegin(GL_QUADS);
               glVertex2i(x1,y1+rsize); 
               glVertex2i(x1,y1);
               // Especifica que a cor corrente é azul
               glColor3f(0.0f, 0.0f, 1.0f);
               glVertex2i(x1+rsize,y1);
               glVertex2i(x1+rsize,y1+rsize);               
     glEnd();

     // Executa os comandos OpenGL
     glutSwapBuffers();
}

// Função callback chamada pela GLUT a cada intervalo de tempo
// (a window não está sendo redimensionada ou movida)
void Timer(int value)
{
    // Muda a direção quando chega na borda esquerda ou direita
      if(x1 > windowWidth-rsize || x1 < 0)
            xstep = -xstep;

    // Muda a direção quando chega na borda superior ou inferior
    if(y1 > windowHeight-rsize || y1 < 0)
          ystep = -ystep;
          
    // Verifica as bordas.  Se a window for menor e o 
    // quadrado sair do volume de visualização 
   if(x1 > windowWidth-rsize)
         x1 = windowWidth-rsize-1;

   if(y1 > windowHeight-rsize)
         y1 = windowHeight-rsize-1;

    // Move o quadrado
    x1 += xstep;
    y1 += ystep;

    // Redesenha o quadrado com as novas coordenadas 
    glutPostRedisplay();
    glutTimerFunc(33,Timer, 1);
}

// Inicializa parâmetros de rendering
void Inicializa (void)
{   
    // Define a cor de fundo da janela de visualização como preta
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}

// Função callback chamada quando o tamanho da janela é alterado 
void AlteraTamanhoJanela(GLsizei w, GLsizei h)
{
     // Evita a divisao por zero
     if(h == 0) h = 1;
                           
     // Especifica as dimensões da Viewport
     glViewport(0, 0, w, h);

     // Inicializa o sistema de coordenadas
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();

     // Estabelece a janela de seleção (left, right, bottom, top)     
     if (w <= h)  {
		windowHeight = 250.0f*h/w;
		windowWidth = 250.0f;
     }
     else  { 
		windowWidth = 250.0f*w/h;
		windowHeight = 250.0f;
     }
     
     gluOrtho2D(0.0f, windowWidth, 0.0f, windowHeight);
}

// Programa Principal 
int main(void)
{
     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
     glutInitWindowSize(400,350);
     glutInitWindowPosition(10,10);
     glutCreateWindow("Anima");
     glutDisplayFunc(Desenha);
     glutReshapeFunc(AlteraTamanhoJanela);
     glutTimerFunc(33, Timer, 1);
     Inicializa();
     glutMainLoop();
}

Obs.: Clique aqui para fazer o download deste programa.

  • glutTimerFunc(33, Timer, 1); estabelece a função Timer previamente definida como a função callback de animação. Seu protótipo é: void glutTimerFunc(unsigned int msecs, void (*func)(int value), int value);. Esta função faz a GLUT esperar msecs milisegundos antes de chamar a função func. É possível passar um valor definido pelo usuário no parâmetro value. Como esta função é "disparada" apenas uma vez, para se ter uma animação contínua é necessário reinicializar o timer novamente na função Timer.

  • void Timer(int value) é a função chamada pela glutTimerFunc. No exemplo, as variáveis utilizadas para determinar a posição do retângulo são atualizadas nesta função.

Antes de prosseguir com a descrição das funções, é necessário explicar o funcionamento do double-buffering, que é uma das características mais importantes em qualquer pacote gráfico que está disponível na GLUT. Double-buffering permite que um desenho seja exibido na tela enquanto está sendo realizado o rendering em um offscreen buffer. Então, um comando de swap coloca a imagem na tela instantaneamente. Isto é útil, principalmente, por dois motivos:
- Alguns desenhos complexos podem levar um certo tempo para serem feitos, e não é desejado que cada passo da composição da imagem seja visível; então, é possível compor uma imagem e exibi-la somente depois de completa, de maneira que o usuário nunca vê uma imagem parcial, pois ela é exibida somente quando está pronta.
- No caso de uma animação, cada quadro (ou frame) é desenhado no offscreen buffer e é exibido (swapped) rapidamente depois de pronto.

  • glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB), já explicada anteriormente, foi usada para trocar o modo de exibição de GLUT_SINGLE para GLUT_DOUBLE. Isto faz com que todo o rendering seja feito em um offscreen buffer.

  • glutSwapBuffers(); é usada no lugar da glFlush porque quando é feita a troca (ou swap) de buffers, é realizada implicitamente uma operação de flush. Esta função continua fazendo o flush mesmo que o programa esteja sendo executado no modo single-buffer, porém com uma qualidade bastante inferior [Wright 2000].

 ../Imagens/emban15.png (1469 bytes)

../Imagens/E-MAIL.JPG (3237 bytes) Comentários, dúvidas, sugestões, envie um mail para [email protected]

../Imagens/emban15.png (1469 bytes)

[Anterior]  [Próxima]  [Principal]

Última alteração em 27 de março de 2003.