Buscar

Tutorial1.3 OpenGL

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 30 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 30 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 30 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

OpenGL na Computação Gráfica 
 
 
 
 
 
 
 
 
 
 
 
 
Charles Novaes de Santana 
José Garcia Vivas Miranda
 
Capítulo I 
 
Iniciando a programação com OpenGL 
 
w
w
w
w
w
w
Programação inicial com OpenGL 
Ingredientes básicos de todo programa OpenGL 
Primitivas geométricas 
OpenGL como Máquina de Estados 
OpenGL orientada a eventos 
Controlando programas com Mouse e Teclado 
 
Charles Novaes de Santana - Estudante de Iniciação Científica 
Jose Garcia Vivas Miranda - Orientador 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Este estudo visa ajudar na compreensão da Computação Gráfica utilizando OpenGL, uma das APIs 
gráficas mais poderosas e mais usadas no mundo. Ao longo dele serão apresentados os principais 
conceitos de Computação Gráfica e as principais funções OpenGL em diversos programas 
exemplos que auxiliarão muito aquele que estudar por esse material. 
 
Antes de programar utilizando OpenGL é preciso saber de algumas de suas características mais 
significativas, cada uma delas será vista em detalhes nos exemplos mostrados no decorrer do 
estudo: 
 
w
w
w
w
w
w
w
w
w
OpenGL é uma API (Interface de Programação de Aplicação) gráfica 
 
 Isso significa que OpenGL trabalha entre o Software e o Hardware, simplificando os cálculos 
necessários para as transformações vetoriais e matriciais. 
 Outras APIs e bibliotecas são associadas à OpenGL: 
 
A GLU (OpenGL Utility Library) faz parte do padrão OpenGL. Contém utilitários 
que permitem a construção de curvas, trianguladores, quádricas. É construída sobre 
a OpenGL. 
A GLUT (OpenGL Utility Toolkit) é uma API portátil de acesso ao sistema de 
janelas. Não é parte oficial do OpenGL. É construída sobre a GLU. 
A GLUI é uma API para a construção de interfaces gráficas, faz com que a interação 
entre o usuário e o aplicativo seja mais simples com a construção de janelas, menus, 
botões, etc. É construída sobre a GLUT. 
 
OpenGL é uma Máquina de Estados. 
 
 Algumas funções do OpenGL guardam flags necessárias às configurações do programa como as 
características de cor de fundo de tela, configurações de janelas e outras habilitações ao programa, 
veremos isso também em muitos programas colocados como exemplo. 
 
OpenGL é orientada a eventos. 
 
 O programa escrito utilizando a OpenGl permanece em loop até que algum evento aconteça. Na 
especificação dos eventos está mencionada a função Callback que será chamada toda a vez que o 
evento a ela relacionado acontecer. O programa só se encerra se o evento correspondente ao final da 
execução for ativado. 
 
Callback 
 Callbacks são rotinas que serão chamadas para tratar eventos. Para que uma rotina 
 callback seja efetivamente chamada deve ser registrada através da função: 
 glutXxxFunc (callback) 
Onde Xxx designa uma classe de eventos e callback é o nome da rotina. 
 
Exemplo 
Para registrar uma callback de desenho chamada Desenho usamos: 
glutDisplayFunc (Desenho) 
 
OpenGL é independente da Plataforma e do Sistema de Janelas. 
 
 As funções da OpenGL e das demais APIs a ela associadas são padronizadas quanto ao formato 
passado ao usuário e ao programador. As diferenças em relação ao tratamento do sistema de janelas 
e do Hardware existem apenas internamente ao código da API. Dessa forma os parâmetros e as 
funções não mudam e um código escrito para um compilador de uma plataforma UNIX, por 
exemplo, compila tranquilamente em um do Windows e vice-versa. 
 
De posse dessas informações podemos começar a tratar dos principais conceitos para a 
programação com OpenGL. 
 
 
 
 
Ingredientes Básicos Necessários a todo programa OpenGL 
 
 
 
1- Sistema de Coordenadas (2D) 
 
O sistema de Coordenadas de uma aplicação OpenGL tem origem no canto inferior esquerdo da tela 
(em relação ao observador). Assim os valores de y crescem à medida que o ponto se aproxima do 
topo da tela, e os valores de x crescem à medida que o ponto se aproxima da lateral direita da tela 
(Figura 1). 
 
 
Figura 1 
 
 
 
 
 
2- Configurações iniciais da janela 
 
Para desenhar utilizando um programa OpenGL é necessário uma janela de visualização. As 
configurações da janela ou das janelas de visualização são feitas na função main( ). 
 
Um exemplo de função main () tratando as configurações de janela segue abaixo: 
 
#include <stdlib.h> 
#include <GL/glut.h> 
 
void desenho(void) 
{ 
} 
 
void main (int argc, char** argv) 
{ 
glutInit (&argc, argv); // inicializa a glut 
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); // especifica modo de desenho 
glutInitWindowSize (640, 480); // tamanho da janela 
glutInitWindowPosition (100, 150); // posicao da janela na tela 
glutCreateWindow (argv[0]); // cria a janela 
glutDisplayFunc (desenho); 
glutMainLoop (); // inicia o Loop infinito do programa 
} 
 
glutInit (&argc, argv) – Esta função inicializa a GLUT. Esses argumentos passados 
poderão ser passados como parâmetros para o programa, como foi feito com o parâmetro argv, que 
representa o nome da janela, conforme especificado pela função glutCreateWindow () 
 
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB) – Essa função especifica como 
o desenho será inicializado. A constante GLUT_SINGLE indica que será utilizado apenas um 
buffer para alocar a imagem – ou seja, o desenho será construído diretamente na tela -, e diz que a 
imagem será feita utilizando o padrão de cores RGB (vermelho, verde e azul) para colorir. 
 
glutInitWindowSize (640, 480) – Esta função especifica qual o tamanho inicial da 
janela. No caso são 640 pixels de largura por 480 pixels de altura. Quando o programa está 
rodando, o usuário pode redimensionar a janela, se prererir. 
 
glutInitWindowPosition (100, 150) – Esta função especifica que a janela 
posicionada a uma distância de 100 pixels do limite esquerdo da tela e a 150 pixels do limite 
superior da tela. 
 
glutCreateWindow (argv[0]) – Esta função abre uma janela de visualização de acordo 
com as configurações especificadas nas funções acima. Esta janela terá como nome o parâmetro 
passado para esta função, no caso a entrada de dados na chamada do executável de acordo com o 
parâmetro argv[0]. 
 
glutDisplayFunc (Desenho) – Esta é uma função callback necessária para a execução de 
qualquer programa que utilize a biblioteca glut (a partir da versão 3.0). Explicaremos melhor as 
funções callbacks no próximo exemplo. 
 
glutMainLoop () - Esta função é responsável por manter o programa em loop até que seja 
chamado algum evento que determine o fim da aplicação. Essa função caracteriza a especificação 
de OpenGL como uma API orientada a eventos, o que será tratado no próximo ponto de estudo. 
 
O código acima irá abrir uma janela sem conteúdo algum. Para todos os programas feitos usando 
OpenGL esse código será utilizado. 
 
 
 
 
 
3- Orientação a Eventos 
 
Como foi dito, a OpenGL é orientada a eventos e trata eventos de Mouse, de Teclado ou de 
Alterações da Janela de Visualização. A especificação dos eventos e seus callbacks ficam no 
main() do programa. O padrão para as funções que estabelecem os callbacks é 
glutXxxFunc(). 
Um exemplo de função main () que abre uma janela e se prepara para tratar os diversos eventos 
segue abaixo: 
 
#include <stdio.h> 
#include <GL/glut.h> 
 
