Aula Prática: Mapeamento, Câmera, Projeção
Disciplina: Computação Gráfica
Professora: Isabel Harb Manssour
 

O objetivo desta aula aprender a utilizar a biblioteca OpenGL para verificar como funciona o mapeamento através da implementação das operações de zoom e pan, além de entender como posicionar a câmera e especificar a projeção em 3D. 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. Este programa tem a implementação dos exercícios da primeira aula prática.

Inicialmente, verifique o conteúdo do programa fonte fornecido para tentar entender o seu conteúdo. Depois, compile e execute o programa que abrirá uma janela com fundo branco, uma casinha e duas linhas que representam os eixos cartesianos. Observe atentamente o código para entender o seu funcionamento e observe as funções callback implementadas(Desenha, Teclado e TeclasEspeciais).

Agora altere o código fonte conforme descrito a seguir para implementar as operações de zoom e pan. 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.

Como o zoom consiste na alteração das coordenadas da window no sistema de referência do universo, para aplicar o zoom altere as coordenadas da função gluOrtho2D sempre que o usuário pressionar um dos botões do mouse. Portanto, considerando a interação através do mouse, para implementar o zoom é necessário alterar as coordenadas da função gluOrtho2D sempre que o usuário pressionar um dos botões do mouse. Primeiro, registre a função callback para gerenciar eventos do teclado acrestando a seguinte linha de código na função main, antes da chamada para a função Inicializa():
glutMouseFunc(GerenciaMouse);

Em seguida, declare a variável global win (logo após os includes) e a inicialize na função Inicializa() com 1, como mostram os trechos de código abaixo:

