Conheça a iniciativa da Biblioteca dos Desenvolvedores  
Índice da Biblioteca  
Área dos Usuários  
Fórum de Discussão  
Forúm
 
  40 - Movimentando e transformando

Agora que sabemos como escrever na tela, podemos aprender as duas funções que ainda faltam na OpenGL.

Primeiro vamos ver como movimentar um cubo 3D.
Você deve estar pensando, não é só alterar os parâmetros x, y e z na hora de imprimir os pontos ?

Sim, podemos fazer isto, mais seria uma tarefa ardua.
A OpenGL possui uma função chamada glTranslatef que faz a movimentação e imprime os pontos no local correto para a gente,
evitando uma trabalhera.

void glTranslatef( GLfloat x, GLfloat y, GLfloat z);
Esta função produz uma translação ( Movimentação ). A matriz atual é multiplicada pela matriz de translação que usa os parâmetros passados para a função.


VOCÊ PRECISA SABER...

Para entender este capítulo e seus códigos, é importante ter lido os conteúdos citados abaixo:

- Utilizando teclado com GLUT

39 - Escrevendo na tela com AllegroGL e GLUT
38 - Extruturando um Objeto 3D


 

 

O código a seguir mostra como movimentar um cubo 3D ( que gira sobre seu proprio eixo ) nos eixos X e Y usando o AllegroGL
Teste o programa usando as teclas direcionais.


CÓDIGO...
// Exemplo de como movimentar um cubo ( que gira sobre seu eixo ) em AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 05/11/2007

#include <allegro.h>
#include <alleggl.h>

int main()
{
   // Iniciações básicas da Allegro
   allegro_init();
   install_keyboard();
   
   // Iniciação da AllegroGL
   install_allegro_gl();
   
   allegro_gl_set(AGL_Z_DEPTH, 8);
   allegro_gl_set(AGL_COLOR_DEPTH, 16);
   allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);
   
   // Setando o Modo Gráfico
   set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);
   
   // Criando uma FONT para poder escrever na tela as variáveis X e Y
   FONT *agl_font = NULL;
   glEnable(GL_TEXTURE_2D);
   agl_font = allegro_gl_convert_allegro_font(font, AGL_FONT_TYPE_TEXTURED, 250.0f);
   
   
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
   // Iniciando a camera
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);
   
   
   glShadeModel( GL_SMOOTH );
   
   // Faz a OpenGL aceitar profunidade
   glClearDepth( 1.0f );
   glEnable( GL_DEPTH_TEST );
   glDepthFunc(GL_LEQUAL);
   
   // Maior qualidade nos gráficos
   glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
   
   glLoadIdentity();
   
   // Angulo para fazer o quadrado girar
   GLfloat angulo;
   angulo = 0.0f;
   
   // Posições X e Y do quadrado
   GLfloat x;
   GLfloat y;
   
   // variáveis temporárias
   GLfloat x_atual;
   GLfloat y_atual;
   
   
   // Iniciamos todas
   x = y = x_atual = y_atual = 0.0f;
   
   // Buffer de teclado
   int buffer_teclado = 0;
   const int iCiclo = 30;
   
   
   
   // Laço principal
   while( !key[KEY_ESC] )
   {   
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glLoadIdentity();
   
   
      if(buffer_teclado == 0)
      {
         
         if ( key[KEY_LEFT] )
         {
            x -= 100;
            buffer_teclado = iCiclo;
         }
      
         if ( key[KEY_RIGHT] )
         {
            x += 100;
            buffer_teclado = iCiclo;
         }
      
         if ( key[KEY_UP] )
         {
            y += 100;
            buffer_teclado = iCiclo;
         }
         
         if ( key[KEY_DOWN] )
         {
            y -= 100;
            buffer_teclado = iCiclo;
         }
   
   
      }
      else
      {
         buffer_teclado--;
      }
   
   
      // Imprimimos as variaveis X e Y
      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      
      allegro_gl_printf(agl_font, -0.9f, 0.9f, 0.0f, makecol( 000, 255, 000), "Variavel X: %f", x );
      allegro_gl_printf(agl_font, -0.9f, 0.8f, 0.0f, makecol( 000, 255, 000), "Variavel Y: %f", y );
      
      
      allegro_gl_printf(agl_font, -0.9f, 0.7f, 0.0f, makecol( 000, 255, 000), "Objeto X: %f", x_atual );
      allegro_gl_printf(agl_font, -0.9f, 0.6f, 0.0f, makecol( 000, 255, 000), "Objeto Y: %f", y_atual );
      
      // atualiza a variavel do objeto de acordo com o X e Y
      x_atual = x / 640;
      y_atual = y / 480;
   
   
   
      // Posiciona o próximo objeto
      glTranslatef( x_atual, y_atual, 0 );
      
      
      // Rotaciona o próximo objeto
      glRotatef(angulo, 1.0f, 1.0f, 1.0f );
      
      
      // Imprime o CUBO
      glBegin(GL_QUADS);
      
      // face da frente
      glColor3f( 255, 0 , 0 );
      glVertex3f( 0.00, 0.00, 0.00 );
      glVertex3f( 0.00, 0.30, 0.00 );
      glVertex3f( 0.30, 0.30, 0.00 );
      glVertex3f( 0.30, 0.00, 0.00 );
      
      
      // face de traz
      glColor3f( 0, 255 , 0 );
      glVertex3f( 0.00, 0.00, 0.30 );
      glVertex3f( 0.00, 0.30, 0.30 );
      glVertex3f( 0.30, 0.30, 0.30 );
      glVertex3f( 0.30, 0.00, 0.30 );
      
      // face de cima
      glColor3f( 255, 255 , 255 );
      glVertex3f( 0.00, 0.30, 0.00 );
      glVertex3f( 0.00, 0.30, 0.30 );
      glVertex3f( 0.30, 0.30, 0.30 );
      glVertex3f( 0.30, 0.30, 0.00 );
      
      // face de baixo
      glColor3f( 255, 255 , 0 );
      glVertex3f( 0.00, 0.00, 0.00 );
      glVertex3f( 0.00, 0.00, 0.30 );
      glVertex3f( 0.30, 0.00, 0.30 );
      glVertex3f( 0.30, 0.00, 0.00 );
      
      // face da esquerda
      glColor3f( 0, 0, 255 );
      glVertex3f( 0.00, 0.00, 0.00 );
      glVertex3f( 0.00, 0.30, 0.00 );
      glVertex3f( 0.00, 0.30, 0.30 );
      glVertex3f( 0.00, 0.00, 0.30 );
      
      // face da direita
      glColor3f( 255, 0, 255 );
      glVertex3f( 0.30, 0.00, 0.00 );
      glVertex3f( 0.30, 0.30, 0.00 );
      glVertex3f( 0.30, 0.30, 0.30 );
      glVertex3f( 0.30, 0.00, 0.30 );
      
      
      glEnd();
         
      // imprime tudo
      allegro_gl_flip();
      
      angulo += 0.2f;
   
   }
   
   allegro_exit();

   return 0;
}
END_OF_MAIN();
   