void main () 
{ 
 
-------------------ABRINDO UMA JANELA DE VISUALIZAÇÃO ------------------ 
 
glutInit (&argc, argv); // inicializa a glut 
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); // especifica modo de desenho 
glutInitWindowSize (640, 480); // tamanho da janela 
glutInitPosition (100, 150);// posicao da janela na tela 
glutCreateWindow (“nome da janela”); // cria a janela 
 
-------------------ESPECIFICANDO AS FUNÇÕES CALLBACKS ------------------ 
glutDisplayFunc (Desenho); // registro de função de desenho 
glutReshapeFunc (Reshape); // registro de função de Atualização de janela 
glutMouseFunc (Mouse); // registro de função de mouse 
glutKeyboard (Teclado); // registro de função de teclado 
glutMainLoop (); // inicia o Loop infinito do programa 
 
} 
 
glutDisplayFunc (Desenho) - Sempre que o sistema determinar que uma janela deve ser 
redesenhada na tela, isso significa um evento de atualização de desenho. Neste exemplo a função 
Desenho( ) é registrada como a função de atualização de desenho e chamada sempre que é preciso 
redesenhar uma cena. 
 
glutReshapeFunc (Reshape) – O tamanho da janela de visualização pode ser alterado 
com o mouse por exemplo. Neste exemplo a função Reshape( ) é registrada como um evento de 
atualização de tamanho de janela. A função Reshape, como veremos adiante, está passando 
parâmetros automaticamente para que sejam atualizados a largura e a altura da janela. 
 
glutMouseFunc (Mouse) – Quando um botão do mouse é pressionado ou solto, um evento 
de mouse é acionado. Neste exemplo a função Mouse( ) é registrada como uma função para ser 
chamada quando ocorrer eventos de Mouse. A função Mouse ( ) recebe argumentos que identificam 
posição do cursor e a natureza da ação iniciada no Mouse ( ). 
 
glutKeyboardFunc (Teclado) – Este comando chama a função Teclado quando uma 
tecla do teclado é pressionada ou solta. Os argumentos da função Teclado ( ) possuem argumentos 
que indicam que tecla foi pressionada além da posição do cursor naquele instante. 
 
 
Como as funções callbacks não foram ainda declaradas, o código acima não realizará função 
alguma, mas estará preparado para receber o código das funções callbacks especificadas 
como parâmetros e realizar aquilo a que se propõem. Abaixo falaremos sobre como a 
OpenGL trata a plotagem de gráficos. 
 
 
4- Desenhando primitivas 
 
Estabelecidas as configurações iniciais do programa e inicializada a janela de visualização, é hora 
de começarmos a desenhar as primitivas gráficas básicas. 
 
Todos os desenhos produzidos pela OpenGL são gerados por primitivas geométricas básicas. 
Pontos, retas, sequência de retas, polígonos e outras primitivas são combinadas de forma que geram 
todas as figuras que veremos ao longo de nosso estudo. 
 
Para especificar qual a primitiva utilizada no desenho é preciso passá-la como parâmetro para a 
função de estado glBegin ( ). Tudo o que estiver entre o glBegin( ) e o glEnd( ) será desenhado 
utilizando a primitiva passada. 
 
Ex: 
 
glBegin (GL_POINTS); 
Desenho ( ): 
glEnd ( ); 
 
No código acima, a função Desenho vai desenhar tudo aquilo por ela especificado utilizando 
pontos, que é a primitiva passada como parâmetro para a glBegin ( ). 
 
As funções que estabelecem o que será desenhado ficam na função callback de desenho. São muitas 
as funções de desenho da OpenGL, citaremos aqui as mais utilizadas, suas vantagens e onde e como 
podem ser usadas. 
 
Antes porém, é preciso identificar um padrão seguido por todas as funções do OpenGL. Para 
facilitar o entendimento e a utilização das funções, a OpenGL segue o seguinte padrão: 
 
{gl library} {comando básico} {número de argumentos} {tipo dos argumentos} 
 
gl library indica a biblioteca à que a função pertence 
comando básico é o radical da função, a função em si 
número de argumentos é a quantidade de parâmetros passados para a função 
tipo de argumento é o tipo dos argumentos passados para a função 
 
No caso, a primeira função que nós aprenderemos é a Vertex, uma função que recebe as 
coordenadas de um ponto como parâmetros. Cada função Vertex estabelece que o ponto recebido 
como parâmetro é um vértice de uma figura. Se a função for chamada em sequência, ligará os 
vértices utilizando a primitiva especificada, se apenas uma Vertex for chamada, será desenhada 
apenas uma primitiva. Utilizando o padrão OpenGL se quisermos uma função Vertex que receba 
um ponto com 2 coordenadas inteiras teremos: glVertex2i (param1, param2). 
 
glVertex2i(...) 
tipo de 
argumentos 
númeo de 
argumentos 
comando 
básico 
Biblioteca 
gl 
 
 
 
 
 
 
É importante ressaltar que a OpenGL possui tipos de dados específicos. Funções como a Vertex 
declarada no exemplo acima esperam argumentos inteiros de um determinado tamanho (32 bits). 
Para evitar problemas de portabilidade ao transportar o código entre plataformas que considerem os 
tipos de dados com tamanhos diferentes, a OpenGL criou seus próprios tipos de dados análogos aos 
já conhecidos. Isso acontece de acordo com a tabela abaixo que faz analogia dos tipos OpenGL com 
os tipos C++: 
 
Sufixo Tamanho de dados Tipo de dado no C++ Nome na OpenGL 
b inteiro 8-bits signed char Glbyte 
s inteiro 16-bits short Glshort 
i inteiro 32-bits int or long Glint, Glsizei 
f floating points 32 bits float Glfloat, Glclampf 
d floating points 64 bits double Gldouble, Glclampd 
ub unsigned 8-bits unsigned char Glubyte, Glboolean 
us unsigned 16-bits unsigned short Glushert 
ui unsigned 32 bits unsigned int or unsigned long Gluint, enum, bitfield 
 
Um exemplo de problema que a OpenGL evita com essa característica seria se determinada função 
espera como parâmetro um inteiro de 32 bits, mas o sistema considera inteiro com 16 bits. Dessa 
forma o exemplo número 1, abaixo, estaria errado, pois passa como parâmetros para a função um 
inteiro 16 bits, enquanto o exemplo número 2 estaria correto pois passa o argumento com a tipagem 
característica da OpenGL que no exemplo é o Glint (inteiro de 32 bits.). 
 
Exemplo 1: 
 
void desenha_ponto (int x, int y) // ERRADO 
{ 
 // desenha um ponto no ponto (x, y) 
 glBegin (GL_POINTS); 
 glVertex (x, y); 
 glEnd ( ); 
} 
 
Exemplo 2: 
 
void desenha_ponto (GLint x, GLint y) // CORRETO 
{ 
 // desenha um ponto no ponto (x, y) 
 glBegin (GL_POINTS); 
 glVertex (x, y); 
 glEnd ( ); 
} 
 
 
 
 
As primitivas utilizadas pela OpenGL são as seguintes: 
 
GL_POINTS Desenha pontos independentes 
 
GL_LINE Desenha uma linha entre dois pontos passados 
 
GL_LINE_STRIP Desenha uma sequência de linhas 
 
GL_LINE_LOOP Desenha uma sequência de linhas que retorna à origem 
 
GL_QUADS Desenha quadriláteros independentes a cada 4 pontos chamados. 
 
GL_QUAD_STRIP Desenha uma sequência de quadriláteros ligados. Dois 
pontos de um quadriláteros formam intersecção com outros dois 
pontos de outro quadrilátero. Para n quadriláteros são necessários 
2*(n+1) pontos. 
 
GL_TRIANGLES Desenha triângulos independentes a cada 3 pontos chamados 
 
