54
12.3. Deteminação da projeção A projecao usada pelo programa e determinada pela funcao OnResize: void OnResize (int width, int height) { glViewport (0, 0, width, height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (-12.0f, 12.0f, -12.0f, 12.0f, -12.0f, 12.0f); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); } A primeira linha determina que a viewport usada pelo programa corresponde a janela inteira. A projecao usada pelo programa e uma projecao ortografica com as mesmas medidas em todos os eixos. Durante o ciclo de vida da aplicacao, esse evento e executado pelo menos uma vez (depois que o laco principal de execucao e iniciado). 50 UFF - Mestrado em Computacao Luis Valente 12.4. Atualização A funcao OnUpdate atualiza a posicao do quadrado e verifica se existiu alguma colisao contra as bordas da janela (viewport, na verdade). Caso exista, a posicao do quadrado e corrigida e a sua velocidade e invertida (no eixo onde ocorreu a colisao). O quadrado possui aresta de tamanho igual a 4 unidades. void OnUpdate () { quad_x += vx; quad_y += vy; quad_z += vz; if (quad_x > 10.0f || quad_x < -10.0f) vx = - vx; if (quad_y > 10.0f || quad_y < -10.0f) vy = - vy; if (quad_z > 10.0f || quad_z < -10.0f) vz = - vz; glutPostRedisplay (); }

aula sobre c++

Embed Size (px)

DESCRIPTION

aulas sobre c++

Citation preview

12.3. Deteminao da projeoA projecao usada pelo programa e determinada pela funcao OnResize:void OnResize (int width, int height){glViewport (0, 0, width, height);glMatrixMode (GL_PROJECTION);glLoadIdentity ();glOrtho (-12.0f, 12.0f, -12.0f, 12.0f, -12.0f, 12.0f);glMatrixMode (GL_MODELVIEW);glLoadIdentity ();}A primeira linha determina que a viewport usada pelo programa corresponde a janela inteira. Aprojecao usada pelo programa e uma projecao ortografica com as mesmas medidas em todos oseixos.Durante o ciclo de vida da aplicacao, esse evento e executado pelo menos uma vez (depois queo laco principal de execucao e iniciado).50UFF - Mestrado em Computacao Luis Valente12.4. AtualizaoA funcao OnUpdate atualiza a posicao do quadrado e verifica se existiu alguma colisao contraas bordas da janela (viewport, na verdade). Caso exista, a posicao do quadrado e corrigida e a suavelocidade e invertida (no eixo onde ocorreu a colisao). O quadrado possui aresta de tamanho iguala 4 unidades.void OnUpdate (){quad_x += vx; quad_y += vy; quad_z += vz;if (quad_x > 10.0f || quad_x < -10.0f)vx = - vx;if (quad_y > 10.0f || quad_y < -10.0f)vy = - vy;if (quad_z > 10.0f || quad_z < -10.0f)vz = - vz;glutPostRedisplay ();}A funcao glutPostRedisplay informa ao freeglut que e necessario redesenhar o conteudoda janela. Se essa funcao nao for usada, nao sera possivel visualizar as alteracoes.12.5. TecladoA funcao OnKeyPress recebe como parametros a tecla que foi pressionada e a posicao domouse no momento em que a tecla foi pressionada.void OnKeyPress (unsigned char key, int x, int y){switch (key){case 'q': case 'Q' :exit (0); break;}}Existem outras funcoes para se tratar eventos do teclado, que podem ser consultadas nadocumentacao do freeglut ou do GLUT.53

12.6. RenderizaoA funcao responsavel pela renderizacao inicia com a requisicao para que a tela e o z-buffersejam limpos.51UFF - Mestrado em Computacao Luis ValenteA seguir, a matriz identidade e carregada, para que o sistema de coordenadas seja reiniciadopara a origem.void OnRender (){glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity ();glTranslatef (quad_x, quad_y, quad_z);glColor3f (1.0f, 0.0f, 0.0f);glBegin (GL_QUADS);glVertex3f (2.0f, 2.0f, 0.0f);glVertex3f (-2.0f, 2.0f, 0.0f);glVertex3f (-2.0f, -2.0f, 0.0f);glVertex3f (2.0f, -2.0f, 0.0f);glEnd ();glutSwapBuffers ();}A seguir, e necessario posicionar o quadrado, o que e feito com o comando glTranslatef.O quadrado e, entao, especificado.A funcao glutSwapBuffers requisita que o buffer usado para as operacoes de renderizacaoseja exibido na tela.13. ConclusesOpenGL e uma API muito rica e cheia de recursos. Este trabalho aborda apenas uma parte doque poderia ser usado.Existem tutoriais e outros recursos para se aprender mais sobre OpenGL em varios lugares nainternet. Aqui estao alguns deles: Site oficial do OpenGL: http://www.opengl.org Nate Robins Programas interativos com demonstracao de varios conceitos sobreOpenGL: http://www.xmission.com/~nate/tutors NeHe Tutoriais variados sobre OpenGL: http://nehe.gamedev.net GameTutorials Varios tutoriais sobre OpenGL, com enfoque para programacao de jogos:http://www.gametutorials.com JOGL Biblioteca para uso OpenGL em Java: https://jogl.dev.java.net Dephi3D OpenGL e programacao 3D com Delphi: http://www.delphi3d.net52UFF - Mestrado em Computacao Luis Valente14. Referncias BibliogrficasOGL04 OpenGL, site oficial: http://www.opengl.org, 2004WrSw99 Wright, Richard S.; Sweet, Michael OpenGL SuperBible Second Edition, WaiteGroup Press, 1999NeDa97 Neider, Jackie; Davis, Tom OpenGL Programming Guide, 2nd Edition,Addison-Wesley, 1997FGLUT04 freeglut, site oficial: http://freeglut.sourceforge.net, 2004DEVIL04 DevIL, site oficial: http://www.imagelib.org, 2004