FIM DE CÓDIGO...

O código acima é auto-explicativo .
Sempre que apertamos as teclas direcionais, o objeto irá se movimentar no plano (x,y).
Eu coloquei ele girando em seu próprio eixo para demonstrar a diferença entre as funções.

O código a seguir mostra como movimentar um cubo 3D ( que gira sobre seu proprio eixo ) nos eixos X e Y usando o GLUT


CÓDIGO...
// Exemplo de como movimentar um cubo ( que gira sobre seu eixo ) em GLUT
// Autor: Adriano Waltrick
// BDJogos
// Data: 20/11/2007

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <GL/glut.h>
#include <stdlib.h>

// Prototipos das funções que serão chamadas pela Glut ( Callback )
static void display(void);
static void key(unsigned char key, int x, int y);
static void EspecialKey(int key, int x, int y);
static void idle(void);
static void resize(int width, int height);
void DesenhaTexto( char *string, float x, float y );

// Angulo para fazer o quadrado girar
GLfloat angulo;

// Posições X e Y do quadrado
GLfloat x;
GLfloat y;

// variáveis temporárias
GLfloat x_atual;
GLfloat y_atual;

// Texto a ser desenhado
char texto[30];


// Main padrão, o programa inicia aqui
int main(int argc, char *argv[])
{
   glutInit(&argc, argv);
   glutInitWindowSize(640,480);
   glutInitWindowPosition(10,10);
   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
   
   glutCreateWindow("Programa Base");
   
   // iniciamos os valores
   ::angulo = 0.0f;
   ::x = ::y = ::x_atual = ::y_atual = 0;
   
   // iniciamos texto
   strcpy(texto, "");
   
   
   // callbacks
   glutReshapeFunc(resize);
   glutDisplayFunc(display);
   glutKeyboardFunc(key);
   glutSpecialFunc(EspecialKey);
   glutIdleFunc(idle);
   
   
   glClearColor(0,0,0,0);
   glutMainLoop();
   
   return EXIT_SUCCESS;
}