GL_TRIANGLE_STRIPS Desenha triângulos conectados com origens diferentes. 
 
GL_TRIANGLE_FAN Desenha triângulos conectados com origem comum, 
são necessários 3n –1 pontos. 
 
GL_POLYGON Desenha um polígono convexo 
 
 
 
 
 
Utilizaremos o exemplo a seguir para falar sobre alguns conceitos importantes na programação com 
OpenGL. 
 
#include <stdlib.h> 
#include <GL/glut.h> 
 
 
/*-----------------minha funcao init ( ) ---------------------*/ 
 
void init (void) 
{ 
glClearColor (1.0, 1.0, 1.0, 0.0); 
glPointSize (4.0); 
glMatrixMode (GL_PROJECTION); 
glLoadIdentity ( ); 
gluOrtho2D (-50.0, 50.0, -100.0, 100.0); 
} 
 
/*-----------------minha funcao desenho ( ) --------------------*/ 
 
void desenho(void) 
{ 
glClear (GL_COLOR_BUFFER_BIT); 
glBegin (GL_POINTS); 
 glVertex2i (40, 80); 
 glVertex2i (40, 30); 
 glVertex2i (-20.0, 30); 
glEnd ( ); 
glFlush ( ); 
} 
 
/*-----------------main ---------------------*/ 
 
int main (int argc,char** argv) 
{ 
glutInit (&argc, argv); 
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); 
glutInitWindowSize (640, 480); 
glutInitWindowPosition (100, 100); 
glutCreateWindow ("Meu primeiro programa"); 
glutDisplayFunc (desenho); 
init ( ); 
glutMainLoop ( ); 
} 
 
O programa acima desenha 3 pontos em uma janela de visualização. Na função callback desenha ( ) 
vemos a utilização da função vertex ( ) utilizando o parâmetro GL_POINTS em 3 pontos distintos. 
A cor de fundo de tela é especificada na função init ( ), que além do fundo de tela guarda funções 
com as configurações iniciais do programa tais como tamanho do ponto a ser usado nos desenhos, 
dimensões do world window (cujo significado será conhecido no próximo capítulo), cor do ponto a 
ser desenhado, etc. 
 
Abaixo teremos uma explicação sobre as novas funções e os novos conceitos da programação 
com OpenGL encontrados nesse código . 
 
5- OpenGl como uma Máquina de Estados 
 
A OpenGL, como foi dito anteriormente é uma Máquina de Estados. O programa fica em Loop 
lendo determinadas variáveis e esperando pela ativação de alguma das funções Callbacks que 
indicarão alterações a serem feitas no valor das variáveis de estado do programa. Abaixo teremos 
algumas dessas variáveis de estado e o papel de cada uma em um programa feito com OpenGL. 
 
glColor3f (red, green, blue) – A função, com prefixo gl e recebendo 3 parâmetros do 
tipo float no exemplo, ativa a variável de estado que define a cor do próximo objeto a ser 
desenhado. Pode representar o preenchimento da primitiva usada na função Callback de Desenho ( 
no caso dessa primitiva ser do tipo POLYGON ou QUAD ou TRIANGLE), ou ainda representar a 
cor de contorno de figuras produzidas com as primitivas linha ou ponto. Uma curiosidade é que a 
variável de estado funciona como uma função e recebe como parâmetros valores de componentes 
de cor vermelha, verde e azul, que combinadas formarão 256 cores diferentes. Para se conseguir 
tons de cinza (variando do preto ao branco) utilizamos os valores das constantes r (vermelho), g 
(verde) e b (azul) iguais (variando de 0 a 1) em valores decimais ou de 0 a 255 em valores inteiros. 
Neste exemplo foi estabelecido um tom de cor para cada vértice do triângulo desenhado. Como 
resultado tivemos a formação de um degradê na linha da figura, esse é um artifício legal a ser usado 
com a função glColor. 
 
glClearColor (red, green, blue, alpha) – A variável de estado ClearColor, com 
prefixo gl, indica a cor do fundo da tela. Recebe como parâmetros as componentes r, g e b das 
cores, assim como na variável glcolor, e ainda recebe a componente alpha que é responsável pela 
transparência – estudaremos a questão de transparência melhor quando estudarmos iluminação, por 
enquanto utilizaremos a constante alpha com valor 0.0. 
 
6- Outras funções OpenGL 
 
glClear (GL_COLOR_BUFFER_BIT) – A função glClear faz com que a janela seja limpa de 
acordo com as configurações especificadas na variável glClearColor. Nesse caso, como apenas o 
buffer de cores é passado como parâmetro, usaremos simplesmente os parâmetros passados por 
glClearColor e limparemos apenas o buffer de cores, mas veremos adiante que outros parâmetros 
podem ser passados para a variável glClear e outras variáveis similares à glClearColor podem 
estabelecer o modo de inicialização de outros buffers a serem utilizados, como por exemplo o 
Depth Buffer. 
 
glPointSize (int) – Esta é uma função que define o tamanho da primitiva a ser usada. Caso 
não seja especificado esse tamanho, o valor default é 1. No nosso exemplo a função especifica o 
tamanho, em pixels, dos pontos. 
 
glFlush () - Como não são utilizadas outras funções callback além da função desenho (), foi 
preciso usar a função glFlush (); que será responsável por garantir que nada deixou de ser feito no 
programa, que todos os desenhos foram corretamente feitos, ou seja, que o buffer de cores foi 
corretamente “esvaziado”. Adiante veremos que quando outras funções callback que trarão o efeito 
de animação começarem a ser utilizadas o glFlush não terá tanta utilidade. 
 
7- Estabelecendo o Sistema de Coordenadas 
 
Usaremos para estabelecer o Sistema de Coordenadas Iniciais de nossos programas algumas 
funções e variáveis de estado que estarão na função init ( ) que é uma função de auxílio às 
configurações iniciais do programa OpenGL. Nesta função estarão os dados que indicarão também 
como serão feitas as transformações durante o decorrer do programa. Falaremos de Transformações 
mais tarde, mas desde já é preciso saber que para qualquer transformação a OpenGL utiliza-se de 
Matrizes de Transformação e a especificação inicial dessas matrizes de Transformação pode ser 
feita na função init ( ) de nossos programas, como feito anteriormente. 
 
Na função init ( ) estaremos também estabelecendo os limites do “mundo” criado em nossos 
programas. A computação Gráfica nos permite brincar de Criadores de pequenos mundos, mas é 
preciso estabelecer os limites de nosso mundo. Isso será feito utilizando a função glortho2D no 
exemplo acima tivemos: 
 
 
void init ( ) 
{ 
 glMatrixMode ( GL_PROJECTION); 
 glLoadIdentity ( ); 
 glOrtho2f ( -50.0, 50.0, -100.0, 100.0); 
} 
 
A função Ortho acima é da biblioteca gl. O sufixo 2D não se refere à quantidade e ao tipo de 
parâmetros como em outras funções, mas sim ao espaço dimensional do “mundo” a ser criado. 
Neste caso iremos trabalhar em 2 Dimensões. (3D se fosse 3 dimensões). Esta função tem como 
parâmetros pontos com coordenadas x, y – por isso recebe 4 valores. Esses pontos indicam os 
limites do mundo a ser trabalhado, nesse caso o ponto mais à direita é o ponto -50.0, o mais à 
esquerda é o ponto 50.0, o ponto mais abaixo é o ponto -100.0 e o ponto mais acima é o ponto 
100.0. Isso quer dizer que eu só posso trabalhar com valores de -50 a 50 na largura da tela e de -100 
a 100 na altura, mas não significa que todo o meu mundo estará sendo mostrado na tela. A parte que 
aparece na tela é definida por outra função, a função de Viewport que veremos no próximo capítulo. 
Por enquanto estamos definindo apenas os limites em que podemos trabalhar. A variável de estado 
MatrixMode define o tipo de matriz de transformação que será usado, mas falaremos disso mais 
tarde, quando falarmos de animação, como já foi dito. 
 