#include <gl/glut.h>
GLfloat win;
...
void Inicializa (void)
{   
   win = 1;
...

Agora, também na função Inicializa, altere a chamada da função glutOrtho2D para que use a variável win da seguinte maneira:

gluOrtho2D (-win, win, -win, win);

Em seguida, implemente a função callback para gerenciar eventos do mouse. Esta função deve alterar a variável win de maneira a implementar o zoom-in e o zoom-out. Lembre que cada vez que esta variável for alterada, deve-se chamar as funções abaixo:

...
        glMatrixMode(GL_PROJECTION); 
        glLoadIdentity(); 
        gluOrtho2D (-win, win, -win, win); 
        glMatrixMode(GL_MODELVIEW);
        glutPostRedisplay(); 	
...

Um exemplo completo da implementação do zoom está disponível em http://www.inf.pucrs.br/~manssour/OpenGL/Eventos.html. A única diferença é que no exemplo é feito o zoom-in e o zoom-out quando o usuário pressiona as teclas GLUT_KEY_UP e GLUT_KEY_DOWN, ao invés de clicar com o botão do mouse.

Para implementar o pan, que consiste, basicamente, no deslocamento da window no sistema de referência do universo, o procedimento é semelhante ao zoom, porém as coordenadas da função gluOrtho2D devem ser alteradas de maneira que a window seja deslocada para cima, para baixo, para esquerda e para direita. Para implementar esta operação, vamos precisar de duas variáveis globais que armazenem este deslocamento. Estas variáveis devem ser declaradas e inicializadas conforme ilustram os trechos de código a seguir.

#include <gl/glut.h>
GLfloat panX, panY;
...
void Inicializa (void)
{   
   ...
   panX = panY = 0;
...

Depois, altere todas as chamadas da função gluOrtho2D da seguinte maneira:

gluOrtho2D (-win+panX, win+panX, -win+panY, win+panY);

Agora basta definir quais são as teclas que irão deslocar a window, ou seja, que irão alterar os valores destas variáveis.

Exercício: Execute o programa e altere o tamanho da janela diminuindo ao máximo a sua largura. Depois aumente a largura da janela e diminua ao máximo a sua altura. O que acontece com o desenho? Considerando a etapa de mapeamento, pense porque a imagem fica alterada e qual seria a solução. A função callback chamada quando o tamanho da janela é alterado pode ser usada para obter o tamanho da viewport.

// 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 window mantendo a proporção com a viewport
	if (w <= h) 
		gluOrtho2D (...);
	else 
		gluOrtho2D (...);

	glMatrixMode(GL_MODELVIEW);
}
...
// Programa Principal 
int main(void)
{
	...
	// Registra a função callback de redimensionamento da janela de visualização
	glutReshapeFunc(AlteraTamanhoJanela);
	...


Agora vamos aprender como trabalhar com a visualização 3D em OpenGL. Para isto, é necessário compreender como são utilizadas as funções de projeção e manipulação da câmera em OpenGL. Inicialmente faça o download do programa que será usado para estudar estes tópicos. Grave este arquivo no drive h e inclua-o no projeto para o ambiente Dev-Cpp que já estava sendo usado. Lembre de remover o programa fonte anterior do projeto.

Importante: caso você não consiga executar o exemplo no Dev-C++, elimine a linha de comando
glutWireTeapot(50.0f);
que desenha um teapot, e acrescente a linha de comando abaixo para que seja desenhado um torus.
glutWireTorus(30, 50, 20, 20);

Inicialmente, analise o código fonte para entender o que programa faz.

A função gluLookAt(0,80,200, 0,0,0, 0,1,0); define a câmera, isto é, através dos seus argumentos é possível indicar a posição da câmera e para onde ela está direcionada. Seu protótipo é: void gluLookAt( GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz );. Os parâmetros: eyex, eyey e eyez são usados para definir as coordenadas x, y e z, respectivamente, da posição da câmera (ou observador); centerx, centery e centerz são usados para definir as coordenadas x, y e z, respectivamente, da posição do alvo, isto é para onde o observador está olhando (normalmente, o centro da cena); upx, upy e upz são as coordenadas x, y e z, que estabelecem o vetor up (indica o "lado de cima" de uma cena 3D) [Wright 2000].

Agora altere o parâmetro upy para -1 e veja o que acontece com o teapot. Depois, atribua o valor 1 para upy novamente. Em seguida, altere o parâmetro eyez para 100, compile e visualize o resultado. Depois altere este mesmo parâmetro para 300, compile e visualize o resultado novamente. Na seqüência, passe o valor 200 para este parâmetro. Altere o parâmetro centerx para 20, compile e execute o programa. Agora altere este mesmo parâmentro para -20, compile e execute o programa.

Considerando as alterações feitas, e a teoria estudada em aula, pense em que consiste alterar os parâmetros eyex, eyey, eyez, centerx, centery e centerz.

Agora inclua a função abaixo no código fonte TeaPot3D.c.

// Callback para gerenciar eventos do teclado para teclas especiais (F1, PgDn, entre outras)
void SpecialKeys(int key, int x, int y)
        {
		switch (key) {
			case GLUT_KEY_LEFT : 
							obsX -=10;
							break;
			case GLUT_KEY_RIGHT : 
							obsX +=10;
							break;
			case GLUT_KEY_UP : 
							obsY +=10;
							break;
			case GLUT_KEY_DOWN : 
							obsY -=10;
							break;

			case GLUT_KEY_HOME : 
							obsZ +=10;
							break;
			case GLUT_KEY_END : 
							obsZ -=10;
							break;
		}
		glLoadIdentity();
		gluLookAt(obsX,obsY,obsZ, 0,0,0, 0,1,0);
        	glutPostRedisplay();
        }

No início do programa, acrescente as variáveis globais que aparecem abaixo.

#include <gl/glut.h>
GLdouble obsX=0, obsY=0, obsZ=200; //acrescente esta linha

Para que o zoom continue funcionando corretamente, na função PosicionaObservador troque a linha de código gluLookAt(0,80,200, 0,0,0, 0,1,0); para gluLookAt(obsX,obsY,obsZ, 0,0,0, 0,1,0);.

Na função main inclua a seguinte chamada de função glutSpecialFunc(SpecialKeys); antes da chamada para a função Inicializa();. Compile e execute o programa. Você verá que através destas alterações é possível alterar a posição do observador mantendo sempre o mesmo alvo.

A função gluPerspective(angle,fAspect,0.1,500); estabelece os parâmetros da Projeção Perspectiva, atualizando a matriz de projeção perpectiva. Seu protótipo é: void gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar );. Descrição dos parâmetros: fovy é o ângulo, em graus, na direção y (usada para determinar a "altura" do volume de visualização); aspect é a razão de aspecto que determina a área de visualização na direção x, e seu valor é a razão em x (largura) e y (altura); zNear, que sempre tem que ter um valor positivo maior do que zero, é a distância do observador até o plano de corte mais próximo (em z); zFar, que também sempre tem que ter um valor positivo maior do que zero, é a distância do observador até o plano de corte mais afastado (em z). Esta função sempre deve ser definida ANTES da função gluLookAt, e no modo GL_PROJECTION [Wright 2000].

Altere o parâmetro zNear da função gluPerspective para 0.5 (as vezes pode haver um problema na iluminação se o valor for muito baixo, tal como 0.1). Agora coloque 2 no lugar de fAspect, compile e execute para ver o que acontece. Troque o valor 2 por 0.5, compile e execute novamente. Coloque novamente a variável fAspect no segundo parâmetro da gluPerspective. Com estes testes, foi possível verificar as conseqüências de alterar a razão de aspecto.

Agora altere o parâmetro zNear da função gluPerspective para 210, compile e execute para ver o que acontece. Coloque novamente o valor 0.5 para zNear e troque o valor de zFar para 200, compile e execute. Coloque novamente o valor 500 para zFar.

Exercício: altere a implementação para que seja desenhada uma pirâmide formada por uma lista de vértices e uma lista de arestas no lugar do teapot. Dica: Faça o desenho usando GL_LINES.

 ../../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 06 de setembro de 2006.