// Função que é chamada quando a janela é redimencionada
static void resize(int width, int height)
{
   const float ar = (float) width / (float) height;
   
   glViewport(0, 0, width, height);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
   
   
   
   glShadeModel( GL_SMOOTH );
   
   // Faz a OpenGL aceitar profunidade
   glClearDepth( 1.0f );
   glEnable( GL_DEPTH_TEST );
   glDepthFunc(GL_LEQUAL);
   
   // Maior qualidade nos gráficos
   glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
   
   glLoadIdentity();
}

// Função que é chamada quando for preciso mostrar ou atualizar a tela
static void display(void)
{
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
   glLoadIdentity();
   
   
   glColor3d( 0, 255, 0 );
   sprintf( texto, "Variavel X: %f", ::x);
   DesenhaTexto( texto, -0.9f, 0.9f );
   
   sprintf( texto, "Variavel Y: %f", ::y);
   DesenhaTexto( texto, -0.9f, 0.8f );
   
   sprintf( texto, "Cubo X: %f", ::x_atual);
   DesenhaTexto( texto, -0.9f, 0.7f );
   
   sprintf( texto, "Cubo Y: %f", ::y_atual);
   DesenhaTexto( texto, -0.9f, 0.6f );
   
   
   // atualiza a variavel do objeto de acordo com o X e Y
   ::x_atual = ::x / 640;
   ::y_atual = ::y / 480;
   
   
   // Posiciona o próximo objeto
   glTranslatef( ::x_atual, ::y_atual, 0 );
   
   
   // função de rotação, estamos rotacionando em todos os ângulos
   glRotatef(::angulo, 1.0f, 1.0f, 1.0f );
   
   
   glBegin(GL_QUADS);
   
   // face da frente
   glColor3f( 255, 0 , 0 );
   glVertex3f( 0.00, 0.00, 0.00 );
   glVertex3f( 0.00, 0.30, 0.00 );
   glVertex3f( 0.30, 0.30, 0.00 );
   glVertex3f( 0.30, 0.00, 0.00 );
   
   // face de traz
   glColor3f( 0, 255 , 0 );
   glVertex3f( 0.00, 0.00, 0.30 );
   glVertex3f( 0.00, 0.30, 0.30 );
   glVertex3f( 0.30, 0.30, 0.30 );
   glVertex3f( 0.30, 0.00, 0.30 );
   
   // face de cima
   glColor3f( 255, 255 , 255 );
   glVertex3f( 0.00, 0.30, 0.00 );
   glVertex3f( 0.00, 0.30, 0.30 );
   glVertex3f( 0.30, 0.30, 0.30 );
   glVertex3f( 0.30, 0.30, 0.00 );
   
   // face de baixo
   glColor3f( 255, 255 , 0 );
   glVertex3f( 0.00, 0.00, 0.00 );
   glVertex3f( 0.00, 0.00, 0.30 );
   glVertex3f( 0.30, 0.00, 0.30 );
   glVertex3f( 0.30, 0.00, 0.00 );
   
   // face da esquerda
   glColor3f( 0, 0, 255 );
   glVertex3f( 0.00, 0.00, 0.00 );
   glVertex3f( 0.00, 0.30, 0.00 );
   glVertex3f( 0.00, 0.30, 0.30 );
   glVertex3f( 0.00, 0.00, 0.30 );
   
   // face da direita
   glColor3f( 255, 0, 255 );
   glVertex3f( 0.30, 0.00, 0.00 );
   glVertex3f( 0.30, 0.30, 0.00 );
   glVertex3f( 0.30, 0.30, 0.30 );
   
   glVertex3f( 0.30, 0.00, 0.30 );
   
   
   glEnd();
   
   ::angulo += 0.2f;
   
   glutSwapBuffers();
}

// Função que é chamada quando uma tecla é apertada
static void key(unsigned char key, int x, int y)
{
   switch (key)
   {
      // caso aperte ESC
      case 27 :
      exit(0);
      break;
   }
   
   glutPostRedisplay();
}

// Função que executa rotinas padrões da Glut
static void idle(void)
{
   glutPostRedisplay();
}


static void EspecialKey(int key, int x, int y)
{
   switch (key)
   {
      case GLUT_KEY_UP: // Caso direcional para CIMA - Aumenta valor de vy
      {
         ::y += 100;         
      }
      break;
      
      case GLUT_KEY_DOWN: // Caso direcional para BAIXO - Diminui valor de vy
      {
         ::y -= 100;          
      }
      break;
      
      case GLUT_KEY_LEFT:
      {
         ::x -= 100;          
      }
      break;
      
      case GLUT_KEY_RIGHT:
      {
         ::x += 100;         
      }
      break;
   }

}