Por enquanto você pode brincar com o código dado, pode alterar a posição do desenho a fim de 
observar o que acontece com a imagem quando esta é definida fora dos limites de seu mundo. 
Como no exemplo anterior ao modificarmos a função desenho para: 
 
/*-----------------minha funcao desenho ( ) --------------------*/ 
 
void desenho(void) 
{ 
glClear (GL_COLOR_BUFFER_BIT); 
glBegin (GL_LINE_LOOP); 
 glColor3f (1.0, 0.0, 0.0); 
 glVertex2i (40, 130); 
 glColor3f (0.0, 1.0, 0.0); 
 glVertex2i (40, 30); 
 glColor3f (0.0, 0.0, 1.0); 
 glVertex2i (-20.0, 30); 
glEnd ( ); 
glFlush ( ); 
} 
 
 
Nas linhas em negrito no código acima foi verificada uma modificação em relação ao código visto 
anteriormente: o ponto a ser desenhado foi estabelecido fora dos limites do mundo definido pela 
função glOrtho. Como resultado vimos que o desenho foi cortado no ponto limite (y = 100) não 
sendo obtido o triângulo esperado. Esse conceito de “dimensão de mundo” será estudado com mais 
detalhes no capítulo 2 deste tutorial. 
 
8- Eventos de Mouse e Teclado 
 
Já temos conhecimento de todas as configurações necessárias para começarmos a programar com 
OpenGL. Fizemos nosso primeiro programa utilizando OpenGL e plotamos 3 pontos na janela de 
visualização. Sabemos que OpenGL é Orientada a Eventos de mouse Teclado e alteração de janela, 
e sabemos como especificar as funções callbacks responsáveis por gerenciar esses eventos. 
Entretanto, não sabemos ainda como utilizar esses eventos de mouse e teclado, o que podemos 
controlar e comopodemos controlar. Teremos abaixo um exemplo de programa utilizando eventos 
de mouse e teclado. É um exemplo simples, mas podemos adiantar que é possível o controle de 
eventos mais complexos e até de uma combinação de eventos utilizando o recurso das flags 
(variáveis de controle que guardam o estado atual de trabalho, podem guardar as opções escolhidas 
durante a execução do programa e a depender da sequência das opções realizar diferentes funções). 
Agora iremos direto ao exemplo para depois comentarmos os diferentes conceitos e funções 
desconhecidos: 
 
O exemplo abaixo desenha três pontos na tela, como em um anterior, mas tem seu desenho 
modificado a depender da ocorrência de eventos durante a execução do programa. Se for apertada 
alguma tecla com representação em ASCII é chamada a função teclado( ), se for alguma tecla sem 
representação em ASCII é chamada a função especiais ( ) e se for apertado o mouse será chamada a 
função mouse. Todas elas têm a mesma função simples de fechar a janela de visualização, mas cada 
um pode implementar qualquer outra alteração no programa a partir desses eventos. 
 
 
#include <stdlib.h> 
#include <GL/glut.h> 
 
int x1=-30, y1=-60, x2=30, y2=-60, x3=0, y3=60; 
 
/*-----------------minha funcao init ( ) ---------------------*/ 
void init (void) 
{ 
 glClearColor (0.0, 0.0, 0.0, 0.0); 
 glMatrixMode (GL_PROJECTION); 
 glLoadIdentity ( ); 
 gluOrtho2D (-50, 50, -100, 100); 
} 
 
/*-----------------minha funcao desenho ( ) ---------------------*/ 
void desenho (void) 
{ 
 glClear (GL_COLOR_BUFFER_BIT); 
 glBegin (GL_LINE_LOOP); 
 glColor3f (1.0, 1.0, 1.0); 
 glVertex2i (x1, y1); 
 glVertex2i (x2, y2); 
 glVertex2i (x3, y3); 
 glEnd (); 
 glFlush (); 
} 
 
/*-----------------minhas funções de mouse ( ) -----------------*/ 
void mouse (int button, int state, int x, int y) 
{ 
 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 
 { 
 exit (0); 
 } 
} 
 
/*-----------------minhas funções teclado ( ) -------------------*/ 
void teclado (unsigned char key, int x, int y) 
{ 
 switch (key) 
 { 
 case 27: 
 exit (0); 
 break; 
 case '+': 
 x1+=05; 
 y1+=05; 
 x2+=05; 
 y2+=05; 
 break; 
 case '-': 
 x1-=05; 
 y1-=05; 
 x2-=05; 
 y2-=05; 
 break; 
 } 
 glutPostRedisplay(); 
} 
 
void especiais (int key, int x, int y) 
{ 
 switch (key) 
 { 
 case GLUT_KEY_F4: 
 exit (0); 
 break; 
 } 
} 
 
/*-----------------main ---------------------*/ 
int main (int argc, char** argv) 
{ 
 glutInit (&argc, argv); 
 glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); 
 glutInitWindowSize (640, 480); 
 glutInitWindowPosition (100, 100); 
 glutCreateWindow ("Para fechar a janela: Bt Direito do Mouse ou F4 | Mover pontos: '+' ou '-' "); 
 glutDisplayFunc (desenho); 
 glutMouseFunc (mouse); 
 glutKeyboardFunc (teclado); 
 glutSpecialFunc (especiais); 
 init ( ); 
 glutMainLoop ( ); 
} 
 
Baseado no código acima comentaremos agora cada nova função e conceito utilizados, da mesma forma que 
fizemos anteriormente. 
 
GlutMouseFunc (mouse) – Essa função chama a função mouse ( ) como função callback 
que vai realizar todas as ações referentes aos eventos de clique no mouse. A função mouse recebe 
como parâmetros o botão acionado, o estado do botão, a posição do cursor no momento em que se 
acionou o botão. É possível trabalhar com o botão (GLUT_LEFT, GLUT_RIGHT, 
GLUT_MIDLE) e com o estado (GLUT_DOWN, GLUT_UP) 
 
GlutKeyboardFunc (teclado) – Essa função chama a função teclado ( ) sempre que uma 
tecla for apertada, identifica a tecla pelo código ASCII. Recebe como parâmetros o código ASCII 
da tecla em questão e a posição do cursor no momento em que a tecla for pressionada. 
 
GlutSpecialFunc (especiais) – Essa função chama a função especiais ( ) sempre que 
uma tecla "especial" for apertada, identifica a tecla por representações especiais da OpenGL. As 
teclas às quais a referência é feita através desta função são: 
 
GLUT_KEY_F1função para tecla F1 
GLUT_KEY_F2 função para tecla F2 
GLUT_KEY_F3 função para tecla F3 
GLUT_KEY_F4 função para tecla F4 
GLUT_KEY_F5 função para tecla F5 
GLUT_KEY_F6 função para tecla F6 
GLUT_KEY_F7 F7 função para tecla F7 
GLUT_KEY_F8 F8 função para tecla F8 
GLUT_KEY_F9 F9 função para tecla F9 
GLUT_KEY_F10 F10 função para tecla F10 
GLUT_KEY_F11 F11 função para tecla F11 
GLUT_KEY_F12 F12 função para tecla F12 
GLUT_KEY_LEFT função para direcional à esquerda 
GLUT_KEY_UP Up função para direcional acima 
GLUT_KEY_RIGHT função para direcional à direita 
GLUT_KEY_DOWN função para direcional abaixo 
GLUT_KEY_PAGE_UP função para tecla Page up 
GLUT_KEY_PAGE_DOWN função para tecla Page down 
GLUT_KEY_HOME função para tecla Home 
GLUT_KEY_END função para tecla End 
GLUT_KEY_INSERT função para a tecla Insert 
 
