Computação Gráfica II

Trabalho Prático

Exercícios



6. Animação

Neste exercício veremos como animar objetos 3D e câmeras em OpenGL.

1. Vai-e-vem do Cubo

Animar um objeto consiste em mudar algumas de suas propriedade ao longo do tempo.


Fig. 1 - Animação de um cubo rebatendo entre duas paredes.

Primeiro, precisamos definir quais parâmetros iremo variar. Para o cubo da figura 1 iremos variar a coordenada x.

Para isso, criamos uma variável global X e uma variação delta:

float X = -20;
float delta = 0.4;

Agora, temos que associar X ao tempo. Com a GLUT, usaremos a função glutTimerFunc:

void glutTimerFunc(unsigned int msecs, void (*func)(int value), value);

Ela tem que ser chamada uma vez na init() para estabelecer qual função timer será usada, como por exemplo:

void init()
{
  glClearColor(0,0,0,0);
  glClearDepth(1.0);           // Enables Clearing Of The Depth Buffer
  setupRC();
  glutTimerFunc(33, TimerFunction, 1 ); // 33 ms
}

TimerFunction é uma função chamada automaticamente que definiremos depois. Ela é a função que vai fazer a variável X variar ao longo do tempo.

void TimerFunction( int value ){

  if( X < -10 ) delta = 0.4;
  if( X > 10 ) delta = -0.4;

  X += delta;

  glutPostRedisplay();
  glutTimerFunc( 33, TimerFunction, 1);
}

Neste exemplo usamos a seguinte função de display. Perceba que a variável X é usada para transladar o cubo.

void display(void)
{

  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Clear the colour and depth buffer

  glLoadIdentity(); // Clear matrix stack
 
  gluLookAt(30,40,80,0,0,0,0,1,0);
 
  // Draw plane
  glPushMatrix();
    glScalef(100,100,100);
    drawPlane();
  glPopMatrix();

  // DRAW CUBE
  glPushMatrix();
    glTranslated( X, 7.5, 0 );
    glScalef(15.0,15.0,15.0);
    drawCube();
  glPopMatrix();
 
  // DRAW WALLS
  glPushMatrix();
    glTranslated( -20, 7.5, 0 );
    glScalef(2.0,20.0,50.0);
    drawCube();
  glPopMatrix();

  glPushMatrix();
    glTranslated( 20, 7.5, 0 );
    glScalef(2.0,20.0,50.0);
    drawCube();
  glPopMatrix();

  glFlush();  // Makes sure that we output the model to the graphics card
 
}

 

2 ) Double-buffering

Se a imagem estiver piscando durante a animação, tem que usar bufferização dupla, que consiste em renderizar para um buffer intermediário e depois rapidamente substituir a imagem atual da viewport por aquela do buffer.

Neste caso:

1. Mudar glutInitDisplayMode para ativar o double buffering:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

2. No final da display(), substituir glFlush() por glutSwapBuffers :

//glFlush();
  glutSwapBuffers();

 

3) Pêndulo

Neste outro exemplo, usaremos uma função que descreve o movimento do pêndulo (ver figura 2). Neste caso, o parâmetro que modificamos é o ângulo de rotação que dá a orientação do pêndulo.


Fig. 2- Animação de um pêndulo.

Primeiro definimos as variáveis globais :

float angle = 0; // roataion angle
float T = 0; // global time

A função timer agora é um pouco diferente...

void TimerFunctionPendulum( int value ) {

  T++;

  if( T == 180 ) T = 0; // mouvement périodique

  angle = sin(T*PI/90)*45; // calcul de l'angle de manière réaliste

  glutPostRedisplay();
  glutTimerFunc( 33, TimerFunctionPendulum, 1);
}
// don't forget to include math.h and to define the value of PI

... e aqui está a nova display():

void display(void)
{
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Clear the colour and depth buffer

  glLoadIdentity(); // Clear matrix stack
 
  // We set the camera in position 50,50,100 and we look at origo
  gluLookAt(30,40,80,0,5,0,0,1,0);
 
  // Draw plane
  glPushMatrix();
    glScalef(100,100,100);
    drawPlane();
  glPopMatrix();

  // DRAW PENDULUM
  glPushMatrix();

  glTranslated( 0, 30, 0 );
  glRotated( angle, 0, 0, 1 );
  glTranslated( 0, -30, 0 );
  glPushMatrix();
    glTranslated( 0, 7.5, 0 );   
    glScalef(8.0,8.0,8.0);
    drawCube();
  glPopMatrix();
  glPushMatrix();
    glTranslated( 0, 15, 0 );
    glScalef(2.0,30.0,2.0);
    drawCube();
  glPopMatrix();

  glPopMatrix();
 
  //glFlush();  // Makes sure that we output the model to the graphics card
  glutSwapBuffers();
}

 

4 ) Animando a câmera

Vejamos agora como animar a câmera ao invés dos objetos.

Primeiro declaramos algumas variáveis e constantes globais:

#define y_min 60
#define ro_min 120
float eyex = 0;
float eyey = y_min;
float eyez = ro_min; // eyex, eye, eyez will go in the gluLookAt()
//
of display()

Depois a função que altera os parâmetros da câmera:

void TimerCamera( int value ){

float ro;
value++;

if( value == 720 ) value = 0;

ro = ro_min - sin(value/2.0*PI/360)*ro_min*0.8;
eyey = y_min - sin(value/2.0*PI/360)*y_min*0.8;
eyex = ro * sin(value/2.0*PI/180);
eyez = ro * cos(value/2.0*PI/180);

glutPostRedisplay();
glutTimerFunc( 33, TimerCamera, value);
// notice the difference in this call to the previous one
// the time is passed as a parameter (value)
}

Sem esquecer de chamá-la na init() com valor 0:

glutTimerFunc(33, TimerCamera, 0 );

 

5 ) Todos juntos

Para terminar, colocamos todos os exemplos anteriores em uma única cena (cubo, pêndulo e movimento da câmera) como na figura 3.


Fig. 3 - Cubo, pêndulo e movimento da câmera em uma única cena.