void DesenhaTexto(char *string, float x, float y)
{
   glPushMatrix();
   
   // Posição no universo onde o texto será colocado
   glRasterPos2f(x, y);
   
   
   // Exibe caracter a caracter
   while(*string)
   {
      glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10,*string++);
   }
   
   glPopMatrix();
}



FIM DE CÓDIGO...

O exemplo do GLUT é muito importante!
Observe que nele usamos a nova função, usamos a função de escrever na tela e as funções de manipulação de teclado.
O restante do código é muito parecido com o do AllegroGL, entender a abordagem prática das duas bibliotecas faz com que não tenhamos preconceitos com novas bibliotecas ( SDL, Directx, Ogre ) que poderemos vir a aprender ou ser obrigados a usar mais tarde.

Agora iremos conhecer uma função para escalar nosso objeto:

void glScalef(GLfloat x, GLfloat y, GLfloat z);
Esta função produz um fator não uniforme de escala ( Diminui ou aumenta ). A matriz atual é multiplicada pela matriz de escalar que usa os parâmetros passados para a função.


 

O código a seguir mostra como aumentar e diminuir um cubo 3D ( que gira sobre seu proprio eixo ) nos eixos X e Y usando o AllegroGL
Teste o programa usando as teclas "A" e "Z".

 


CÓDIGO...
// Exemplo de como aumentar ou diminuir o tamanho de um cubo ( que gira sobre seu eixo ) em AllegroGL
// Autor: Adriano Waltrick
// BDJogos
// Data: 20/11/2007

#include <allegro.h>
#include <alleggl.h>

int main()
{
   // Iniciações básicas da Allegro
   allegro_init();
   install_keyboard();
   
   // Iniciação da AllegroGL
   install_allegro_gl();
   
   allegro_gl_set(AGL_Z_DEPTH, 8);
   allegro_gl_set(AGL_COLOR_DEPTH, 16);
   allegro_gl_set(AGL_SUGGEST, AGL_Z_DEPTH | AGL_COLOR_DEPTH);
   
   // Setando o Modo Gráfico
   set_gfx_mode(GFX_OPENGL_WINDOWED, 640, 480, 0, 0);
   
   // Criando uma FONT para poder escrever na tela as variáveis X e Y
   FONT *agl_font = NULL;
   glEnable(GL_TEXTURE_2D);
   agl_font = allegro_gl_convert_allegro_font(font, AGL_FONT_TYPE_TEXTURED, 250.0f);
   
   
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
   // Iniciando a camera
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glFrustum(-1.0, 1.0, -1.0, 1.0, 1, 60.0);
   
   
   glShadeModel( GL_SMOOTH );
   
   // Faz a OpenGL aceitar profunidade
   glClearDepth( 1.0f );
   glEnable( GL_DEPTH_TEST );
   glDepthFunc(GL_LEQUAL);
   
   // Maior qualidade nos gráficos
   glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
   
   glLoadIdentity();
   
   // Angulo para fazer o quadrado girar
   GLfloat angulo;
   angulo = 0.0f;
   
   // Valor de Escala
   GLfloat escala;
   escala = 1.0f;
   
   // Buffer de teclado
   int buffer_teclado = 0;
   const int iCiclo = 30;
   
   
   
   // Laço principal
   while( !key[KEY_ESC] )
   {
   
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glLoadIdentity();
      
      
      
      if(buffer_teclado == 0)
      {
            
         if ( key[KEY_A] )
         {
            escala += 1.0f;
            buffer_teclado = iCiclo;
         }
         
         if ( key[KEY_Z] )
         {
            escala -= 1.0f;
            buffer_teclado = iCiclo;
         }
      
      
      
      
      }
      else buffer_teclado--;
      
      
      // Imprimimos as variaveis X e Y
      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      
      allegro_gl_printf(agl_font, -0.9f, 0.9f, 0.0f, makecol( 000, 255, 000), "Escala: %f", escala );
      
      
      
      
      // Posiciona o próximo objeto
      glScalef( escala, escala, escala );
      
      
      // Rotaciona o próximo objeto
      glRotatef(angulo, 1.0f, 1.0f, 1.0f );
      
      
      // Imprime o CUBO
      glBegin(GL_QUADS);
      
      // face da frente
      glColor3f( 255, 0 , 0 );
      glVertex3f( 0.00, 0.00, 0.00 );
      glVertex3f( 0.00, 0.30, 0.00 );
      glVertex3f( 0.30, 0.30, 0.00 );
      glVertex3f( 0.30, 0.00, 0.00 );
      
      
      // face de traz
      glColor3f( 0, 255 , 0 );
      glVertex3f( 0.00, 0.00, 0.30 );
      glVertex3f( 0.00, 0.30, 0.30 );
      glVertex3f( 0.30, 0.30, 0.30 );
      glVertex3f( 0.30, 0.00, 0.30 );
      
      // face de cima
      glColor3f( 255, 255 , 255 );
      glVertex3f( 0.00, 0.30, 0.00 );
      glVertex3f( 0.00, 0.30, 0.30 );
      glVertex3f( 0.30, 0.30, 0.30 );
      glVertex3f( 0.30, 0.30, 0.00 );
      
      // face de baixo
      glColor3f( 255, 255 , 0 );
      glVertex3f( 0.00, 0.00, 0.00 );
      glVertex3f( 0.00, 0.00, 0.30 );
      glVertex3f( 0.30, 0.00, 0.30 );
      glVertex3f( 0.30, 0.00, 0.00 );
      
      // face da esquerda
      glColor3f( 0, 0, 255 );
      glVertex3f( 0.00, 0.00, 0.00 );
      glVertex3f( 0.00, 0.30, 0.00 );
      glVertex3f( 0.00, 0.30, 0.30 );
      glVertex3f( 0.00, 0.00, 0.30 );
      
      // face da direita
      glColor3f( 255, 0, 255 );
      glVertex3f( 0.30, 0.00, 0.00 );
      glVertex3f( 0.30, 0.30, 0.00 );
      glVertex3f( 0.30, 0.30, 0.30 );
      glVertex3f( 0.30, 0.00, 0.30 );
      
      
      glEnd();
      
            
      
      // imprime tudo
      allegro_gl_flip();
      
      angulo += 0.2f;
   
   }
   
   allegro_exit();
   
   return 0;
}
END_OF_MAIN();