Notemos que as teclas TAB, ESC, espaço, backspace e delete têm código ASCII e não são 
consideradas teclas especiais. 
 
 
Capítulo II 
 
Trabalhando com Janelas 
 
w
w
w
w
Introdução ao conceito de Viewport 
Transformações em Viewport 
World Window X Viewport 
Trabalhando nas coordenadas do Mundo 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1- Introdução 
 
No capítulo anterior, todos os nossos desenhos eram feitos usando o sistema de coordenadas da tela: 
Divisão da janela de visualização em pixels, variando de 0 ao valor estabelecido como largura para 
a janela no eixo x e de 0 ao valor estabelecido como altura para a janela no eixo y. Dessa forma só 
é possível utilizar de valores positivos para representar aquilo que se deseja desenhar na tela, assim 
sendo são necessários valores muito altos para as coordenadas x e y se quisermos obter um 
desenho de tamanho razoável. Esses limites estabelecidos são chamados de limites de world 
window ou limites do mundo virtual criado pelo programador. 
 
Como solução para esse problema, entretanto, nós podemos não pensar em termos de pixels, mas 
sim em termos de variação das coordenadas x e y no universo dos reais (negativos, positivos, 
decimais). Dessa forma, é claro, teremos que encontrar uma relação entre as dimensões da figura no 
mundo virtual e as dimensões mostradas na tela para o usuário. 
 
Para entender melhor o que foi dito no parágrafo anterior é preciso conhecer os conceitos de world 
window e de Viewport. World window é conhecido como o retângulo cujas dimensões representa 
os limites que definem o mundo do programador. O programa só poderá atuar nas dimensões 
estabelecidas por esses limites. Nada poderá ser desenhado fora das posições especificadas como 
limites de mundo, o que não quer dizer que tudo o que for desenhado dentro desses limites será 
visualizado ao mesmo tempo na tela. Para isso existe o conceito de Viewport que é a função que 
define a porção do mundo virtual que será visualizado. Define o que será mostrado na janela de 
visualização, e essa definição é feita em relação aos limites do mundo virtual. 
 
A figura abaixo representa melhor essa definição: 
 
. 
 
 
 
 
 
 
 
 
 
 
Conhecendo os conceitos de Viewport e de World Window, precisamos agora de um bom exemplo 
que ilustre esses conceitos e possa introduzir o tratamento dado a eles pela OpenGL. 
 
O programa abaixo desenha um triângulo na janela e altera as especificações do world window e do 
viewport a partir de eventos de mouse e teclado. Com o mouse o usuário determina se quer alterar 
parâmetros da função de world window (botão esquerdo) ou de viewport (botão direito) e com o 
teclado determina se quer alterar altura (tecla ‘a’|’A’) ou largura (‘l’|’L’) e ainda se quer aumentar 
(‘+’)ou dimiuir (‘-‘) o valor desses parâmetros. Com esse programa o usuário poderá entender 
melhor o significadode cada conceito estudado e o que cada um modifica em um programa. 
 
#include <stdio.h> 
#include <stdlib.h> 
#include <gl/glut.h> 
 
#define LARG 300 
#define ALTU 300 
 
//<<<<<<<<<<<<<<<<<<<<<<<< prototipos e variaveis >>>>>>>>>>>>>>>>>>> 
 
GLint Larg = LARG; 
GLint Alt = ALTU; 
// variaveis do viewport 
GLint Base_vis=0; 
GLint Esq_vis=0; 
GLint Larg_vis = LARG; 
GLint Alt_vis = ALTU; 
// variaveis do WorldView 
GLint Base_mundo=0; 
GLint Esq_mundo=0; 
GLint Larg_mundo = LARG; 
GLint Alt_mundo = ALTU; 
 
GLint flag_mundo = 0; 
GLint flag_vis = 0; 
GLint altura; 
GLint largura; 
 
 
void init (void); 
void teclado (unsigned char key, int x, int y); 
void mouse (int button, int state, int x, int y); 
void desenho (void); 
void reshape (GLint Larg, GLint Alt); 
 
//<<<<<<<<<<<<<<<<<<<<<<<< main >>>>>>>>>>>>>>>>>>>>>> 
int main(int argc, char** argv) 
{ 
 glutInit (&argc, argv); 
 glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); 
 glutInitWindowSize (Larg, Alt); 
 glutInitWindowPosition (0, 0); 
 glutCreateWindow ("Estudando a Janela"); 
 glutDisplayFunc (desenho); 
 glutMouseFunc (mouse); 
 init (); 
 glutReshapeFunc( reshape ); 
 glutKeyboardFunc(teclado); 
 glutMainLoop (); 
 return (0); 
} 
//<<<<<<<<<<<<<<<<<<<<<<< init >>>>>>>>>>>>>>>>>>>> 
void init(void) 
 { 
 glClearColor(1.0,1.0,1.0,0.0); 
} 
//<<<<<<<<<<<<<<<<<<<<<<<< desenho >>>>>>>>>>>>>>>>> 
void desenho(void) 
{ 
glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
gluOrtho2D(Esq_mundo, Larg_mundo, Base_mundo , Alt_mundo); 
glViewport (Esq_vis,Base_vis, Larg_vis, Alt_vis); 
 glClear(GL_COLOR_BUFFER_BIT); 
glBegin(GL_POLYGON); 
 glColor3f(0,0,1); 
glVertex2i(0, 0); 
glColor3f(0,1,0); 
glVertex2i(0, ALTU); 
 glColor3f(1,0,0); 
glVertex2i(LARG, ALTU/2); 
glEnd(); 
glFlush(); 
} 
 
//<<<<<<<<<<<<<<<<<<<<<< Reshape >>>>>>>>>>>>>>>>>>> 
 
void reshape (GLint x, GLint y) 
{ 
Larg_vis=x;Alt_vis=y; 
glViewport (0, 0, Larg_vis, Alt_vis); 
 
} 
 
//<<<<<<<<<<<<<<<<<<<<<<< mouse >>>>>>>>>>>>>>>>>>>> 
void mouse(int button, int state, int x, int y) 
{ 
switch (button) 
{ 
case GLUT_LEFT_BUTTON: 
 flag_mundo=0; 
 flag_vis=1; 
if (state == GLUT_DOWN ) 
 { 
 printf ("viewport ligado\n"); 
 printf ("world window desligado\n"); 
 } 
break; 
case GLUT_RIGHT_BUTTON: 
flag_mundo=1; 
flag_vis=0; 
if ( state == GLUT_DOWN ) 
 { 
 printf ("world window ligado\n"); 
 printf ("viewport desligado\n"); 
 } 
break; 
} 
 } 
 
