Aula Prática: Transformações Geométricas
Disciplina: Computação Gráfica
Professora: Isabel Harb Manssour
 

O objetivo desta aula aprender a trabalhar com as transformações geométricas usando a biblioteca OpenGL. Para isto, serão utilizadas as bibliotecas OpenGL, GLU e GLUT, de maneira que o programa fique portável e possa ser executado tanto no ambiente Windows como no ambiente Linux.

Para implementação de aplicações OpenGL na linguagem de programação C/C++ é necessário criar um projeto para linkar as bibliotecas. Na primeira aula prática já foi fornecido este projeto para o ambiente Dev-Cpp, portanto, basta remover os programas fontes anteriores do projeto e incluir o programa fonte que será usado nesta aula, que na verdade é a resposta dos exercícios 2D da aula prática de Mapeamento, Câmera e Projeção.

Inicialmente, verifique o conteúdo do programa fonte fornecido para entender como foi implementado o zoom, o pan e a correção de aspecto. Depois, compile e execute o programa que abrirá uma janela com fundo branco, uma casinha e duas linhas que representam os eixos cartesianos. Aplique zoom e pan e procure alterar o tamanho da janela várias vezes, aumentando e diminuindo bastante a sua largura e altura, de maneira intercalada. Observe atentamente o código para entender o seu funcionamento e observe as funções callback implementadas(Desenha, Teclado, TeclasEspeciais e GerenciaMouse).

Agora altere o código fonte conforme descrito a seguir para implementar as transformações geométricas em duas casinhas separadamente. A cada alteração, compile e execute novamente o programa para verificar os resultados obtidos. Em caso de dúvida, consulte a professora ou o tuturial de introdução à OpenGL disponível em http://www.inf.pucrs.br/~manssour/OpenGL/Tutorial.html.

Altere o programa de maneira que as chamadas para as funções que desenham a casa fiquem em uma função, conforme o exemplo abaixo:

           void DesenhaCasa(void)
           {
                   glLineWidth(3);
                   
                   glBegin(GL_TRIANGLES);
                     ....
                   glEnd();
                   
                   glBegin(GL_LINE_LOOP);
                     ....
                   glEnd();           
           }

           void Desenha(void)
           {
                   ....
                   glTranslatef(tx, ty, 0);
                   DesenhaCasa();
                   ....
           }

Em seguida, declare as seguintes variáveis globais (logo após os includes):
GLint angulo;
GLfloat ex,ey;

Inicialize estas variáveis na função Inicializa() com os seguintes valores:
angulo = 0;
ex = 1;
ey = 1;

Agora acrescente os comandos abaixo na função Desenha, logo após a chamada para a função glTranslatef colocada anteriormente:
glScalef(ex, ey, 1);
glRotatef(angulo, 0, 0, 1);

Finalmente, para fazer o tratamento dos eventos, inclua e termine de implementar a função callback TeclasEspeciais conforme descrito abaixo. O código desta função deve ser alterado para permitir:

  • rotacionar o objeto para esquerda cada vez o usuário pressiona a tecla PageUp (incremente a variável global angulo);
  • rotacionar o objeto para direita cada vez o usuário pressiona a tecla PageDn (decremente a variável global angulo);
  • aumentar o tamanho do objeto cada vez que o usuário pressiona a tecla Home (incremente ex e ey);
  • diminuir o tamanho do objeto cada vez que o usuário pressiona a tecla End (decremente ex e ey);