FIM DE CÓDIGO...

Observe que no exemplo acima estamos escalando em X, Y e Z. Isto dá a impressão de Zoom.

Um detalhe importante que temos que observar é:

- Para aumentar a altura do objeto, devemos manter( salvar ) os parametros antigos de X e Z iguais.
Exemplo: glScalef( 10, 50, 10 );

- Para aumentar a largura do objeto, devemos manter( salvar ) os parametros antigos de Y e Z iguais.
Exemplo: glScalef( 50, 10, 10 );

Aumentar a profundidade de nosso objeto não vai funcionar por enquanto.

As teclas A e Z são geralmente utilizadas para fazer zoom.
Porém, o que fizemos acima não é um zoom, na verdade estamos aumentando o tamanho do objeto.

O efeito de zoom seria dado usando o comando glTranslatef passando como parametro o eixo Z.
Porém, se fizermos isso agora não vai funcionar.

Não podemos ver as modificações dos parametros Z das funções por que a OpenGL tem por padrão a visão Ortogonal.

Você precisa saber ...

Orthographic view / Visão Ortogonal
Em uma visão ortogonal todos os pontos do objeto são perpendiculares ao plano de visão, e são projetados em paralelo.

Em geometria, perpendicularidade (ou ortogonalidade) é uma noção que indica se dois objectos (retas ou planos) fazem um ângulo de 90º.

 

Este modo de visão ortográfica é muito parecido com os jogos Isométricos.
A perspectiva do tipo isométrica ocorre quando o observador está situado no infinito (e portanto, as retas projetantes são paralelas umas às outras) e incidem perpendicularmente ao Plano de Quadro ( Wikipedia ).

Exemplo de Projeção Ortográfica do Blender 3D:

Na imagem abaixo vemos um plano com um cubo. Observe que as linhas de fundo do programa estão sempre no mesmo angulo.

Exemplo de Projeção Perspectiva do Blender 3D:

Observe que esta projeção é como o nosso olho vê.. voltada ao horizonte.

Levando isto em consideração, ao tentar modificar o parametro de Z com o translate na nossa visão atual, não iremos perceber o zoom.
Para perceber o zoom devemos fazer uma projeção perspectiva.

Não se esqueça que, quando aplicamos glRotate, glTranslate e glScale estamos modificando as coordenadas do mundo 3D e não um objeto em si ( grupo de vertices ).. Isto é muito importante para entender o sistema de cameras.

Download do exemplo 1 - Allegro - Clique Aqui

Download do exemplo 1 - Glut - Clique Aqui

Download do exemplo 2 - Allegro - Clique Aqui


Contribuidor
Adriano Waltrick
20/11/2007


 

« Anterior

 

Próximo »

 
 

01/06/2007 (C) Copyright. Todos os Direitos Reservados. Leia a política de privacidade do portal.
É proibida a cópia de conteúdo deste site de acordo com a Lei Brasileira de Direitos Autorais.