//<<<<<<<<<<<<<<<<<<<<<<< teclado >>>>>>>>>>>>>>>>>>>> 
void teclado (unsigned char key, int x, int y) 
{ 
switch (key) 
{ 
case '+': 
if (flag_mundo) 
 { 
if (altura) 
 { 
 if ( (Alt_mundo - 10) > 0 ) 
{ 
Alt_mundo+=10; 
} 
 } 
 if (largura) 
 { 
 if ( (Alt_mundo - 10) > 0 ) 
{ 
 Larg_mundo+=10; 
} 
 } 
 } 
 else if (flag_vis) 
 { 
if (altura) 
{ 
if ( (Alt_vis - 10) > 0 ) 
{ 
Alt_vis+=10; 
} 
} 
if (largura) 
{ 
if ( (Larg_vis - 10) > 0) 
{ 
Larg_vis+=10; 
} 
} 
 } 
 break; 
 case '-': 
if (flag_mundo) 
{ 
if (altura) 
{ 
if ( Alt_mundo > 10 ) 
{ 
Alt_mundo-=10; 
} 
} 
if (largura) 
{ 
if ( Larg_mundo > 10 ) 
{ 
Larg_mundo-=10; 
} 
} 
} 
else if (flag_vis) 
{ 
if (altura) 
{ 
Alt_vis-=10; 
} 
if (largura) 
{ 
Larg_vis-=10; 
} 
} 
break; 
 case 'a'|'A': 
altura= !altura; 
if (altura) 
printf ("altura ligada\n"); 
else 
printf ("altura desligada\n"); 
break; 
 case 'l'|'L': 
largura= !largura; 
if (largura) 
printf ("largura ligada\n"); 
else 
printf ("largura desligada\n"); 
break; 
 case 27: 
exit (0); 
 break; 
 } 
printf ("Altura Mundo = %d Largura Mundo = %d \nAltura Viewport = %d 
Largura Viewport = %d \n", Alt_mundo, Larg_mundo, Alt_vis, Larg_vis); 
 glutPostRedisplay (); 
} 
 
 
Agora iremos explicar o que aconteceu no exemplo acima... o que há de novo em termos de funções 
e conceitos de Computação Gráfica. 
 
Já são conhecidas muitas funções de configuração do programa, além das funções responsáveis por 
chamar as callbacks e manter a orientação a eventos da OpenGL. No nosso exemplo acima temos 
que: 
 
 
glutDisplayFunc (desenho) – A função callback de desenho é a função desenho, será chamada 
sempre que precisar ser redesenhado algo na janela. 
 
 
 
glutMouseFunc (mouse) – A função callback de mouse é a função mouse. Nesse exemplo a 
função possui tarefas para dois eventos: 
 
Quando é pressionado o botão esquerdo do mouse (button = GLUT_LEFT_BUTTON && state = 
GLUT_DOWN) é acionada uma flag (variável que guarda um estado, simula uma variável booleana, já 
que C não possui tipo booleano) chamada flag_vis. 
 
Quando é pressionado o botão direito do mouse ( button = GLUT_RIGHT_BUTTON && state = 
GLUT_DOWN ) é acionada uma flag chamada flag_mundo. 
 
Essas flags serão usadas em outras funções, como na função callback de teclado, da qual falaremos 
a seguir. 
 
 
glutKeyboardFunc (teclado) – A função callback de eventos de teclado é a função teclado. 
Nesse caso vimos que essa função está respondendo a 5 teclas diferentes: 
 
Quando é apertada a tecla 'a' minúscula ou maiúscula, é acionada uma flag chamada altura. 
 
Quando é apertada a tecla 'l' minúscula ou maiúscula, é acionada uma flag chamada largura. 
 
Quando é apertada a tecla '+' a função callback irá avaliar todas as flags já comentadas (altura, 
largura, flag_vis, flag_mundo) e irá incrementar a altura ou largura correspondente ao world 
window ou ao viewport, de acordo com as flags especificadas. 
 
Quando é apertada a tecla '-' a função callback irá avaliar todas as flags já comentadas (altura, 
largura, flag_vis, flag_mundo) e irá decrementar a altura ou largura correspondente ao world 
window ou ao viewport, da mesma forma que quando é apertada a tecla '+'. 
 
Esse exemplo retrata bem a Orientação a Eventos da OpenGL, além de mostrar as diferenças entre 
World Window e Viewport. O usuário verá o que acontece quando se altera cada uma dessas 
variáveis. 
 
glutReshapeFunc (reshape) – A função Reshape não havia sido apresentada. É uma função 
responsável por tratar os eventos de alteração de janela. Se o usuário mover a janela, ou alterar o 
seu tamanho é preciso uma função que garanta que o desenho irá acompanhar as transformações 
ocorridas com a janela, seja alterando suas dimensões ou simplesmente a posição em que é 
desenhado na tela. 
 
No nosso caso, a função Reshape recebeu apenas a Viewport: 
 
glViewport (x, y, largura, altura)- Especifica a janela de visualização, diz o retângulo 
observado pelo usuário. Os parâmetros definem as dimensões do novo retângulo de viewport em 
relação ao retângulo atual, onde: 
 
x, y - Especifica o canto esquerdo inferior do retângulo de Viewport, em pixels. 
 
largura, altura - Especificam a largura e a altura, respectivamente, do retângulo de Viewport. 
Quando as dimensões da janela são alteradas, essas variáveis são atualizadas automaticamente. 
 
O importante de nosso estudo atual é perceber que O Viewport pode ter várias utilidades em nossos 
programas. Pode simplesmente atualizar a janela de visualização e garantir a proporção entre o 
desenho da tela e as dimensões da mesma, mas também simular um zoom na imagem. 
 
Sendo o canto inferior esquerdo da tela representado por duas variáveis na função Viewport, 
podemos alterar a origem de nossa área de visualização da forma que entendermos melhor. Dessa 
forma podemos fazer uma espécie de recorte na imagem, utilizando apenas uma parte da imagem 
para mostrar na mesma janela de visualização na qual mostramos a imagem completa. No exemploacima não temos o canto inferior esquerdo da área de visualização representado por variáveis, mas 
você poderia implementar uma função de teclado que agisse sobre essas variáveis, a serem criadas 
por você. 
 
 
Capítulo III 
 
w
w
w
Desenvolvendo ferramentas para transformar uma figura em outra. 
Introduzir conceitos fundamentais de transformações, abrangendo rotação, translação e escala. 
Desenvolver funções que aplicam transformações aos objetos em programas de computador. 
 
 
 
Vimos como trabalhar com OpenGL. Já conseguimos desenhar gráficos simples em 2D, mas na 
computação Gráfica os programas raramente são estáticos. Os desenhos não são feitos para se 
admirar, mas para serem manipulados, estudados. 
 
Assim como na álgebra se usa de transformações lineares para modificar gráficos, também na 
computação gráfica esses tipos de transformações são usados para dinamizar os programas. 
Transformações de Translação, Rotação e de Escala da figura obtida são as mais comuns. Além das 
transformações lineares citadas há as transformações de câmera - que não modificam o objeto 
desenhado, mas permitem modificar o ângulo e posição de visão da cena desenhada entre outras 
coisas, manipulando a câmera. 
 
Transformações 
 
Na álgebra as transformações lineares podem ser representadas por matrizes que representam a 
transformação geométrica desejada: Rotação, Escala, Cizalhamento .... Também em programas que 
utilizam OpenGL são usadas matrizes para guardar as transformações realizadas sobre objetos ou 
sobre a câmera, mas vamos nos ater às transformações sobre o objeto por enquanto, transformações 
estas que incluem ainda a Translação, que não é Transformação Linear porque sua aplicação sobre a 
origem não retorna a origem. Essas matrizes são chamadas de Matrizes de Transformação. Elas 
guardam a posição do objeto em determinado instante e tornam possível serem realizadas 
transformações sobre transformações. 
 
No exemplo abaixo vemos um exemplo de transformações, nele utilizamos as funções glRotate e 
glTranslate que internamente são tratadas pela OpenGL como matrizes. No caso desse exemplo 
temos um cubo que gira e se move a partir de comandos do teclado. 
 
#include <stdlib.h> 
#include <GL/glut.h> 
 
//<<<<<<<<<<<<<<<<<< Variáveis Globais>>>>>>>>>>>>>>>>>> 
 
int rotaciona=1, translada=0, escala=0; 
int largura, altura; 
float angle=0, t_x=0, t_y=0,e_x=1,e_y=1; 
 
//<<<<<<<<<<<<<<<<<<<< Protótipos >>>>>>>>>>>>>>>>>>>>>>> 
 
void teclado (int key, int x, int y); 
void reshape (int largura, int altura); 
void desenho (void); 
void init(void); 
 
//<<<<<<<<<<<<<<<<<<<< Main >>>>>>>>>>>>>>>>>>>>>>> 
 
int main (int argc, char** argv) 
{ 
 glutInit (&argc, argv); 
 glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); 
 glutInitWindowSize (300, 300); 
 glutInitWindowPosition (10, 10); 
 glutCreateWindow ("Transformações"); 
 glutDisplayFunc (desenho); 
 glutKeyboardFunc (teclado); 
 glutReshapeFunc (reshape); 
 init (); 
 glutMainLoop (); 
 return (0); 
} 
 
 
void init(void) 
 { 
 glClearColor(1.0,1.0,1.0,0.0); 
 glMatrixMode(GL_PROJECTION); 
 glLoadIdentity(); 
 gluOrtho2D(-100, 100, -50, 50); 
} 
 