void TeclasEspeciais(int key, int x, int y)
{
    switch (key)
    {
	... // teclas já implementadas
    	case GLUT_KEY_PAGE_UP:
                             break; 
    	case GLUT_KEY_PAGE_DOWN: 
                             break; 
    	case GLUT_KEY_HOME:
                             break; 
   	case GLUT_KEY_END:
                             break; 
    }
    ...

Para outras informações sobre o tratamento de eventos, consulte o tutorial de OpenGL (http://www.inf.pucrs.br/~manssour/OpenGL/Eventos.html).

O objetivo agora é criar duas instâncias da casa que podem ser manipuladas através das transformações de escala, rotação e translação, de forma independente, como exemplificado na próxima figura. Neste caso, é necessário criar outras variáveis para guardar as transformações que serão aplicadas na nova instância da casinha. A função callback que gerencia eventos do teclado deve ser alterada de maneira que, por exemplo, quando o usuário pressiona F1, ele irá manipular a primeira instância da casinha, e quando ele pressiona F2 ele irá manipular a segunda instância da casinha (dica: crie uma variável para armazenar qual foi a instância selecionada).

Basta alterar a função Desenha() para que as transformações geométricas sejam aplicadas apenas em uma das instâncias de cada vez. Para isto, devem ser utilizadas as funções glPushMatrix() e glPopMatrix() da seguinte maneira:

           void Desenha(void)
           {
                   ....
                    // Desenha a primeira instância da casinha
                    glPushMatrix();
                    glTranslatef(...);
                    glScalef(...);
                    glRotatef(...);
                    DesenhaCasa();
                    glPopMatrix();

                    // Desenha a segunda instância da casinha
                    glPushMatrix();
                    glTranslatef(...);
                    glScalef(...);
                    glRotatef(...);
                    DesenhaCasa();
                    glPopMatrix();
                   ....
           }

As funções glPushMatrix e glPopMatrix são usadas para definir o escopo das transformações. A glPushMatrix é utilizada para guardar a matriz de transformação corrente na pilha, e a glPopMatrix para recuperar a matriz de transformação corrente da pilha.


Agora vamos aprender a utilizar algumas primitivas gráficas disponíveis na GLUT para modelos de objetos 3D e exercitar as transformações geométricas 3D. Inicialmente faça o download do programa que será usado nesta aula. Grave este arquivo no drive h e inclua-o no projeto para o ambiente Dev-Cpp. Lembre de remover os programas fontes anteriores do projeto para incluir o programa fonte que será usado nesta aula.

A função glutWireTeapot(50.0f); é usada para desenhar o wire-frame de um teapot (bule de chá). Seu protótipo é: glutWireTeapot(GLdoouble size);, onde o parâmetro size indica um raio aproximado do teapot. Uma esfera com este raio irá "envolver" totalmente o modelo [Wright 2000]. Assim como a função teapot, a biblioteca GLUT também possui funções para desenhar outros objetos 3D. Estas funções estão listadas abaixo [Woo 1999]:
- void glutWireCube(GLdouble size);
- void glutWireSphere(GLdouble radius, GLint slices, GLint stacks);
- void glutWireCone(GLdouble radius, GLdouble height, GLint slices, GLint stacks);
- void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings);
- void glutWireIcosahedron(void);
- void glutWireOctahedron(void);
- void glutWireTetrahedron(void);
- void glutWireDodecahedron(GLdouble radius);

Os parâmetros slices e stacks que aparecem no protótipo de algumas funções, significam, respectivamente, o número de subdivisões em torno do eixo z (como se fossem linhas longitudinais) e o número de subdivisões ao longo do eixo z (como se fossem linhas latitudinais). Já rings e nsides correspondem, respectivamente, ao número de seções que serão usadas para formar o torus, e ao número de subdivisões para cada seção.

Agora crie e inicialize as seguintes variáveis globais no programa:
GLint rings = 6, nsides = 20, slices = 20, stacks = 10;

Acrescente no seu código os comandos necessários para incrementar e decrementar o valor destas variáveis. Por exemplo, F1 incrementa e F2 decrementa a variável rings, F3 incrementa e F4 decrementa a variável nsides, e assim por diante.

Inclua no lugar do teapot um torus. Passe por parâmetro para a função glutWireTorus as variáveis rings e nsides criadas anteriormente, compile e execute o programa. Depois altere os valores destas variáveis utilizando as teclas especificadas anteriormente. Observando o funcionamento do programa, na sua opinião, qual técnica de modelagem foi utilizada para modelar o torus?

Teste a utilização das funções Cone, Sphere e Cube disponíveis na GLUT. Utilize as variáveis globais criadas anteriormente na chamada destas funções (rings, nsides, slices, stacks). Durante a execução, experimente alterar os valores destas variáveis.

Olhe a próxima figura e faça as alterações necessárias para gerar a imagem que aparece na figura.

Agora, usando as transformações geométricas e a função glutWireCone(30, 30, 10, 8); acrescente o código necessário para gerar a imagem abaixo. Importante: NÃO altere os parâmetros da glutWireCone NEM os parâmetros de visualização. Use apenas as transformações geométricas!!!


Agora remova duas das chamadas para a função glutWireCone, deixando que apenas um cone seja desenhado. Depois, inclua os comandos necessários para que seja possível alterar as transformações geométricas que são aplicadas simplesmente pressionando uma tecla. Para isto, inicialmente, deverão ser criadas as seguintes variáveis globais:

GLfloat tx, ty, tz, ex, ey, ez, ang, rotx, roty, rotz; 
Depois de criar estas variáveis, inicialize-as na função Inicializa() com os seguintes valores:
 tx = ty = tz = 0;
 ex = ey = ez = 1; 
 ang = 0;
 rotx = 1;
 roty = 0;
 rotz = 0; 

Na seqüência, acrescente os comandos para aplicar as transformações geométricas antes da chamada para glutWireCone, conforme o código abaixo:
 ...
 glTranslatef(tx, ty, tz); 
 glRotatef(ang, rotx, roty, rotz);
 glScalef(ex, ey, ez);
 glutWireCone(radius, 20, slices, stacks);
 ... 

Finalmente, inclua comandos para alterar estas variáveis, por exemplo, na função callback para gerenciar teclado, conforme ilustrado abaixo. Lembre de registrar esta função na main() (glutKeyboardFunc(GerenciaTeclado)).
// Função callback chamada para gerenciar eventos de teclado 
void GerenciaTeclado(unsigned char key, int x, int y) { 
	switch (key) { 
		case 'x': // diminui a translação em x
			tx -= 2;
			break; 
		case 'X': // aumenta a translação em x
			tx += 2;
			break; 
		case 'y': // diminui a translação em y
			ty -= 2;
			break; 
		case 'Y': // aumenta a translação em y
			ty += 2;
			break; 
		case 'z': // diminui a translação em z
			tz -= 2;
			break;  
		case 'Z': // aumenta a translação em z
			tz += 2;
			break; 
		// faça o mesmo para as demais variáveis
	} 
	glutPostRedisplay(); 
} 


Exercício: tente fazer a aula prática sobre composição de transformações geométricas disponível aqui.

 ../../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)

[Homepage CG]  [Homepage CG-SI]

Última alteração em 11 de setembro de 2006.