1. IntroduoOpenGL (Open Graphics Library) e uma biblioteca (API1) para Computacao Grafica 3D e 2Dque foi desenvolvida inicialmente por Silicon Graphics Inc. (SGI). Atualmente, e adminstrada pelaARB (Architecture Review Board)2. A ARB e uma entidade que congrega varios representantes daindustria, como SGI, Intel, NVIDIA e Sun Microsystems.A API do OpenGL oferece algumas primitivas basicas (como pontos, linhas, triangulos,quadrilateros e poligonos), operacoes para manipulacao do sistema de coordenadas e operacoes commatrizes (translacao, rotacao e escala) e efeitos como mapeamento de textura, entre outroscomandos.OpenGL foi projetado para ser utilizado em varias plataformas e sistemas operacionais, comoMac OS, OS/2, Unix, Windows, Linux, OPENStep e BeOS. Pode ser utilizado em diversosambientes de desenvolvimento de linguagens de programacao como Delphi, Visual Basic, C/C++,Java, Fortran e Python, entre outros. Devido a esse proposito, existem varias funcionalidades quenao estao disponiveis em OpenGL, porque sao dependentes da plataforma nativa. Entre essasfuncionalidades, encontram-se janelas (e interface grafica), fontes para texto e comandos parainteracao com o usuario (como processamento de eventos do teclado e mouse).A versao atual do OpenGL e 1.53. A biblioteca possui dois componentes principais: GL: Representa o nucleo do OpenGL, que agrega as funcoes principais. GLU: E uma biblioteca utilitaria, que possui funcoes diversas para quadrics, NURBS ematrizes, entre outras.Uma caracteristica importante de OpenGL e que o OpenGL e uma API de modo imediato(immediate mode). Em APIs de modo imediato, os comandos submetidos alteram o estado dohardware grafico assim que sao recebidos. O estado do hardware grafico representa um tipo deconfiguracao que esta em uso no momento, e como essa configuracao e aplicada internamente pelohardware. Por exemplo, uma aplicacao pode utilizar iluminacao em uma cena. Desta forma, diz-seque o estado de iluminacao esta ligado. Quando esse estado e ligado, o hardware e configuradointernamente para realizar uma serie de operacoes que tem a ver com essa funcionalidade.2. Usando OpenGLNo sistema operacional Windows, o OpenGL ja esta pronto para uso (em modo simulado, porsoftware, pelo menos). A implementacao da biblioteca esta contida em arquivos DLL (opengl32.dlle glu32.dll) no Windows e em arquivos .so (libGL.so, libGLU.so) no Linux.Para utilizar plenamente os recursos oferecidos pelo hardware com o OpenGL, e precisoinstalar o driver especifico da placa grafica. Esses drivers podem ser encontrados nos sites dosfabricantes dos chipsets da placa grafica (como NVIDIA4 ou ATI5). No Linux, uma das solucoes einstalar a Mesa3D6, que e uma implementacao nao-oficial da API do OpenGL. Alguns fabricantes(como a NVIDIA) oferecem drivers nativos para Linux, que podem ser obtidos no site da empresa.1 Application Programming Interface2 http://www.opengl.org/about/arb/3 A versao 2.0 ja esta sendo desenvolvida.4 http://www.nvidia.com5 http://www.ati.com6 http://www.mesa3d.org2UFF - Mestrado em Computacao Luis Valente2.1. Configurao inicialEsta secao contem instrucoes de configuracao do ambiente de desenvolvimento para criaraplicacoes com OpenGL.Grande parte dos compiladores C e C++ disponiveis ja possuem os arquivos necessarios para sedesenvolver programas com OpenGL. Entretanto, a versao do OpenGL que pode ser usada atravesdesses arquivos pode variar bastante. A versao que vem com o Visual C++ e 1.1, enquanto oMinGW (GCC para Windows) possui a versao 1.3.2.2. Visual C++Para usar o OpenGL com o Visual C++, e preciso incluir os seguintes arquivos nos programas:#include #include #include O arquivo gl.h possui as funcoes principais do OpenGL, enquanto o glu.h possui as funcoes dabiblioteca utilitaria.Os arquivos de ligacao com as DLLs sao dois: opengl32.lib e glu32.lib (caso se use a GLU).Esses arquivos podem ser incluidos nos projetos da seguinte forma: Visual C++ 6: Acesse o menu Projects e depois Settings. A seguir, acesse a abaLinker. No campo Object/library modules acrescente opengl32.lib glu32.lib (semaspas). Visual C++ 7 (.NET): Acesse o menu Project e depois Properties. No painel daesquerda, escolha a pasta Linker e depois Input. No campo Additional dependencies,acrescente opengl32.lib glu32.lib (sem aspas).E necessario incluir o arquivo principal do Windows (windows.h), antes dos arquivos doOpenGL ou erros de compilacao serao gerados.2.3. GCCPara usar o OpenGL com o GCC, e preciso incluir os seguintes arquivos nos programas:#include #include O arquivo gl.h possui as funcoes principais do OpenGL, enquanto o glu.h possui as funcoes dabiblioteca utilitaria.Os arquivos de ligacao com as DLLs podem ser especificados atraves dos parametros-lopengl32 e -lglu32 (caso se use a GLU), tanto em Windows quanto em Linux.2.4. ConvenesTodos os comandos do OpenGL seguem uma convencao, que pode ser observada na Figura 2.1.3UFF - Mestrado em Computacao Luis ValenteO comando retratado na figura possui as seguintes caracteristicas: Um prefixo que indica de qual parte da API o comando pertence. Alguns valores possiveissao gl (funcoes principais), glu (biblioteca utilitaria), wgl (funcoes especificas para Windows),glx (funcoes especificas para Unix/X11) e agl (funcoes especificas para Mac OS). O nome principal do comando. O exemplo da figura representa um comando para sealterar a cor atual. O numero de argumentos aceitos pela funcao. A funcao do exemplo aceita 3 argumentos. O tipo dos argumentos. No exemplo, o tipo dos argumentos e ponto flutuante. Dessaforma, a funcao aceita 3 numeros de ponto flutuante.Como um dos objetivos do OpenGL e ser independente de plataforma, sao definidos variostipos de dados, que sao descritos na tabela 1.Sufixo Tipo de dado Tipo definido no OpenGL Tipo correspondentena linguagem Cb inteiro 8 bits GLbyte signed chars inteiro 16 bits GLshort shorti inteiro 32 bits GLint, GLsizei int, longf ponto flutuante 32 bits GLfloat, GLclampf floatd ponto flutuante 64 bits GLdouble, GLclampd doubleub inteiro 8 bits sem sinal GLubyte, GLboolean unsigned charus inteiro 16 bits sem sinal GLushort unsigned shortui inteiro 32 bits sem sinal GLuint, GLenum, GLbitfield unsigned int, unsignedlongv array, e usado em conjunto com os outrosTabela 2.1 Tipos de dados do OpenGL4Figura 2.1 Comando tpico do OpenGL (WrSw99)UFF - Mestrado em Computacao Luis ValenteE comum que existam diversas variacoes de comandos, que diferem entre si pelo tipo e numerode argumentos aceitos. Exemplos:glColor3f (1.0f, 1.0f, 1.0f);GLfloat color [3];glColor3fv (color);3. Sistemas de janelasDevido a portabilidade do OpenGL, a API nao possui funcoes para lidar com sistemas dejanelas, cujas caracteristicas dependem do sistema operacional usado. Esse e o primeiro problema aser enfrentado pelo desenvolvedor, ja que para usar o OpenGL e preciso abrir uma janela.Eventualmente, a aplicacao tera que interagir com o usuario, quando sera necessario tratar eventosrelacionados com o teclado e o mouse.O desenvolvedor possui duas opcoes: Usar a API especifica do sistema operacional. Essa opcao torna a aplicacao dependente dosistema operacional. Entretanto, e possivel utilizar caracteristicas avancadas (e/ou otimizadas)relacionadas ao sistema sistemas. Obviamente, sera preciso aprender a utilizar a API dosistema operacional escolhido. Usar algum toolkit ou biblioteca que ofereca uma abstracao para o sistema de janelas.Existem varios exemplos de ferramentas desse tipo disponiveis na internet. Muitas delas estaodisponiveis para varios sistemas operacionais e possuem o codigo aberto. Suas APIsgeralmente sao bem mais faceis de aprender (e menos complexas) do que as APIs de sistemasoperacionais especificos. Entretanto, por tentar oferecer caracteristicas que sejam comuns avarios sistemas operacionais, podem ter algumas limitacoes em termos de funcionalidades.A opcao a se tomar depende dos objetivos da aplicacao.Como o objetivo deste trabalho e ensinar OpenGL somente, a segunda opcao foi escolhida aqui.O toolkit usado neste trabalho e o freeglut7.O freeglut e uma biblioteca de codigo aberto que esta disponivel em diversas plataformas. Ela eoriginaria do GLUT (OpenGL utility toolkit), que era o toolkit padrao para demonstrar conceitossobre OpenGL. Dessa forma, e possivel encontrar na internet varios programas com exemplos deutilizacao de OpenGL escritos com o GLUT. Entretanto, o GLUT nao e mais desenvolvido (suaultima versao e de 1998).3.1. Instalao do freeglutEsta secao assume que o compilador utilizado e o Visual C++. Inicialmente, e preciso ir no site(http://freeglut.sourceforge.net/) do freeglut e baixar o codigo fonte.7 http://freeglut.sourceforge.net/5UFF - Mestrado em Computacao Luis Valente3.1.1. CompilaoA seguir, e preciso compilar o codigo fonte para gerar as DLLs e arquivos .lib. Para isso,descompacte o arquivo para um diretorio qualquer (ex: c:\freeglut). Depois, basta abrir o arquivo doworkspace (freeglut.dsw). Esse arquivo de projeto foi construido para ser usado com o Visual C++6, mas pode ser utilizado pelo Visual C++ .NET sem problemas.Nesse workspace, constam dois projetos: o freeglut_static e o freeglut (que esta selecionado porpadrao). O primeiro e usada para se construir uma biblioteca estatica e o outro para se construir aDLL. Neste trabalho, sera usada a versao em DLL.Para compilar o projeto, e preciso acessar o menu Build e depois Build freeglut.dll, caso ocompilador seja o Visual C++ 6. Se for o Visual C++ .NET, os menus sao Build e depois Buildfreeglut.Essas instrucoes geram a versao debug da DLL. Caso se queira gerar a versao release(recomendado), basta acessar os menus Build, Set active configuration e escolher freeglut Win32 Release, no Visual C++ 6. No Visual C++ .NET, o caminho e Build, ConfigurationManager ... e escolher Release em Active Solution Configuraration. A seguir e precisoconstruir a DLL como explicado anteriormente.3.1.2. ConfiguraoApos a construcao da DLL, e preciso configurar o Visual C++ para que seja possivel usar ofreeglut. Isso pode ser feito com os passos descritos aqui (supondo que o diretorio do freeglut sejac:\freeglut).3.1.2.1. Visual C++ 6 Acrescentar o diretorio c:\freeglut\include no Visual C++. Seguir pelos menus Tools,Options e escolher a aba Directories. Em Show directories for, escolher include files.Criar uma nova entrada e acrescentar o nome do diretorio. Copiar a .lib gerada para um diretorio c:\freeglut\lib (esse passo nao e estritamentenecessario, mas conveniente). Acrescentar o diretorio onde esta o freeglut.lib (ex: c:\freeglut\lib) no Visual C++.Seguir pelos menus Tools, Options e escolher a aba Directories. Em Show directoriesfor, escolher library files. Criar uma nova entrada e acrescentar c:\freeglut\lib (ou outrodiretorio onde esteja o arquivo).3.1.2.2. Visual C++ .NET Acrescentar o diretorio c:\freeglut\include no Visual C++. Seguir pelos menus Tools,Options e escolher Projects no painel da esquerda. A seguir, escolher VC++ Directoriese em Show directories for, escolher Include files. Criar uma nova entrada e acrescentar onome do diretorio. Copiar a .lib gerada para um diretorio c:\freeglut\lib (esse passo nao e estritamentenecessario, mas conveniente). Acrescentar o diretorio onde esta o freeglut.lib (ex: c:\freeglut\lib) no Visual C++.Seguir pelos menus Tools, Options e escolher Projects no painel da esquerda. A seguir,6UFF - Mestrado em Computacao Luis Valenteescolher VC++ Directories e em Show directories for, escolher library files. Criar umanova entrada e acrescentar c:\freeglut\lib (ou outro diretorio onde esteja o arquivo).3.1.3. Outros compiladoresPara usar o freeglut com outros compiladores, sera necessario compilar o codigo e gerar osarquivos de ligacao com o compilador em questao. O codigo fonte do freeglut ja vem com makefilesque podem ser usados para compilar o codigo com o GCC.Existem versoes pre-compiladas do freeglut para o GCC do Linux e Windows (MinGW). Essasversoes podem ser obtidas em http://jumpgate.homelinux.net/random/freeglut-fedora/ (pacote RPMpara Linux) e http://www.nigels.com/glt/devpak/ (Windows, pacote DevPak para o DevC++8).3.2. Exemplo de usoO exemplo demonstra um programa simples com freeglut e serve para testar a instalacao. Aquiesta o exemplo:#include void OnDisplay (){glClearColor (0.0f, 0.0f, 0.25f, 1.0f);glClear (GL_COLOR_BUFFER_BIT);glFlush ();}int main (int argc, char * argv []){glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);glutCreateWindow (Exemplo 1);glutDisplayFunc (OnDisplay);glutMainLoop ();return 0;}3.2.1. Arquivos de inclusoO freeglut possui um arquivo de inclusao principal:#include 8 O DevC++ e uma IDE (Integrated Development Environment) para o GCC do Windows. E gratuita e esta disponivelem http://www.bloodshed.net/dev/devcpp.html7UFF - Mestrado em Computacao Luis ValenteEsse arquivo permite utilizar todas as funcoes do freeglut. Esse arquivo ja incluiautomaticamente os arquivos principais do OpenGL (o gl.h e o glu.h). Dessa forma, nao e precisoespecifica-los. Nao e necessario incluir o arquivo principal do Windows (windows.h).3.2.2. Funo principalA funcao principal main e o ponto de entrada do programa. Na primeira linha, tem-se:glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);Todas as funcoes do freeglut possuem o prefixo glut, seguindo a convencao adotada peloOpenGL. A funcao da primeira linha especifica uma configuracao para o OpenGL. Essaconfiguracao e definida por uma combinacao de varias flags. A configuracao do exemplo requisitaque seja usado um unico buffer para a janela e o modo de cores usado seja RGB. No modoGLUT_SINGLE (single-buffered), todas as operacoes de desenho sao executadas diretamente najanela da aplicacao. Esse modo nao e adequado para animacao, porque o usuario percebe quando aimagem e apagada e desenhada ao mesmo tempo. Esse problema e conhecido como flicker. Aalternativa e usar o modo double-buffered, que cria dois buffers. Nessa configuracao, o conteudo deum dos buffers esta visivel enquanto o outro permanece invisivel. Os comandos de desenho saoexecutados no buffer que esta oculto, e no final da operacao, o que esta visivel torna-se invisive, evice-versa. Dessa forma, a animacao resultante e suave e sem flicker. A constante para esse modo eGLUT_DOUBLE.A proxima linha da funcao contem:glutCreateWindow (Exemplo 1);Essa funcao e responsavel por criar a janela. O argumento correponde ao texto que aparecera nabarra de titulo da janela.A proxima linha demonstra um conceito importante no freeglut:glutDisplayFunc (OnDisplay);Essa funcao indica ao freeglut que a funcao OnDisplay sera usada para desenhar na janela.Essa funcao e um exemplo das funcoes callback do freeglut. Uma funcao callback e uma funcaodefinida pelo usuario e registrada no freeglut, para ser executada na ocorrencia de algum eventoespecifico. Nesse exemplo, OnDisplay sera executada toda vez que for necessario redesenhar ajanela.Existem diversos tipos de eventos que podem ser tratatos atraves de funcoes callback. Para cadatipo de evento que pode ser tratado, existe uma funcao especifica responsavel por registrar umafuncao callback.A seguir, tem-se a seguinte linha de codigo:glutMainLoop ();Esse comando requisita que o freeglut inicie o laco principal da aplicacao. Nesse laco, ocorre oprocessamento dos eventos da aplicacao (que podem ser tratados atraves de callbacks). O lacoprincipal da aplicacao e executado ate que seja requisitado o termino do programa.8UFF - Mestrado em Computacao Luis Valente3.2.3. Comandos do OpenGLA funcao OnDisplay possui varios comandos do OpenGL que serao analisados a seguir. Naprimeira linha, tem-se:glClearColor (0.0f, 0.0f, 0.25f, 1.0f);Esse comando estabelece a cor de fundo da janela. No exemplo, a cor de fundo sera umavariacao de azul. As cores em OpenGL (como sera explicado em outras secoes) sao especificadas noformato RGBA. Nas funcoes que aceitam argumentos de ponto flutuante, o valor de cadacomponente varia de 0.0 (ausencia) a 1.0 (intensidade maxima).Apos definir a cor de fundo, a tela e preenchida com a cor de fundo (ou seja, e limpa) com oseguinte comando:glClear (GL_COLOR_BUFFER_BIT);O argumento da funcao indica qual e o tipo de buffer que sera afetado. Em OpenGL, um buffere uma area de memoria com algumas propriedades especiais. A constanteGL_COLOR_BUFFER_BIT corresponde a area de memoria que contem os pixels da janela (ou seja,a tela). Existem diversos tipos de buffers em OpenGL.A ultima linha da funcao OnDisplay e listada a seguir:glFlush ();Esse comando requisita ao OpenGL que execute todos os comandos pendentes. E comum que oOpenGL agrupe varios comandos (internamente, sem conhecimento do usuario) para que sejamexecutados de uma unica vez. O objetivo disso e melhorar o desempenho da aplicacao.4. PrimitivasUma primitiva e um objeto simples que pode ser usado para a criacao de outros objetoscomplexos. As primitivas disponiveis no OpenGL estao resumidas na figura 4.1.A especificacao de primtivas no OpenGL segue um padrao, demonstrado no seguinte trecho decodigo:glBegin (nome da primitiva)... // comandos que especificam os componentes da primitivaglEnd ();O nome da primitiva e uma constante que indica qual e o tipo de primitiva usado. Essasconstantes estao presentes na figura 4.1.Para se especificar os vertices da primitiva, o seguinte comando e usado:glVertex* ()O * e usado aqui para indicar que existem diversas variacoes do comando, por exemplo:9UFF - Mestrado em Computacao Luis ValenteglVertex3f (10.0f, 40.0f, 0.0f); // x, y, z, 1glVertex3i (5, 5, 5); // x, y, z, 1glVertex2d (20.0, 10.0); // x, y, 0, 1glVertex4f (0.0f, 30.0f, 10.0f, 1.0f); // x, y, z, wFigura 4.1 Primitivas do OpenGL (NeDa97)4.1. PontosPara especificar pontos simples, e necessario usar a constante GL_POINTS.glBegin (GL_POINTS);glVertex3f (0.0f, 0.0f, 0.0f);glVertex3f (10.0f, 20.0f, -3.0f);glVertex3f (4.0f, -10.0f, 1.0f);glEnd ();O exemplo desenha tres pontos na janela. Por padrao, o OpenGL desenha os pontos comtamanho igual a 1 pixel. Entretanto, e possivel desenhar pontos maiores. Para isso, e preciso usar oseguinte comando:glPointSize (GLfloat tamanho);10UFF - Mestrado em Computacao Luis ValenteO maior valor possivel depende do hardware onde o programa sera executado. O unico valorgarantido a existir e 1.0 (que corresponde a um pixel). Para consultar a faixa de valores possiveis,basta usar o seguinte trecho de codigo:GLfloat faixa [2];glGetFloatv (GL_POINT_SIZE_RANGE, faixa);GLfloat min = faixa [0];GLfloat max = faixa [1];A faixa de valores possiveis para o tamanho dos pontos e apenas uma das propriedades doOpenGL que podem ser consultadas. Existem diversas outras, que podem ser obtidas usandofuncoes como glGetFloatv , glGetIntegerv, glGetDoublev e glGetBooleanv.Outra propriedade interessante que pode ser alterada e a suavizacao no desenho dos pontos(anti-aliasing). O comando para especifica-la e:glEnable (GL_POINT_SMOOTH);O comando glEnable e responavel por habilitar alguma propriedade do OpenGL (ou seja,ligar o estado). O comando correspondente, para desligar, e glDisable. Dessa forma, paradesligar a suavizacao no desenho dos pontos, basta usar este comando:glDisable (GL_POINT_SMOOTH);4.2. LinhasExistem tres primitivas relacionadas a linhas em OpenGL que sao GL_LINE,GL_LINE_STRIP e GL_LINE_LOOP.A primitiva GL_LINE corresponde a linhas simples:glBegin (GL_LINE)glVertex3f (0.0f, 0.0f, 0.0f);glVertex3f (10.0f, 10.0f, 5.0f);glVertex3f (5.0f, -20.0f, 0.0f); // descartadoglEnd ();Quando essa primitiva e usada, cada par de vertices e usado para desenhar uma linha. Casoexista um numero impar de vertices, o ultimo vertice e descartado.Na primitiva GL_LINE_STRIP, os vertices especificados sao conectados em sequencia,conforme sao especificados:glBegin (GL_LINE_STRIP)glVertex3f (0.0f, 0.0f, 0.0f);glVertex3f (10.0f, 10.0f, 5.0f);glVertex3f (5.0f, -20.0f, 0.0f);glEnd ();11UFF - Mestrado em Computacao Luis ValenteNesse exemplo, existirao dois segmentos de reta.A primitiva GL_LINE_LOOP e semelhante a primitiva GL_LINE_STRIP, so que o ultimovertice especificado e conectado ao primeiro, formando um ciclo.Por padrao, as linhas desenhadas possuem a espessura igual a 1 pixel. Essa propriedade pode seralterada com o seguinte comando:glLineWidth (GLfloat valor);O unico valor garantido a existir e 1.0, para consultar a faixa de valores permitida, oprocedimento e semelhante aquele usado para consultar a faixa de valores para os pontos:GLfloat faixa [2];glGetFloatv (GL_LINE_WIDTH_RANGE, faixa);GLfloat min = faixa [0];GLfloat max = faixa [1];Tambem e possivel desenhar as linhas com anti-aliasing, usando o comando:glEnable (GL_LINE_SMOOTH);4.3. PolgonosO OpenGL permite usar tres tipos de poligonos: triangulos, quadrilateros e poligonos genericos.Comum a todos eles, existe uma propriedade importante: a ordenacao dos vertices (a ordem em quesao especificados) deve ser consistente. As ordenacoes possiveis sao ilustradas na figura 4.2.Figura 4.2 Ordenaes possveis. (a) Sentido horrio. (b) Sentido anti-horrio.Essa propriedade e importante porque a ordenacao dos vertices define o lado do poligono queesta voltado para a frente e o lado do poligono que esta voltado para tras. O padrao usado peloOpenGL (e neste trabalho) e que as faces voltadas para frente sao especificadas em sentido antihorario.Esse padrao pode ser alterado com o seguinte comando:glFrontFace (ordem);12UFF - Mestrado em Computacao Luis ValenteA ordem pode ser GL_CW (sentido horario) ou GL_CCW (sentido anti-horario).Para entender porque a importancia dessa especificacao, considere o seguinte exemplo: Imagineque em um programa, o usuario visualize um cubo. O cubo e formado por seis poligonos, mas naverdade existem doze faces: seis que estao voltadas para frente e seis que estao voltadas para tras(porque cada poligono possui duas faces). O OpenGL, por padrao, processa as doze faces.O processo de eliminacao das faces que nao podem ser vistas pelo usuario (as que estao nointerior do cubo, supondo que o usuario esteja for a dele) e conhecido como backface culling. Parahabilitar o backface culling, e necessario usar esse comando:glEnable (GL_CULL_FACE);Os poligonos podem ser desenhados de diversas maneiras: com preenchimento de cor (padrao),em wireframe ou so com os vertices.Para alterar o modo de renderizacao dos poligonos, usa-se o seguinte comando:glPolygonMode (tipo de face, modo);Os tipos de face aceitos sao: GL_FRONT (afeta as faces da frente), GL_BACK (afeta as faces detras) e GL_FRONT_AND_BACK (afeta ambas). As constantes para os modos de renderizacao saoGL_FILL (solido), GL_LINE (wireframe) e GL_POINT (somente vertices). Dessa forma, paradesenhar as faces da frente dos poligonos em modo wireframe, basta usar este comando:glPolygonMode (GL_FRONT, GL_LINE);E importante observar que o modo especificado afeta apenas o tipo de face desejado. Porexemplo, caso se queira desenhar as faces da frente em modo solido e as de tras como wireframe,estes comandos seriam usados (para que ambas sejam visualizadas, o backface culling teria queestar desligado):glPolygonMode (GL_FRONT, GL_FILL);glPolygonMode (GL_BACK, GL_LINE);4.3.1. TringulosOs triangulos sao o tipo de primitiva mais usado em OpenGL (e em graficos 3D, em geral). NoOpenGL, existem tres variacoes sobre o tema: GL_TRIANGLES, GL_TRIANGLE_STRIP eGL_TRIANGLE_FAN.A primitiva GL_TRIANGLE permite desenhar triangulos simples:glBegin (GL_TRIANGLES)glVertex2f (10.0f, 10.0f);glVertex3f (20.0f, -5.0f);glVertex3f (-20.0f, -5.0f);glVertex3f (100.0f, 0.0f); // descartadoglVertex3f (100.0f, -8.0f); // descartadoglEnd ();13UFF - Mestrado em Computacao Luis ValenteQuando essa primitiva e usada, o OpenGL usada cada trinca de vertices para desenhar umtriangulo. Caso exista uma trinca incompleta, esta e descartada.A primitiva GL_TRIANGLE_STRIP e usada para se desenhar uma tira de triangulos(triangulos conectados sequencialmente). Esse esquema pode ser visualizado na figura 4.3.Figura 4.3 Sequncia de especificao de vrtices para GL_TRIANGLE_STRIPOs tres primeiros vertices sao usados para formar o primeiro triangulo. A seguir, cada verticesubsequente e conectado aos dois vertices anteriores. Na figura 4.3, a ordenacao dos vertices segueo sentido anti-horario.A primitiva GL_TRIANGLE_FAN e usada para se conectar varios triangulos em torno de umponto central, tal como um leque (fan):glBegin (GL_TRIANGLE_FAN);glVertex3f (0.0f, 0.0f, 0.0f);glVertex3f (10.0f, -1.0f, 0.0f);glVertex3f (10.0f, 9.0f, 0.0f);glVertex3f ( 0.0f, 12.0f, 0.0f);glVertex3f (-10.0f, 8.0f, 0.0f);glEnd ();O primeiro vertice especificado na primitiva e o ponto central do leque. Os dois verticesseguintes formam o primeiro triangulo. A partir de entao, e preciso somente especificar um novovertice para formar um novo triangulo (o triangulo sera construido usando o novo vertice e doisvertices especificados antes deste).A figura 4.4. ilustra um leque formado por essa primitiva.14UFF - Mestrado em Computacao Luis ValenteFigura 4.4 Malha gerada por GL_TRIANGLE_FAN4.3.2. QuadrilterosAs primitivas para quadrilateros em OpenGL sao duas: GL_QUADS e GL_QUAD_STRIP.O uso de GL_QUADS possibilita que sejam gerados quadrilateros simples. O OpenGL utilizaquatro vertices de cada vez para formar um quadrilatero, como neste exemplo:glBegin (GL_QUADS);glVertex3f (-10.0f, -10.0f, 0.0f);glVertex3f (10.0f, -10.0f, 0.0f);glVertex3f (10.0f, 10.0f, 0.0f);glVertex3f (-10.0f, 10.0f, 0.0f);glVertex3f (-30.0f, -10.0f, 0.0f); // descartadoglVertex3f (30.0f, -10.0f, 0.0f); // descartadoglEnd ();Figura 4.5 GL_QUADSCaso nao existam vertices suficientes para formar um quadrilatero, eles sao descartados.15UFF - Mestrado em Computacao Luis ValenteA primitiva GL_QUAD_STRIP serve para formar tiras de quadrilateros conectados. Seu modode uso e quase identico ao de GL_TRIANGLE_STRIP. Em GL_QUAD_STRIP e precisoespecificar quatro vertices iniciais (para formar o primeiro quadrado) e mais dois vertices de cadavez para formar os outros quadrados. O uso dessa primitiva e ilustrado na figura 4.6.Figura 4.6 Aplicao de GL_QUAD_STRIP4.3.3. Polgonos genricosA construcao de poligonos genericos pode ser feita usando a primitiva GL_POLYGON. Nao halimites para o numero de vertices, mas existem duas regras para o uso de GL_POLYGON.A primeira delas e que o poligono a ser gerado deve pertencer a um unico plano (ou seja, todosos vertices devem estar no mesmo plano). A segunda regra e que os poligonos devem ser convexos.5. Cores e sombreamentoCores em OpenGL sao especificadas como RGBA. O comando para alterar as cores e:glColor* ()Assim como varios comandos, o glColor possui diversas variacoes. Nas versoes que aceitamargumentos de ponto flutuante, os valores para cada componente variam entre 0.0 (ausencia) e 1.0(intensidade maxima). Exemplos de uso:glColor3f (1.0f, 1.0f, 1.0f); // brancoglColor3f (0.0f, 0.0f, 0.0f); // pretoglColor3f (1.0f, 0.0f, 0.0f); // vermelho puroNas variacoes que trabalham com numeros inteiros sem sinal, os valores dos componentesvariam de 0 (ausencia) a 255 (intensidade maxima).O OpenGL trabalha internamente com RGBA, de forma que se forem especificadas apenas trescomponntes, o quarto componente (alfa) sera 1.0 por padrao.glColor3f (0.0f, 1.0f, 0.0f); // verde , alfa = 1.0glColor4f (1.0f, 1.0f, 0.0f, 0.25f) // amarelo, alfa = 0.2516UFF - Mestrado em Computacao Luis ValenteQuando um comando de cor e usado, a cor especificada sera usada para todas as primitivas ateque uma outra cor seja especificada. Segue um pequeno exemplo:glColor3f (1.0f, 0.0f, 0.0f);glBegin (GL_TRIANGLES);glVertex3f ( 0.0f, 10.0f, 5.0f);glVertex3f (-10.0f, 0.0f, 5.0f);glVertex3f ( 10.0f, 0.0f, 5.0f);glEnd ();Nesse exemplo, o triangulo sera preenchido com a cor vermelha. Entretanto, as cores tambempodem ser especificadas para cada vertice, como no proximo exemplo:glBegin (GL_TRIANGLES);glColor3f (1.0f, 0.0f, 0.0f);glVertex3f (0.0f, 10.0f, 5.0f);glColor3f (0.0f, 1.0f, 0.0f);glVertex3f (-10.0f, 0.0f, 5.0f);glColor3f (0.0f, 0.0f, 1.0f);glVertex3f (10.0f, 0.0f, 5.0f);glEnd ();Para entender o que acontece nesse exemplo, e preciso explicar o conceito de modo desombreamento.O modo de sombreamento do OpenGL indica como sera feita a coloracao das primitivas (epreenchimento dos poligonos. Existem dois modos possiveis: o sombreamento suave (Gouraud) esombreamento fixo. No sombreamento fixo, uma unica cor e usada para preencher o poligono. Nocaso de sombreamento suave, o OpenGL ira realizar uma interpolacao entre as cores dos verticespara preencher os poligonos.O resultado desses dois modos (aplicados no exemplo) pode ser conferido na figura 5.1.17UFF - Mestrado em Computacao Luis ValenteFigura 5.1 Modos de sombreamento. (a) Sombreamento fixo. (b) Sombreamento suave.Para determinar o modo de sombreamento, o seguinte comando e usado:glShadeModel (modo);O modo de sombreamento suave corresponde a constante GL_SMOOTH e o modo desombreamento fixo corresponde a constante (GL_FLAT). O modo padrao usado pelo OpenGL eGL_SMOOTH.6. Z-BufferO OpenGL usa o z-buffer para determinar a visibilidade dos objetos desenhados na cena. Esseteste ocorre na etapa de rasterizacao.O z-buffer e um dos varios buffers que existem no OpenGL. Tipicamente, a implementacao doz-buffer e feita no hardware da placa grafica. O z-buffer armazena valores que tem a ver com aprofundidade dos pixels da tela. Dessa forma, o z-buffer possui o mesmo tamanho da janela ou telada aplicacao.De maneira simplificada, o algoritmo de z-buffer e usado da seguinte maneira: no inicio daaplicacao (ou antes de imagem ser construida, por exemplo, no inicio de um quadro de animacao doprograma), o z-buffer e preenchido (limpo) com um certo valor (um valor muito grande, porexemplo). Quando um pixel precisa ser pintado na tela, o algoritmo consulta o valor correspondentea esse pixel que esta armazenado no z-buffer. Se o valor for menor (o que quer dizer que o novopixel estaria mais perto), o pixel e pintado na tela e o valor de profundidade e armazenado no zbuffer.Caso esse valor fosse maior do que aquele que la estivesse, o pixel nao seria pintado. Aconsequencia da aplicacao desse algoritmo e que a cena e desenhada corretamente (em termos dedeterminacao de visibilidade).18UFF - Mestrado em Computacao Luis ValentePara se usar o z-buffer no OpenGL, e preciso requisitar sua criacao. No freeglut, basta usar aconstante GLUT_DEPTH junto com as outras na hora da inicializacao:glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);A seguir, e preciso habilitar o uso do z-buffer no OpenGL (que esta desligado por padrao). Issopode ser feito com o seguinte comando:glEnable (GL_DEPTH_TEST);Caso se queira desligar o teste de z-buffer, basta usar o comando glDisable(GL_DEPTH_TEST).Durante o ciclo de vida da aplicacao, o z-buffer devera ser zerado toda vez que se desejar criaruma nova imagem. Isso e normalmente feito no mesmo momento em que se limpa a tela. Pararealizar essa operacao conjunta, basta usar este comando:glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);O funcionamento do z-buffer e suas configuracoes podem ser alteradas com grandeflexibilidade, mas esse detalhamento esta fora do escopo deste trabalho. Para maiores informacoes,por favor, consulte a documentacao do OpenGL.7. Transformaes e projeesO OpenGL usa diversos tipos de transformacoes geometricas na especificacao da cena. Essastransformacoes podem ser dos seguites tipos: Viewport, Modelagem, Projecao e Camera.O sistema de coordenadas tridimensional usado no OpenGL e o sistema de coordenadas da maodireita, que pode ser visualizado na figura 7.1.Figura 7.1 Sistema de coordenadas da mo direita7.1. ViewportA transformacao de viewport indica a area da janela onde serao realizadas as operacoes dedesenho. A figura 7.2 ilustra um exemplo de viewport.19UFF - Mestrado em Computacao Luis ValenteFigura 7.2 Uma viewport (WrSw99)A origem da viewport e o canto inferior esquerdo. Para se determinar a viewport, o seguintecomando e usado:glViewport (origem_x, origem_y, largura, altura);Dessa forma, para especificar a viewport da figura 7.2, basta submeter este comando:glViewport (0, 0, 150, 100);7.2. MatrizesO OpenGL usa matrizes para implementar todas as transformacoes existentes. Normalmente, ousuario nao precisa lidar com as matrizes diretamente (embora isso seja possivel se for desejado),pois existem varios comandos para manipula-las.As transformacoes de modelagem e projecao sao independentes entre si. Internamente, oOpenGL mantem uma matriz para cada um desses tipos.Em um dado momento, so e permitido usar um dos tipos de matriz. O tipo de matriz usado nomomento e determinado pelo seguinte comando:glMatrixMode (nome da matriz);O nome da matriz de modelagem e GL_MODELVIEW e o da matriz de projecao eGL_PROJECTION. Segue um exemplo:glMatrixMode (GL_PROJECTION);// a partir deste momento, a matriz afetada a de// projeo... // comandos que afetam a matriz de projeoglMatrixMode (GL_MODELVIEW);20UFF - Mestrado em Computacao Luis Valente// a partir deste momento, a matriz afetada a de// modelagem... // comandos que afetam a matriz de modelagemExistem algumas operacoes pre-definidas que podem ser aplicadas em matrizes. Essescomandos afetam o tipo de matriz selecionado no momento. As operacoes principais sao translacao,rotacao, escala e carregar a matriz identidade.A matriz identidade serve para reiniciar o sistema de coordenadas, ou seja, a posicaoselecionada sera a origem, nao existirao rotacoes e a escala sera igual a 1 em todos os eixos. Ocomando para carregar a matriz identidade e:glLoadIdentity ();A operacao de translacao desloca o sistema de coordenadas pelo numero de unidadesespecificadas. O comando correspondente e:glTranslate* (x, y, z); // * = f ou dEsse comando e acumulativo (assim como todos os outros), como e descrito neste exemplo:glLoadIdentity (); // posio = 0,0,0glTranslatef (10.0f, 0.0f, 0.0f); // posio = 10,0,0glTranslatef (0.0f, 5.0f, -1.0f); // posio = 10,5,-1A operacao de rotacao pode ser expressa com este comando:glRotate* (angulo, x, y, z); // * = f ou dO angulo e expresso em graus, e os parametros x, y, e z representam o eixo de rotacao. Dessaforma, para realizar uma rotacao de 30o em torno do eixo Z, este trecho de codigo e usado:glRotatef (30, 0.0f, 0.0f, 1.0f);A operacao de escala e feita com o seguinte comando:glScale* (escala_x, escala_y, escala_z); // * = f ou dOs parametros representam os fatores de escala em cada eixo. O valor 1.0 nao afeta a escala.7.3. ModelagemComo exemplo, suponha que se queria desenhar um triangulo na posicao (10, 10, 0). Isso podeser feito com o seguite trecho de codigo:glMatrixMode (GL_MODELVIEW);glLoadIdentity ();glTranslatef (10, 10, 0);glBegin (GL_TRIANGLES);21UFF - Mestrado em Computacao Luis ValenteglVertex2f (0.0f, 10.0f);glVertex2f (-10.0f, 0.0f);glVertex2f (10.0f, 0.0f);glEnd ();Agora, suponha que se queira desenha o mesmo triangulo com uma rotacao de -20o em torno doeixo Z:glMatrixMode (GL_MODELVIEW);glLoadIdentity ();glRotatef (-20.0f, 0.0f, 0.0f, 1.0f);glBegin (GL_TRIANGLES);glVertex2f (0.0f, 10.0f);glVertex2f (-10.0f, 0.0f);glVertex2f (10.0f, 0.0f);glEnd ();7.4. ProjeoO OpenGL possui funcoes para configurar dois tipos de projecoes: projecoes ortograficas eprojecoes em perspectiva.7.4.1. Projeo ortogrficaA projecao ortografica pode ser especificada com o seguinte comando:void glOrtho (GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far);Os parametros correspondem aos valores dos planos que formam o volume de visao da projecaoortografica. Esse volume de visao pode ser visualizado na figura 7.3.22UFF - Mestrado em Computacao Luis ValenteFigura 7.3 Volume de viso da projeo ortogrfica (WrSw99)O volume de visao da projecao ortografica e um paralelepipedo (ou um cubo), de forma quetodos os objetos (primitivas, etc) que estiverem for a desse volume nao aparecerao na imagem final.Por exemplo, suponha que se queria construir uma projecao que possua um comprimento de 20unidades em todos os eixos, e que a origem esteja no centro da janela9. Isso pode ser feito com oseguinte trecho de codigo:glMatrixMode (GL_PROJECTION);glLoadIdentity ();glOrtho (-10.0, 10.0, -10.0, 10.0, -10.0, 10.0);glMatrixMode (GL_MODELVIEW);glLoadIdentity ();No caso dos parametros near e far, valores negativos indicam que o plano esta atras doobservador (o near e negativo porque o exemplo tem como objetivo posicionar a origem no centrodo volume de visao).O exemplo tambem demonstra uma convencao que e adotada em programas que usam OpenGL.A determinacao da projecao e uma tarefa que e realizada poucas vezes. Na maioria dos casos, oscomandos de matrizes afetam a matriz de modelagem. Dessa forma, a convencao e assumir sempreque a matriz atual e a de modelagem. Caso se queira alterar algum outro tipo de matriz, altera-se otipo de matriz e realiza-se as operacoes desejadas. No final das operacoes, restaura-se o determinaseque o tipo de matriz e a de modelagem. O objetivo dessa convencao e evitar erros que podemocorrer quando se altera a matriz errada (por exemplo, alterar a matriz de projecao acidentalmente).9 Na verdade, que esteja no centro da viewport. Nesse exemplo, considera-se que a viewport ocupe toda a janela (oque e bastante comum).23UFF - Mestrado em Computacao Luis ValenteEm relacao a projecoes ortograficas, existe ainda um outro tipo de problema a se tratar. Noexemplo, foi criada uma projecao quadrada. Entretanto, e comum que a janela da aplicacao sejaretangular. Dessa forma, tem-se o seguinte problema: Suponha que a projecao foi criada como noexemplo. Os eixos X, Y e Z podem representar valores de -20 a 20. Suponha que a janela daaplicacao possui tamanho igual a 300x100. A proporcao da janela (largura/altura) e diferente daproporcao da projecao (que e 1). Sendo assim, as imagens desenhadas na janela seraodesproporcionais, conforme pode ser visualizado na figura 7.4.Figura 7.4 Viewport e projeo desproporcionalPara corrigir essa distorcao, e necessario levar em consideracao a razao de aspecto da janela aose calcular a projecao. Isso pode ser feito da seguinte forma:// largura e altura da viewportlargura = ...altura = ...glMatrixMode (GL_PROJECTION);glLoadIdentity ();GLdouble proporcao = largura/altura;if (proporcao >= 1.0)glOrtho (left * proporcao, right * proporcao, bottom, top,near, far);elseglOrtho (left, right, bottom / proporcao, top / proporcao,near, far);glMatrixMode (GL_MODELVIEW);glLoadIdentity ();24UFF - Mestrado em Computacao Luis Valente7.4.2. Projeo em perspectivaPara definir uma projecao em perspectiva, e necessario especificar os planos que formam ofrustum (que e o volume de visao dessa projecao). O frustum e um volume tridimensional em formade uma piramide imaginaria limitada pelos planos delimitadores near e far, que correspondem adistancias relativas ao observador, na direcao de sua linha de visao. O frustum e ilustrado na figura7.5.Figura 7.5 Frustum (WrSw99)Para especificar o frustum, existe o seguinte comando do OpenGL:glFrustum (left, right, bottom, top, near, far);Entretanto, especificar os planos do frustum nao e conveniente na maioria das vezes. Por essarazao, a GLU oferece uma funcao para especificar o frustum de outra forma:gluPerspective (campo de viso, proporo, near, far);A figura 7.6 ilustra os parametros de gluPerspective:Figura 7.6 Parmetros de gluPerspective (WrSw99)O primeiro parametro corresponde ao campo de visao vertical (angulo em graus). O segundoparametro corresponde a proporcao entre a altura e largura da viewport. Os dois ultimos parametroscorrespondem aos planos delimitadores near e far, como na outra funcao.25UFF - Mestrado em Computacao Luis Valente7.5. CmeraA separacao do conceito de transformacao de camera, em OpenGL, e apenas uma notacao deconveniencia. Nao existe uma matriz separada para transformacao de camera, na verdade, essatransformacao afeta a matriz de modelagem.A transformacao de camera serve para posicionar e orientar o ponto de vista na cena. OOpenGL oferece uma funcao para especificar essa transformacao:gluLookAt (pos_x , pos_y , pos_z,alvo_x, alvo_y, alvo_z,up_x , up_y , up_z);Os primeiros tres parametros correspondem a posicao do observador (ou da camera) na cena. Ostres seguintes correspondem ao ponto para onde a camera esta apontada. Os tres ultimosespecificam um vetor que indica qual e a direcao que pode ser considerada para cima. Porexemplo, se o usuario esta posicionado em (0, 0, 0) e olhando para (0, 0, -20), a direcao para cimacorresponde a (0, 1, 0).A transformacao de camera deve ser a primeira a ser especificada na renderizacao da cena:// supondo que o modo de matriz atual seja GL_MODELVIEWvoid desenharCena (){glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glLoadIdentity ();glLookAt (0.0, 0.0, 0.0,0.0, 0.0, -20.0,0.0, 1.0, 0.0);// comandos para posicionar, rotacionar, desenhar, etc...}Se nenhuma transformacao de camera for especificada, o usuario estara posicionado em (0, 0, 0)e olhando para (0, 0, -1) e a direcao considerada para cima e o eixo Y.A transformacao de camera pode ser implementada usando os comandos de manipulacao dematrizes (que devem ser usados para que se possa construir outros tipos de transformacoes).Por exemplo, suponha que a configuracao da camera seja a padrao. Se for necessario mover acamera 20 unidades para a esquerda, pode-se executar essa tarefa com este trecho de codigo:glLoadIdentity ();glTranslatef (-20.0f, 0.0f, 0.0f);E interessante notar que esse exemplo e equivalente a este outro:glLoadIdentity ();26UFF - Mestrado em Computacao Luis ValenteglLookAt (-20.0, 0.0, 0.0,0.0, 0.0, -1.0,0.0, 1.0, 0.0);7.6. Hierarquia de transformaesSuponha que seja necessario desenhar duas esferas em uma cena, como na figura 7.7.Figura 7.7 Cena com duas esferas (WrSw99)Como sabe-se que as operacoes de transformacao de matrizes sao cumulativas, uma primeiratentativa de se resolver esse caso poderia ser feita da seguinte forma:glLoadIdentity ();glTranslatef (10.0f, 0.0f, 0.0f);desenharEsfera ();glLoadIdentity ();glTranslatef (0.0f, 10.0f, 0.0f);Entretanto, esse exemplo e inadequado por varios motivos. Primeiramente, quando existemmuitos objetos na cena, essa abordagem torna-se confusa e ineficiente (varias chamadas aglLoadIdentity). Outro problema e quando alguns objetos dependem de outros. Por exemplo,se uma das esferas girasse em torno da outra, seria bem mais complicado implementar esse modelose a cada transformacao fosse necessario carregar a matriz identidade.Para resolver esses problemas, o OpenGL fornece pilhas de matrizes. As pilhas podem serusadas para salvar o valor de alguma matriz, realizar as operacoes desejadas e depois restaurar ovalor da matriz anterior.O OpenGL mantem uma pilha para cada tipo de matriz existente. Assim como os comandos demanipulacao de matrizes, os comandos de manipulacao da pilha afetam apenas o tipo de matrizatual. Esses comandos sao glPushMatrix e glPopMatrix.Aqui esta um exemplo de utilizacao desses comandos:glLoadIdentity ();27UFF - Mestrado em Computacao Luis Valente// salva a matriz atual (identidade)glPushMatrix ();glTranslatef (0.0f, 10.0f, 0.0f);desenharEsfera ();glPopMatrix ();/* a matriz atual volta a ser a identidade */glPushMatrix ();glTranslatef (10.0f, 0.0f, 0.0f);desenharEsfera ();glPopMatrix ();7.7. Outras operaes (avanado)Alem das operacoes implementadas pelo OpenGL, e possivel realizar operacoes personalizadas.O OpenGL possui dois comandos para definir essas operacoes:glLoadMatrix* (m); // * = f ou dglMultMatrix* (m); // * = f ou dA funcao glLoadMatrix* permite substituir a matriz atual pela matriz especificada comoparametro. A funcao glMultMatrix* permite multiplicar a matriz atual por uma matrizqualquer.A definicao da matriz m deve ser feita usando um array simples:GLfloat matriz [16];O OpenGL trabalha internamente vetores coluna, por isso a matriz m e tratada da seguinteforma:Figura 7.8 Armazenamento interno da matriz28UFF - Mestrado em Computacao Luis ValenteO formato das matrizes usadas em OpenGL e diferente do formato usual de matrizes nalinguagem C:float matriz [4][4]; // C convencionalO problema e que na linguagem C, as matrizes sao armazenadas em memoria por ordem delinha. Dessa forma, os quatro primeiros elementos correspondem a primeira linha, os quatroseguintes a segunda linha, e assim sucessivamente. Assim, o elemento m (i, j) da matriz declaradaem C representa o elemento a (j, i) da matriz do OpenGL.Para ilustrar o uso dessas funcoes, o exemplo a seguir implementa a funcionalidade da funcaoglTranslatef:void translate (GLfloat x, GLfloat y, GLfloat z){GLfloat * m = {1.0f, 0.0f, 0.0f, 0.0f,0.0f, 1.0f, 0.0f, 0.0f,0.0f, 0.0f, 1.0f, 0.0f,x , y , z , 1.0f};glMultMatrixf (m);}8. Composio de objetosA maneira mais simples de se desenhar algum objeto seria especificar os seus vertices emalguma funcao qualquer, como por exemplo:glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)desenharMeuObjeto ();Existem varias desvantagens em se usar essa abordagem. Por exemplo, se for necessario realizarcalculos complexos para gerar a geometria do objeto, nesse exemplo esses calculos seriamrealizados varias vezes (quando eles poderiam ser feitos uma vez so, como na inicializacao doprograma).Com o OpenGL, e possivel agrupar comandos para serem executados em uma unica chamada,com as diplay lists. Display lists sao listas de comandos do OpenGL pre-processados.No exemplo do calculo da geometria do objeto, ao se usar uma display list, somente o resultadofinal do processo (como os vertices) seria armazenado.As display lists sao referenciadas por um identificador, que e um numero simples. Entretanto, epreciso requisitar ao OpenGL que gere um identificador valido. Isso pode ser feito da seguinteforma:GLuint minhaLista = glGenLists (1);A variavel minhaLista contem o identificador da lista, e o argumento da funcao glGenListsindica quantas listas deverao ser criadas. Caso sejam criadas varias listas, elas poderao ser acessadassequencialmente, a partir do identificador principal. Por exemplo, caso se queira criar cinco listas:29UFF - Mestrado em Computacao Luis ValenteGLuint listas = glGenLists (5);As listas criadas poderao ser acessadas usando listas, listas+1, listas+2, ...,listas+4.Apos a criacao da lista, e necessario preenche-la com comandos. Para fazer isso, usa-se:glNewList (minhaLista, GL_COMPILE);... // clculos, comandos do OpenGLglEndList ();A constante GL_COMPILE indica ao OpenGL que os comandos devem ser agrupados na lista.Uma outra alternativa e usar GL_COMPILE_AND_EXECUTE, que indica que os comandos deveraoser armazenados e executados.Alguns comandos como glNewList e glEndList nao sao armazenados na lista (existemoutros, que estao descritos na documentacao do OpenGL).Depois que a lista foi definida, e possivel executar os comandos armazenados a qualquermomento, com o seguinte comando:glCallList (minhaLista);Ao final da aplicacao, e necessario liberar os recursos alocados pela lista, com este comando:glDeleteLists (minhaLista, 1);O primeiro argumento refere-se ao identificador da lista, e o segundo a quantidade de listas queserao apagadas.Uma observacao importante em relacao a display lists e que as display lists sao estaticas, ouseja, nao e possivel alterar os dados armazenados na lista depois que elas forem preenchidas.Entretanto, e possivel substituir o seu conteudo:glNewList (minhaLista, GL_COMPILE);... // novos comandosglEndList ();9. IluminaoPara usar iluminacao em OpenGL, e preciso seguir alguns passos: Habilitar o uso de iluminacao; Especificar os vetores normais; Configurar o material dos objetos; Configurar as fontes de luz.30UFF - Mestrado em Computacao Luis ValenteO uso de iluminacao esta desabilitado por padrao. Para habilitar a iluminacao, e necessario usaro seguinte comando:glEnable (GL_LIGHTING);A iluminacao pode ser desligada a qualquer momento usando este comando:glDisable (GL_LIGHTING);9.1. Vetores normaisOs vetores normais sao usados pelo OpenGL para calcular a incidencia de luz sobre umasuperficie. O comando para especificar vetores normais e:glVertex3* ()Esses vetores podem ser associados a superficies inteiras ou a vertices individuais. Paraespecificar os vetores normais por vertice, basta especifica-los com os vertices questao, como noexemplo a seguir:glNormal3f (0.0f, 1.0f, 0.0f);glVertex3f (a, b, c);glNormal3f (0.0f, 0.0f, 1.0f);glVertex3f (d, e, f);Por questoes de otimizacao, o OpenGL espera que os vetores normais fornecidos sejamunitarios. E possivel requisitar ao OpenGL que normalize os vetores conforme estes foremsubmetidos, com o seguinte comando:glEnable (GL_NORMALIZE);Entretanto, isso representa um custo adicional que pode ser evitado.Outra observacao importante e que os comandos glScale* afetam o comprimento dosvetores normais, o que pode ocasionar erros no calculo de iluminacao.9.2. MateriaisOs materiais sao propriedades de uma superficie que definem sua aparencia. Essas propriedadestem a ver com a componente da luz que eles sao capazes de refletir.Os tipos de material que podem ser especificados no OpenGL sao: GL_AMBIENT,GL_DIFFUSE, GL_SPECULAR, GL_EMISSION e GL_SHININESS.O GL_AMBIENT, GL_DIFFUSE e GL_SPECULAR especificam a reflectancia de luz ambiente,difusa e especular, respectivamente. O GL_EMISSION especifica a intensidade de luz emitida pelomaterial,. O GL_SHININESS especifica um valor (specular exponent) que tem a ver com aconcentracao de brilho em uma superficie. Quando maior esse valor, mais concentrado e o brilhoespecular (a area ocupada por ele e menor).31UFF - Mestrado em Computacao Luis ValenteA primeira alternativa para se especificar materiais e usar a funcao glMaterial*. Essafuncao recebe tres parametros: qual e o tipo de face a ser afetado (frente, tras ou ambas), qual e apropriedade a ser alterada e os valores da propriedade.Como exemplo, tem-se o seguinte trecho de codigo:GLfloat cinza [] = {0.60, 0.60, 0.60, 1.0};glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cinza);glBegin (GL_TRIANGLES);glVertex3f (0.0f, 10.0f, 30.0f);glVertex3f (-50.0f, 0.0f, 30.0f);glVertex3f (50.0f, 0.0f, 30.0f);glEnd ();O exemplo especifica que o material refletido pelo triangulo, sob luz ambiente e difusa e umavariacao de cinza. E importante notar que somente a face da frente sera afetada. Caso se queiraafetar ambas as faces, e necessario usar a constante GL_FRONT_AND_BACK.Para configurar materiais de modo que possuam efeitos especulares, pode ser usado este trechode codigo:GLfloat cor [] = {1.0f , 1.0f, 1.0f, 1.0f};glMaterialfv (GL_FRONT, GL_SPECULAR, cor);glMaterialf (GL_FRONT, GL_SHININESS, 128.0f);A variavel cor indica qual sera a cor refletida pela luz especular. No exemplo, cor indica quetodas as cores serao refletidas. O parametro GL_SHININESS pode variar de 0 a 128.Caso uma cena possua muitos materias diferentes, o uso de glMaterial* pode tornar-seineficiente. Por isso, existe uma outra alternativa para se especificar propriedades dos materiais.A outra opcao e usar o chamado color tracking. Quando o color tracking esta ativado, apropriedade do escolhida e determinada com o uso de glColor*.Inicialmente, e preciso habilitar o color tracking:glEnable (GL_COLOR_MATERIAL);A seguir, e preciso configura-lo, com o seguinte comando:void glColorMaterial (GLenum face, GLenum mode);O parametro face indica qual e o tipo de face afetada (GL_FRONT, GL_BACK ouGL_FRONT_AND_BACK). O parametro mode indica qual e a propriedade do material a ser usada, epode ser GL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, ouGL_AMBIENT_AND_DIFFUSE (padrao). Exemplo de uso:32UFF - Mestrado em Computacao Luis ValenteglEnable (GL_COLOR_MATERIAL);glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);glColor3f (1.0f, 0.0f, 0.0f);glBegin (GL_TRIANGLES);glVertex3f (0.0f, 10.0f, 30.0f);glVertex3f (-50.0f, 0.0f, 30.0f);glVertex3f (50.0f, 0.0f, 30.0f);glEnd ();9.3. Fontes de luzE possivel especificar uma valor de luz ambiente global para a cena. Isso pode ser feitoalterando-se o modelo de iluminacao usado pela aplicacao, que e demonstrado no seguinte trecho decodigo:GLfloat luz_ambiente [] = {1.0f, 1.0f, 1.0f, 1.0f};glLightModelfv (GL_LIGHT_MODEL_AMBIENT, luz_ambiente);Por padrao, o valor padrao de luz ambiente para ess modelo e {0.2, 0.2, 0.2, 1.0}. Existemoutros modelos que podem ser alterados.A especificacao do OpenGL preve um numero minimo de oito fontes de luz que podem serusadas em um programa. Entretanto, nem todas elas necessitam ser implementadas em hardware(algumas implementacoes podem ter apenas uma fonte de luz em hardware).Existem tres tipos de fonte de luz no OpenGL: fontes de luz direcionais, fontes de luz pontuaise fontes de luz refletoras (spot lights). A especificacao do tipo de fonte de luz e feita atraves daconfiguracao de seus parametros (nao existe uma diferenciacao explicita entre esses tipos).Aqui esta um exemplo de configuracao de fonte de luz:GLfloat corAmbiente [] = {0.5f, 0.5f, 0.5f, 1.0f};GLfloat corDifusa [] = {1.0f, 1.0f, 1.0f, 1.0f};GLfloat posicao [] = {0.0f, 0.0f, 50.0f, 1.0f};glLightfv (GL_LIGHT0, GL_AMBIENT, corAmbiente);glLightfv (GL_LIGHT0, GL_DIFFUSE, corDifusa);glLightfv (GL_LIGHT0, GL_POSITION, posicao);glEnable (GL_LIGHT0);Todas as propriedades da fonte de luz sao especificadas pela funcao glLight*. Em linhasgerais, esse comando recebe como parametros uma contante que indica a fonte de luz a ser alterada(GL_LIGHT0, GL_LIGHT1, ..., GL_LIGHT7), a propriedade a ser altera e valor dessapropriedade.33UFF - Mestrado em Computacao Luis ValenteNo exemplo, foram especificadas as componentes de cor difusa e ambiente da fonte de luz,assim como sua posicao. A diferenca entre entre fontes de luz direcionais e pontuais e determinadapelo parametro de posicao. Se o quarto parametro (w) for 1.0, significa que a fonte de luz e pontual(e esta localizada naquela posicao). Caso o valor seja 0.0, significa que a fonte de luz e direcional(ou seja, ela esta localizada a uma distancia infinita ao longo do vetor especificado como posicao).Por ultimo, e necessario habilitar o uso da fonte de luz desejada.O valor do componente especular da fonte de luz pode ser alterado com a propriedadeGL_SPECULAR:GLfloat corEspecular [] = {1.0f , 1.0f, 1.0f, 1.0f};glLightfv (GL_LIGHT0, GL_SPECULAR, corEspecular);Para a criacao de spot lights, existem algumas propriedades que podem ser alteradas, conformee descrito neste exemplo:GLfloat spotDirection [] = {0.0f, 0.0f, -1.0f};glLightfv (GL_LIGHT0, GL_SPOT_DIRECTION, spotDirection);glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 60.0f);glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 100.0f);A principal propriedade a ser alterada e o angulo (em graus) que define o cone de luz, quecorresponde a constante GL_SPOT_CUTOFF. Essa propriedade e ilustrada na figura 9.1.Figura 9.1 Propriedade GL_SPOT_CUTOFF (NeDa97)Os valores possiveis para essa propriedade variam de 0o a 90o. Existe um valor especial, 180o,que pode ser usado para desabilitar essa propriedade (efetivamente desabilitando esse tipo de fontede luz). Esse valor e o padrao.A propriedade GL_SPOT_DIRECTION indica qual e a direcao do feixe de luz. O valor dapropriedade e expresso em coordenadas do objeto (ou seja, em relacao a fonte de luz).A propriedade GL_SPOT_EXPONENT indica a intensidade de distribuicao da luz. Os valoresaceitos variam de 0 a 128. Quanto maior o valor, mais concentrada e a luz no centro do cone. Ovalor padrao e 0, que resulta em uma distribuicao uniforme da luz.34UFF - Mestrado em Computacao Luis Valente10. Mapeamento de texturaO mapeamento de texturas em OpenGL e feito com os seguintes passos: Habilitar o uso de texturas; Leitura da imagem em disco (ou geracao dos dados da textura atraves de algumalgoritmo); Transferir os dados da textura para o OpenGL; Selecionar a textura para uso e especificar as coordenadas de textura dos vertices.Esses passos serao explicados nas secoes seguintes.10.1. Habilitar o uso de texturasO mapeamento de texturas, por padrao, esta desligado no OpenGL. O OpenGL permite o uso detexturas de uma, duas ou tres dimensoes. Neste trabalho, o enfoque sera dirigido ao uso de texturasde duas dimensoes.Para habilitar o mapeamento de texturas de duas dimensoes, e necessario usar o seguintecomando:glEnable (GL_TEXTURE_2D);De forma analoga a de outras propriedades, o mapeamento de texturas pode ser desligado com ocomando correspondente glDisable.10.2. Identificadores de texturasTodas as texturas em OpenGL sao referenciadas por um identificador (numero). Osidentificadores podem ser requisitados ao OpenGL com o seguinte trecho de codigo:GLuint identificador;glGenTextures (1, & id);O primeiro argumento do comando glGenTextures indica a quantidade de identificadores aserem criados enquanto o segundo parametro indica onde esses identificadores serao armazenados.Como e possivel perceber, varios identificadores podem ser gerados de uma so vez, como eexemplificado a seguir:GLuint texturas [5];glGenTextures (5, texturas);Para que seja possivel usar a textura, e necessario informar ao OpenGL que a textura sera usada.Para isso, e necessario usar este comando:glBindTexture (GL_TEXTURE_2D, identificador);A partir desse momento, todas as operacoes envolvendo texturas fazem referencia e/ou afetam atextura representada por identificador.35UFF - Mestrado em Computacao Luis ValenteQuando a textura nao for mais necessaria, sera preciso liberar os recursos que foram alocados.Essa tarefa e realizada como no exemplo a seguir:glDeleteTextures (1, & identificador);glDeleteTextures (5, texturas);O comando glDeleteTextures recebe como parametros a quantidade de texturas a teremseus recursos devolvidos ao sistema e um local (uma variavel ou array) que contem osidentificadores das texturas.10.3. Transferncia dos dados para o OpenGLPara transferir os dados da textura para o OpenGL, e necessario usar este comando:void glTexImage2D(GL_TEXTURE_2D,GLint level,GLint components,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const GLvoid *pixels);O parametro level indica o nivel de detalhe da textura. O nivel de detalhe e usado para seespecificar mipmaps. O nivel zero (0) corresponde a imagem original.O parametro components indica o numero de componentes de cor existentes na imagem. Osvalores permitidos sao 1, 2, 3 ou 4.Os parametros width e height indicam a largura e a altura da imagem em pixels,respectivamente. Uma observacao importante e que esses valores precisam ser potencia de 2.O parametro border indica se a textura possui uma borda. Os valores possiveis sao 0 ou 1.O parametro format indica qual e o formato dos dados da imagem. Existem varias constantespara representar esses tipos, como GL_RGB, GL_RGBA e GL_LUMINANCE (esses valores estaolistados na documentacao).O parametro type indica qual e o tipo verdadeiro do array pixels. Por exemplo, se os dadosda imagem foram carregados em um array de GLubytes, o tipo sera GL_UNSIGNED_BYTE (osoutros valores estao listados na documentacao.O ultimo parametro corresponde ao array que contem os dados da imagem.Um exemplo simples de uso dessa funcao e descrito no trecho de codigo a seguir:/*** Carregar uma imagem RGB de 64x64 do disco e transfer-la* para o OpenGL*/unsigned int * buffer;36UFF - Mestrado em Computacao Luis ValenteGLuint id;... // alocar buffer para imagem e carrega imagem do disco// (isso ainda ser visto com mais detalhes)// habilita o uso de texturas 2DglEnable (GL_TEXTURE_2D);// gerar um identificador de texturaglGenTextures (1, & id);// selecionar a textura para usoglBindTexture (GL_TEXTURE_2D, id);// transferir os dados para o OpenGLglTexImage2D (GL_TEXTURE_2D,0, // nvel de detalhe3, // nmero de componentes de cor64, // largura64, // altura0, // bordaGL_RGB, // formatoGL_UNSIGNED_BYTE // tipo de dados do arraybuffer // array contendo os// dados da imagem);10.3.1. MipmapsA tecnica de mipmaps foi definida por Lance Williams no artigo Pyramidal Parametrics(SIGGRAPH '83). A tecnica consiste em se criar varias versoes de uma mesma imagem, emresolucoes diferentes, como ilustrado na figura 10.1.37UFF - Mestrado em Computacao Luis ValenteFigura 10.1 Exemplo de uma cadeia de mipmaps (NeDa97)Esse processo e realizado ate que se chegue a menor imagem possivel (com 1 pixel). Asmipmaps podem ser aplicadas para mapeamento de texturas em poligonos da seguinte forma: ospoligonos que estao distantes do observador usariam versoes de menor resolucao das texturas,enquanto os que estao proximos do observador utilizariam uma textura de maior resolucao.Algumas vantagens desse metodo sao: Melhoria do desempenho da aplicacao, porque como as imagens sao pre-fltradas, epossivel escolher uma imagem que possua tamanho proximo ao do poligono a ser mapeado,reduzindo o custo do processamento em tempo real da interpolacao. Adicionalmente, podemser aplicados filtros mais custosos (que produzam melhores resultados visuais) na etapa deinicializacao (geracao das mipmaps), o que talvez nao poderia ser feito em tempo real. Diminuicao de artefatos visuais causados pelo aliasing.Uma das desvantagens e a quantidade de espaco adicional para se armazenar as imagens.O OpenGL possui uma funcao para a geracao automatica de mipmaps, que esta definida naGLU. Essa funcao pode ser usada da seguinte forma:gluBuild2DMipmaps (GL_TEXTURE_2D,components, // igual ao glTexImage2Dwidth, // igual ao glTexImage2Dheight, // igual ao glTexImage2Dformat, // igual ao glTexImage2Dtype, // igual ao glTexImage2Dpixels // igual ao glTexImage2D);10.4. Leitura da imagem em discoO OpenGL nao oferece nenhuma funcionalidade para ler e interpretar arquivos de imagem dodisco. Essa tarefa e de responsabilidade do desenvolvedor. Entretanto existem diversas bibliotecasdisponiveis na internet para auxiliar o desenvolvedor nessa tarefa. Neste trabalho, sera usada abiblioteca DevIL para a leitura dos dados em disco.38UFF - Mestrado em Computacao Luis Valente10.4.1. Instalao da DevILA biblioteca DevIL (Developer's Image Library) esta disponivel em http://www.imagelib.org.Essa biblioteca e gratuita e possui o codigo aberto, esta disponivel para varias plataformas. Ela foiescolhida por ser facil de se usar e possuir um modelo de uso parecido com o OpenGL.Inicialmente, e preciso baixar do site da DevIL a versao pre-compilada da biblioteca (a nao serque ser queira compila-la para gerar as DLLs). A versao pre-compilada para Windows esta prontapara ser usada com o Visual C++.A seguir, e necessario configurar o compilador para usar os arquivos .h e os arquivos de ligacao.As instrucoes supoem que o arquivo tenha sido descompactado em c:\devil.Para configurar a DevIL no Visual C++ 6: Acesse os menus Tools, Options e escolher a aba Directories. Em Show directoriesfor, escolher include files. Criar uma nova entrada e acrescente c:\devil\include. Acesse os menus Tools, Options e escolher a aba Directories. Em Show directoriesfor, escolher library files. Criar uma nova entrada e acrescentar c:\devil\lib.Para configurar a DevIL no Visual C++ .NET: Acesse os menus Tools, Options e escolher Projects no painel da esquerda. Aseguir, escolher VC++ Directories e em Show directories for, escolher Include files.Criar uma nova entrada e acrescentar c:\devil\include. Acesse os menus Tools, Options e escolher Projects no painel da esquerda. Aseguir, escolher VC++ Directories e em Show directories for, escolher library files.Criar uma nova entrada e acrescentar c:\devil\lib.10.4.2. Leitura da imagem em discoUma vez que DevIL foi configurada corretamente, e possivel usar suas funcoes para ler osdados da imagem do disco, conforme demonstra o trecho de codigo a seguir:/*** Esta funo demonstra como carregar um arquivo em disco* com a DevIL.** Retorna um identificador de textura do OpenGL.* Caso seja 0, porque algum erro ocorreu no processo.*/GLuint CarregarImagem (const char * arquivo){// esta varivel representa um identificador para a imagemILuint image;// cria um id para a imagemilGenImages (1, & image);// seleciona a imagem para uso39UFF - Mestrado em Computacao Luis ValenteilBindImage (image);// determinamos que o 0,0 da figura o canto// inferior esquerdoilEnable (IL_ORIGIN_SET);ilOriginFunc (IL_ORIGIN_LOWER_LEFT);// carregamos a imagem do discoilLoadImage (arquivo);// algum erro no carregamento do arquivo ?ILenum erro = ilGetError ();if (erro != IL_NO_ERROR){// desaloca recursos usados para carregar a imagemilDeleteImages (1, & image);return 0;}// recuperamos dados sobre a imagemint width = ilGetInteger (IL_IMAGE_WIDTH);int height = ilGetInteger (IL_IMAGE_HEIGHT);int bytesPerPixel = ilGetInteger (IL_IMAGE_BYTES_PER_PIXEL);ILenum imageFormat = ilGetInteger (IL_IMAGE_FORMAT);ILubyte * imageData = ilGetData ();// envia os dados para o OpenGLGLuint tex = 0;// habilita o uso de texturasglEnable (GL_TEXTURE_2D);// gera um identificador para a texturaglGenTextures (1, & tex);// seleciona a textura para usoglBindTexture (GL_TEXTURE_2D, tex);// carrega os dados para o OpenGLglTexImage2D (GL_TEXTURE_2D,0, // nvel de detalhe40UFF - Mestrado em Computacao Luis ValentebytesPerPixel, // nmero de componentes de corwidth, // larguraheight, // altura0, // bordaimageFormat, // formatoGL_UNSIGNED_BYTE // tipo de dados do arrayimageData // array contendo os dados// (pixels) da imagem);// desaloca os recursos usados para carregar// a imagem com a DevILilDeleteImages (1, & image);// retorna o identificador de texturareturn tex;}10.4.3. Outras consideraesPara se usar as funcoes da DevIL, e preciso incluir o seu arquivo principal:#include Antes que as funcoes da DevIL possam ser usadas, e necessario inicializar a biblioteca. Ao finaldo programa, e necessario finalizar a biblioteca. Esses comandos correspondem a:ilInit (); // inicializar a DevILilShutDown (); // finalizar a DevILPara a ligacao com a DLL, e preciso especificar o arquivo de ligacao. No Visual C++ 6, issopode ser feito da seguinte forma: Acesse o menu Projects e depois Settings. A seguir, acesse a aba Linker. No campoObject/library modules acrescente devil.lib (sem aspas).Ja no Visual C++ .NET, o procedimento e este: Acesse o menu Project e depois Properties. No painel da esquerda, escolha a pastaLinker e depois Input. No campo Additional dependencies, acrescente devil.lib (semaspas).10.5. Coordenadas de texturaPara efetivamente aplicar a textura nos poligonos, e preciso especificar as coordenadas detextura.O sistema de coordenadas de textura (2D), e ilustrado na figura 10.2.41UFF - Mestrado em Computacao Luis ValenteFigura 10.2 Sistema de coordenadas de textura 2DAs coordenadas de textura 2D sao especificadas com este comando:glTexCoord2* (s, t)O eixo s corresponde ao eixo horizontal da figura 10.2 e o eixo t corresponde ao eixo vertical damesma figura. No exemplo a seguir, uma textura e mapeada em um quadrado:glBindTexture (GL_TEXTURE_2D, id);glColor3f (1.0f, 1.0f, 1.0f);glBegin (GL_QUADS);glTexCoord2f (0.0f, 0.0f);glVertex3f (-10.0f, -10.0f, 0.0f);glTexCoord2f (1.0f, 0.0f);glVertex3f (10.0f, -10.0f, 0.0f);glTexCoord2f (1.0f, 1.0f);glVertex3f (10.0f, 10.0f, 0.0f);glTexCoord2f (0.0f, 1.0f);glVertex3f (-10.0f, 10.0f, 0.0f);glEnd ();Como visto na figura 10.2, as coordenadas de textura variam de 0.0 a 1.0 nos dois eixos.Entretanto, caso sejam especificados valores fora dessa faixa, ocorrera uma destas alternativas: atextura sera truncada (GL_CLAMP) ou a textura sera repetida pelo poligono (GL_REPEAT, que eo padrao). A figura 10.3 ilustra esses resultados:42UFF - Mestrado em Computacao Luis ValenteFigura 10.3 Resultados (NeDa97) (a) Truncamento. (b) Repetio (padro)Esse comportamento pode ser redefinido utilizando-se o seguinte trecho de codigo:glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, modo);glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, modo);A constante GL_TEXTURE_WRAP_S indica que a alteracao sera efetuada somente para o eixoS, enquanto que a constante GL_TEXTURE_WRAP_T indica que o eixo T sera o afetado. Dessaforma, e possivel determinar comportamentos diferentes para cada um dos eixos.10.6. Outros parmetrosExistem diversos parametros que afetam a aparencia de textura que podem ser configurados.Um dos mais interessantes e aquele que determina qual sera o filtro utilizado para interpolar atextura sobre o poligono.Os filtros disponiveis podem ser de dois tipos: filtros de reducao ou filtros de ampliacao. Osfiltros de reducao sao usados quando a textura e maior do que o poligono a ser mapeado, enquanto ofiltro de ampliacao e usado quando o poligono e maior do que a textura. Os filtros podem serespecificados com este trecho de codigo:glTextureParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,filtro);glTextureParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,filtro);A constante GL_TEXTURE_MIN_FILTER indica que o filtro que sera alterado e o filtro dereducao. Ja o filtro de ampliacao e representado pela constante GL_TEXTURE_MAG_FILTER.Os filtros existentes sao os seguintes: GL_NEAREST: Utiliza o texel mais proximo (vizinho) do pixel que esta sendo mapeado. Eo filtro de melhor desempenho, porem e o de menor qualidade. Pode ser usado como filtro deampliacao ou reducao.43UFF - Mestrado em Computacao Luis Valente GL_LINEAR: Utiliza interpolacao linear. Prove melhores resultados visuais, mas e maiscustoso em termos computacionais. Pode ser usado como filtro de reducao e ampliacao. Essefiltro e o selecionado por padrao. GL_NEAREST_MIPMAP_NEAREST: Escolhe a mipmap com tamanho semelhante ao dopoligono que esta sendo mapeado e usa o mesmo criterio que GL_NEAREST para escolher otexel da textura. GL_NEAREST_MIPMAP_LINEAR: Escolhe a mipmap com tamanho semelhante ao dopoligono que esta sendo mapeado e usa o mesmo criterio que GL_LINEAR para escolher otexel da textura. GL_LINEAR_MIPMAP_NEAREST: Escolher duas mipmaps com tamanhos maisproximos ao do poligono que esta sendo mapeado e usar o filtro GL_NEAREST para escolhero texel de cada textura. O valor final e uma media entre esses dois valores. GL_LINEAR_MIPMAP_LINEAR: Escolher duas mipmaps com tamanhos mais proximosao do poligono que esta sendo mapeado e usar o filtro GL_LINEAR para escolher o texel decada textura. O valor final e uma media entre esses dois valores.Outro parametro que pode ser alterado indica o modo como a textura sera afetada pelas coresdos poligonos e informacoes de iluminacao calculadas. O modo padrao (GL_MODULATE) indicaque essas informacoes sejam interpoladas com os dados da textura. Ja o modo GL_DECAL indicaque o mapeamento deve ignorar essas informacoes (a textura e mapeada como se fosse umadesivo).Esses modos podem ser determinados com o comando:glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_MODE, modo);11. Objetos mais complexosO OpenGL oferece meios de desenhar objetos mais complexos do que linhas e poligonos, comocurvas de Bezier e NURBS.Esta secao explica um outro tipo de objeto que pode ser desenhado em OpenGL: as superficiesquadraticas. Com o uso de superficies quadraticas, e possivel desenhar cilindros, discos e esferas.As superficies quadraticas sao representadas em OpenGL pelo tipo de dadosGLUquadricObj. Inicialmente, e preciso criar um objeto desses para uso:#include GLUquadricObj * quadric = gluNewQuadric ();Quando nao for mais necessario usar o objeto quadric, sera necessario liberar os recursosalocados para a superficie:gluDeleteQuadric (quadric);Existem varias propriedades da superficie que podem ser configuradas atraves de comandos daGLU.44UFF - Mestrado em Computacao Luis ValenteO comando gluQuadricStyle afeta o modo como o objeto e desenhado. Os modospossiveis sao GLU_FILL (solido), GLU_LINE (wireframe), GLU_SILHOUETTE (desenhasomente a silhueta) e GLU_POINT (desenha somente os vertices). A sintaxe desse comando e:gluQuadricStyle (quadric, estilo);O comando gluQuadricNormals controla o modo como os vetores normais do objeto saogerados. O modo GLU_NONE indica que os vetores normais nao devem ser gerados. O modoGLU_FLAT indica que os vetores normais devem ser gerados para cada face somente, o que resultaem uma aparencia facetada para o objeto. Ja o modo GLU_SMOOTH indica que os vetores normaisdevem ser gerados para cada vertice, para que a aparencia resultante seja suave. Os vetores normaisafetarao a aparencia do objeto caso a iluminacao esteja sendo usada. O comando pode ser usado daseguinte forma:gluQuadricNormals (quadric, modo);Outra propriedade relacionada com iluminacao indica qual e a orientacao usada para os vetoresnormais. Existem duas opcoes: os vetores podem apontar para fora do objeto ou para dentro doobjeto. As opcoes correspondentes sao GLU_OUTSIDE e GLU_INSIDE. Geralmente, escolhe-segerar os vetores normais apontando para dentro do objeto quando se deseja posicionar o observadordentro desse objeto. O comando para alterar essa propriedade e:gluQuadricOrientation (quadric, valor);As superficies quadraticas tambem podem texturizadas. Existe um comando para determinar seas coordenadas de textura do objeto devem ser geradas automaticamente, como e exemplificado aseguir:gluQuadricTexture (quadric, flag);As opcoes possives sao GLU_TRUE (gerar as coordenadas) e GLU_FALSE (nao gerar ascoordenadas).11.1. CilindrosOs cilindros podem ser desenhados com o seguinte comando:void gluCylinder (GLUquadricObj * qobj,GLdouble baseRadius,GLdouble topRadius,GLdouble height,GLint slices,GLint stacks);Os parametros baseRadius e topRadius indicam os raio da base do cilindro e do topo docilindro, respectivamente. O parametro height indica qual e a altura do cilindro. O parametroslices indica qual e o numero de faces na lateral do cilindro. Ja o parametro stacks indicaquantas divisoes existem ao longo do corpo do cilindro. Esses parametros sao ilustrados na figura11.1.45UFF - Mestrado em Computacao Luis ValenteFigura 11.1 Parmetros de gluCylinder. (a) slices. (b) stacks.A base do cilindro e desenhada em z = 0, e o topo estara em z = height. As extremidades docilindro nao sao preenchidas, ou seja, o cilindro nao e fechado.11.2. DiscosOs discos podem ser desenhados com a seguinte funcao:void gluDisk (GLUquadricObj * qobj,GLdouble innerRadius,GLdouble outerRadius,GLint slices,GLint loops);Os parametros innerRadius e outerRadius correspondem aos raios interno e externo dodisco. O parametro slices indica quantos lados o disco possui. Esses parametros sao ilustrados nafigura 11.2.Figura 11.2 Parmetros raio interno e externo de gluDisk46UFF - Mestrado em Computacao Luis ValenteFinalmente, o parametro loops indica o numero de circulos concentricos que devem serdesenhados entre os raios interno e externo.O disco e desenhado no plano z = 0.11.3. Discos incompletosA funcao gluDisk permite desenhar discos completos. E possivel desenhar discosincompletos (que nao possuem uma circunferencia completa). Para isso, usa-se esta funcao:void gluPartialDisk (GLUquadricObj * qobj,GLdouble innerRadius,GLdouble outerRadius,GLint slices,GLint loops,GLdouble startAngle,GLdouble sweepAngle);A diferenca entre gluDisk e gluPartialDisk e nesta ultima funcao, uma fracao do discoe desenhada, com inicio no angulo startAngle e fim no angulo startAngle+sweepAngle.O angulo startAngle e especificado no sentido horario quando visto a partir do topo do disco.O disco e desenhado no plano z = 0.11.4. EsferasPara se desenhar esferas, e utilizado o seguinte comando:void gluSphere (GLUquadricObj * qobj,GLdouble radius,GLint slices,GLint stacks);A esfera e desenhada de forma que o seu centro coincida com a origem. O parametro radiusdefine raio da esfera. O parametro slices indica o numero de divisoes da esfera em torno do eixoZ (como longitude). Ja o parametro stacks indica o numero de divisoes da esfera ao longo doeixo Z (como latitude). A figura 11.3 ilustra os parametros slices e stacks.47UFF - Mestrado em Computacao Luis ValenteFigura 11.3 Parmetros de glSphere. (a) slices. (b) stacks.12. Exemplo com freeglutEsta secao apresenta um esqueleto de programa que pode ser usado como ponto de partida parao desenvolvimento de aplicacoes simples com freeglut e OpenGL. Nesse programa, um quadradovermelho sera animado e desenhado em uma janela. Quando o quadrado colidir contra as bordas daparede (na verdade, da viewport), sua velocidade sera alterada de modo que o objeto ira quicar. Ousuario podera encerrar a aplicacao usando a tecla ESC do teclado.O primeiro passo e incluir os arquivos necessarios e declarar as funcoes que tratarao eventos nofreeglut, como e feito neste trecho de codigo:#include GLfloat quad_x = 0.0f;GLfloat quad_y = 0.0f;GLfloat quad_z = 0.0f;GLfloat vx = 0.01f;GLfloat vy = 0.005f;GLfloat vz = 0.008f;void OnUpdate ();void OnResize (int width, int height);void OnRender ();void OnKeyPress (unsigned char key, int x, int y);void InitGL ();O unico arquivo que precisa ser incluido e o do freeglut. A posicao atual do quadrado earmazenada nas variaveis quad_x, quad_y e quad_z. O ponto de referencia e o centro doquadrado. A velocidade do quadrado e armazenada nas variaveis vx, vy e vz.48UFF - Mestrado em Computacao Luis ValenteAs funcoes OnUpdate, OnResize, OnRender e OnKeyPress sao usadas para tratareventos. A atualizacao da animacao e realizada em OnUpdate. A funcao OnResize eresponsavel por tratar o evento que ocorre quando a janela e redimensionada. As operacoes dedesenho sao feitas em OnRender, e a funcao OnKeyPress e responsavel por tratar o teclado.Finalmente, na funcao InitGL, e estabelecida uma configuracao inicial para o OpenGL.O programa principal e definido no seguinte trecho de codigo:void main (){glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);glutCreateWindow (Exemplo de animao);glutDisplayFunc (OnRender);glutReshapeFunc (OnResize);glutKeyboardFunc (OnKeyPress);glutIdleFunc (OnUpdate);InitGL ();glutMainLoop ();}12.1. Funo principalA primeira linha do programa requisita ao freeglut que sejam usados dois buffers para a janela,um z-buffer e modo de cores RGB. Como a aplicacao usa uma animacao, o modo double-buffered enecessario para evitar o efeito de flicker.As funcoes responsaveis por tratar eventos sao especificadas ao freeglut logo depois, comorepetido aqui:glutDisplayFunc (OnRender);glutReshapeFunc (OnResize);glutKeyboardFunc (OnKeyPress);glutIdleFunc (OnUpdate);A funcao glutReshapeFunc especifica qual e a callback usada para se tratar o evento deredimensionamento da janela. E importante que esse evento seja tratado para que se possa atualizara viewport e a projecao usada pelo programa quando a janela mudar de tamanho (o OpenGL nao fazisso automaticamente).Uma das funcoes disponiveis para especificar a callback responsavel tratar eventos do teclado eglutKeyboardFunc.Em glutIdleFunc, e especificada uma funcao que sera executada quando nao houver outroseventos a serem tratados (em outras palavras, essa funcao e executada quando a aplicacao estaociosa).Logo adiante, os estados iniciais do OpenGL sao determinados e a aplicacao inicia seu lacoprincipal de execucao.49UFF - Mestrado em Computacao Luis Valente12.2. InicializaoNa etapa de inicializacao, sao submetidos comandos que determinam funcionalidades que seraousadas no restante da aplicacao. A funcao correspondente e descrita a seguir:void InitGL (){glEnable (GL_DEPTH_TEST);glEnable (GL_CULL_FACE);glClearColor (0.0f, 0.0f, 0.0f, 1.0f);glMatrixMode (GL_MODELVIEW);glLoadIdentity ();}Essa funcao requisita que o testes de z-buffer e eliminacao de faces escondidas (backfaceculling) sejam habilitados.A seguir, a cor de fundo da janela e estabelecida. (preto).Finalmente, determina-se que o tipo de projecao usado a partir deste momento sera a matriz demodelagem.