//<<<<<<<<<<<<<<<<<<<< Desenho>>>>>>>>>>>>>>>>>>>>>>> 
void desenho (void) 
{ 
 glClear(GL_COLOR_BUFFER_BIT); 
 glMatrixMode(GL_MODELVIEW); 
 glLoadIdentity(); 
 
 glTranslatef (t_x, t_y,0); 
 glRotatef (angle, 0, 0, 1); 
 glScalef (e_x, e_y, 1); 
 
 glBegin(GL_POLYGON); 
 glColor3f(0,0,1); 
 glVertex2i(0, 0); 
 glColor3f(0,1,0); 
 glVertex2i(0, 20); 
 glColor3f(1,0,0); 
 glVertex2i(30, 10); 
 glEnd(); 
 glFlush(); 
} 
 
//<<<<<<<<<<<<<<<<<<<< Teclado >>>>>>>>>>>>>>>>>>>>>>> 
 
void teclado (unsigned char key, int x, int y) 
{ 
 if (translada) 
 { 
 switch (key) 
 { 
 case '+': 
 t_x+=10; 
 break; 
 case '-': 
 t_x-=10; 
 break; 
 } 
 } 
 
 
 if (rotaciona) 
 { 
 switch (key) 
 { 
 case '+': 
 angle+=10; 
 break; 
 case '-': 
 angle-=10; 
 break; 
 } 
 } 
 
 if (escala) 
 { 
 switch (key) 
 { 
 case '+': 
 e_x+=1; 
 break; 
 case '-': 
 e_x-=1; 
 break; 
 } 
 } 
 
 switch (key) 
 { 
 case 't'|'T': 
 translada = !translada; 
 break; 
 case 'r'|'R': 
 rotaciona = !rotaciona; 
 break; 
 case 'e'|'E': 
 escala = !escala; 
 break; 
 
 } 
 printf("Translada=%c\n",translada?'V':'F'); 
 printf("Rotaciona=%c\n",rotaciona?'V':'F'); 
 printf("Escala =%c\n",escala?'V':'F'); 
 printf("X=%f\n",t_x); 
 printf("Angulo=%f\n",angle); 
 printf("Escala=%f\n\n",e_x); 
 glutPostRedisplay(); 
} 
 
 
//<<<<<<<<<<<<<<<<<<<< Reshape >>>>>>>>>>>>>>>>>>>> 
 
void reshape (int largura, int altura) 
{ 
 glViewport (0, 0, largura, altura); 
} 
 
 
 
Iremos agora falar das novidades do programa, das novas funções e dos novos conceitos. É preciso 
treinar, e por isso preferimos colocar um exemplo mais geral e comentar pouco a pouco as 
novidades. 
 
No exemplo dado, trabalhamos com 3 coordenadas (x, y, z) mas representamos apenas 2 
Dimensões pois mantivemos a coordenada z com valor fixo. 
 
GlTranslate (t_x, t_y, t_z) – Para transladar um sistema é preciso multiplicar todos 
os pontos do sistema de coordenadas por uma matriz de translação. A função GLTranslate cria uma 
matriz de translação a partir dos parâmetros tx, ty, tz . As constantes t_x, t_y, t_z serão os valores a 
serem somados às respectivas coordenadas x, y e z. 
 
GlRotate (angle, r_x, r_y, r_z) – Para rotacionar um sistema de coordenadas é preciso multiplicar 
as coordenadas atuais por uma matriz de rotação. A função GLRotate cria uma matriz de rotação a 
partir dos parâmetros angle ( que indica o ângulo de rotação ), r_x, r_y e r_z (que descrevem as 
coordenadas de um vetor que definirá o eixo de rotação). No exemplo trabalhado os valores das 
coordenadas do eixo de rotação foram 0,0,1, o que significa que o sistema vai girar em torno do 
eixo z, que é o eixo perpendicular ao plano da tela. 
 
GlScale (e_x, e_y, e_z) – Para escalonar um sistema de coordenadas é preciso 
multiplicar cada coordenada de um objeto por um fator de escala. Através dos parâmetros e_x, e_y, 
e_z, que representam os fatores de escala relativos a cada eixo coordenado, a função GLScale 
realiza essa transformação . 
 
GlLoadIdentity – A função GLLoadIdentity carrega a matriz identidade na matriz de 
transformações no Pipeline do OpenGL. O conceito de Pipeline será visto em uma futura lição. 
 
GlMatrixMode () – Todas as transformações acima são feitas sobre o objeto, é importante 
especificar que as transformações podem ser sobre os objetos e sobre a câmera. O que vai 
determinar que tipo de transformação será realizada é a função GLMatrixMode. Para que as 
transformações sejam realizadas sobre o objeto (sistema de coordenadas) o parâmetro dessa função 
deve ser GL_MODELVIEW e para que sejam efetuadas sobre a câmera o parâmetro deve ser 
GL_PROJECTION. Os conceitos de câmera serão vistos no próximo capítulo. 
Capítulo IV 
 
• Transformações de Câmera 
• Conceitos de Visualização 
• Conceitos de Visualização 3D 
• Conceitos de Câmera 
• Funções de Câmera 
 
 
Vimos no capítulo anterior como manipular as imagens através de transformações diretas no objeto 
desenhado. Mas as manipulações de cena podem ser feitas sob o ponto de vista do observador sem 
que seja alterado o objeto desenhado. Essas manipulações são possíveis através das transformações 
de câmera da OpenGL. 
 
Assim como nas transformações do objeto, nas transformações de câmera é necessária a utilização 
de Matrizes de Transformação, que agora deixam de ser do tipo GL_ModelViewe passam a ser do 
tipo GL_Projection. Elas guardam a posição da câmera, o ângulo do campo de visão do observador 
e outros parâmetros que podem modificar o modo como se vê a cena, se alterados. 
 
Entre outras coisas, será possível “viajar” pela imagem gerada com a modificação da posição da 
câmera de observação, será possível observar a imagem em seus mínimos detalhes através do efeito 
de zoom obtido com a diminuição do ângulo do volume de visão do observador. 
 
No exemplo abaixo vemos como trabalhar com câmeras em OpenGL é simples. Utilizamos nele as 
funções gluPerspective e gluLookAt. Essas duas funções apenas permitem inúmeras transformações 
como será observado no exemplo: 
 
 
#include <stdlib.h> 
#include <GL/glut.h> 
 
//<<<<<<<<<<<<<<<<<< Variáveis Globais>>>>>>>>>>>>>>>>>> 
 
int projecao =1;//inicializa como perspective 
 
float graus=60.0; 
float Aspecto=1.0; 
float Zmin=0.01; 
float Zmax=1000.0; 
float Xmin=-150; 
float Xmax=150.0; 
float Ymin=-100; 
float Ymax=100.0; 
 
float CamX=0; 
float CamY=60; 
float CamZ=200; 
float FocoX=0; 
float FocoY=0; 
float FocoZ=0; 
float NormalX=0; 
float NormalY=1; 
float NormalZ=0; 
 
//<<<<<<<<<<<<<<<<<<<< Protótipos >>>>>>>>>>>>>>>>>>>>>>> 
 
void teclado (unsigned char key, int x, int y); 
void desenha (void); 
void init(void); 
 
//<<<<<<<<<<<<<<<<<<<< Main >>>>>>>>>>>>>>>>>>>>>>> 
 
int main (int argc, char** argv) 
{ 
 glutInit (&argc, argv); 
 glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB| GLUT_DEPTH); 
 glutInitWindowSize (600,400 ); 
 glutInitWindowPosition (0, 0); 
 glutCreateWindow ("Projeções"); 
 glutDisplayFunc (desenha); 
 glutKeyboardFunc (teclado); 
 init (); 
 glutMainLoop (); 
} 
 
void init () 
{ 
 glClearColor (0,0,0, 0); 
 glEnable (GL_DEPTH_TEST); 
} 
 
//<<<<<<<<<<<<<<<<<<<< Desenho>>>>>>>>>>>>>>>>>>>>>>> 
 
void desenha (void) 
{ 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
 glMatrixMode(GL_PROJECTION); 
 glLoadIdentity(); 
 if (projecao) 
 { 
 gluPerspective(graus,Aspecto,Zmin,Zmax); 
 } 
 else 
 { 
 glOrtho (Xmin, Xmax, Ymin, Ymax, Zmin, Zmax); 
 } 
 glMatrixMode (GL_MODELVIEW); 
 glLoadIdentity (); 
 
 gluLookAt(CamX,CamY,CamZ,FocoX,FocoY,FocoZ, NormalX,NormalY,NormalZ ); 
 glBegin(GL_LINES); 
 glVertex3i(0,0,0); 
 glVertex3i(100,0,0); 
 glVertex3i(0,0,0); 
 glVertex3i(0,100,0); 
 glVertex3i(0,0,0); 
 glVertex3i(0,0,100); 
 glEnd(); 
 glPushMatrix (); 
 glTranslatef(0,0,-200); 
 glColor3f(0,1,0); 
 glutWireTeapot(40.0f); 
 glPopMatrix (); 
 glColor3f(1,1,1); 
 glutWireTeapot(40.0f); 
 
 glutSwapBuffers(); 
} 
 
//<<<<<<<<<<<<<<<<<<<< Teclado >>>>>>>>>>>>>>>>>>>>>>> 
 
void teclado (unsigned char tecla, int x, int y) 
{ 
 switch (tecla) 
 { 
 case '+': 
 CamZ+=10; 
 break; 
 case '-': 
 CamZ-=10; 
 break; 
 case 27: 
 exit (1); 
 break; 
 case 'p'|'P': 
 projecao = !projecao; 
 break; 
 } 
 glutPostRedisplay(); 
} 
 
O exemplo acima possui dois Teapots, um localizado no centro do eixo de coordenadas e outro 
transladado para uma posição atrás do primeiro Teapot. Há a função de teclado que permite 
modificar o tipo de projeção de Ortogonal para em Perspectiva. Com isso é possível compreender 
as diferenças entre as projeções na prática. 
 
 
 
Projeção Ortogonal não diferencia a distância que o sólido está do observador para representa-lo na 
tela. Se representarmos dois objetos de mesmas dimensões, um a 30 metros e um a 50 metros do 
observador, na imagem gerada na tela não haverá diferenças entre eles. 
 
Projeção em Perspectiva procura ser mais fiel à realidade e define que um objeto mais distante da 
câmera terá dimensões menores na tela do que um mais próximo da câmera. 
 
É importante observar que foi usada uma imagem em 3 Dimensões para trabalharmos com câmera. 
É impossível trabalhar com câmera sem trabalhar em 3 Dimensões, ou seja, sem trabalhar com 3 
Coordenadas (x, y, z). Utilizamos a função glutWireTeapot que é uma ferramenta pronta da 
GLUT que desenha um objeto sólido chamado de TeaPot. Essa função da OpenGL tem um fim 
principalmente didático. 
 
Por se tratar de uma imagem em 3D, percebemos que foi usado um parâmetro diferente para a 
função glutInitDisplayMode e para a função GLClear. 
Um dos parâmtros utilizados para a primeira foi o GLUT_DOUBLE, ou seja, que serão usados 2 
buffers para desenhar o objeto na tela: um para desenhar na tela diretamente e outro para fazer as 
transformações necessárias durante a animação da imagem. Um buffer fica oculto e transfere a 
imagem gerada completa depois das transformações para a tela, evitando efeitos indesejáveis como 
o piscar da imagem. 
Outro parâmetro utilizado nessa mesma função foi o GL_DEPTH_BUFFER, que significa que 
haverá um Buffer exclusivo para as imagens com profundidade (afinal, profundidade é diferente de 
3 Dimensões). O DEPTH_BUFFER é responsável por garantir que não serão desenhadas imagens 
ocultas na tela, que a face oculta de um objeto em 3 Dimensões (a parte de trás do objeto) não 
aparecerá indevidamente. 
Na função GL_Clear fica especificado que o DEPTH_BUFFER deverá ser limpo sempre que se 
limpar a tela de visualização. 
 
 
 
Vamos abaixo especificar o que faz cada função de câmera vista no exemplo acima. 
 
GL_PROJECTION – Esse é o parâmetro da função GL_MATRIX_MODE para especificar que as 
transformações atuais se referem à câmera e não ao objeto. Representa dizer que a projeção da 
imagem em 3D srá feita em Perspectiva e não de forma Ortogonal. 
 
GluPerspective () – Esta função é responsável por garantir que o volume de visualização 
será uma Pirâmide. A função define o ângulo do volume de visualização (que quando menor for, vai 
capturar imagens mais detalhadas de espaços menores do sólido gerado ), a relação entre a altura e a 
largura da imagem visualizada (gerando distorções na imagem, deixando-a mais estreita ou larga, 
comprida ou curta...), o ponto mais perto a ser observado (primeiro limite de visualização) e o ponto 
mais distante a ser observado (segundo limite de visualização). 
 
GluLookAt () – Esta função recebe 9 parâmetros sendo os três primeiros para definir as 
coordenadas x, y e z do ponto no espaço tridimensional em que a câmera se encontra. Os três 
parâmetros seguintes indicam as coordenadas x,y,z do ponto no espaço tridimensional para onde a 
câmera está focando e os três últimos parâmtros definem o vetor normal da câmera, ou seja, o vetor 
perpendicular à câmera (indica qual o “lado de cima” da câmera). 
 
 
Com isso, vimos mais um conceito da programação gráfica utilizando OpenGL. Mas sabemos que 
ainda há muito que estudar. O exemplo deste capítulo tem muitas funções que não vimos a 
especificação porque não estudamos ainda os conceitos, mas as usamos para termos um bom 
exemplo sobre um conceito difícil de se compreender (câmera de visualização e suas 
transformações) e para mostrar um pouquinho do que a OpenGL é capaz, deixando um gostinho de 
“quero estudar mais” no ar. 
 
Não nos esqueçamos que esta é apenas a primeira versão do nosso tutorial de OpenGL. Num futuro 
breve, estaremos divulgando novos materiais com novos conceitos e a mesma vontade de ajudar no 
aprendizado da Computação Gráfica. 
 
Maiores informações no site http://twiki.im.ufba.br/Fractais ou por email para brown@im.ufba.br 
ou vivas@ufba.br. 
 
Boa Sorte nos estudos!!!!!!!!!!! 
 
Até uma próxima versão!!!!!!!!!!!

Outros materiais