Manual de Apoio Luís Filipe Lobo

Tamanho: px
Começar a partir da página:

Download "Manual de Apoio 2010. Luís Filipe Lobo <ellobo@ipb.pt>"

Transcrição

1 Computação Gráfica Manual de Apoio 2010 Luís Filipe Lobo

2 Conteúdo 1 Introdução A caminho do 3D Efeitos 3D Transformações Geométricas Eye Coordinates Viweing Transformations Modeling Transformations Projection Transformations Viewport Transformations Princípios Básicos de Programação 3D Sistemas de Coordenadas Coordenadas Cartesianas - 2D Viewport - Mapeamento de coordenadas para pixels O Vertex (vértice) Coordenadas Cartesianas 3D Projecções: 3D 2D Projecções Ortogonais Projecções em Perspectiva Introdução ao OpenGL O pipeline OpenGL Tipos de Dados Nomes de Funções - Convenção JOGL - Java OpenGL The State Machine O pipeline de Transformações Matriz Modelview A Matriz Identidade (Identity Matrix) Projecções Câmaras e Actores Primitivas Geométricas e Buffers O ponto 3D - (Vertex) Primitivas Pontos: GL POINTS Linhas: GL LINES Tiras de Linha: GL LINE STRIP Loops de Linha: GL LINE LOOP Padrões de Linha:GL LINE STIPPLE Triângulos: GL TRIANGLES Tiras de Triângulos:GL TRIANGLE STRIP Triangle Fans:GL TRIANGLE FANS Outras Primitivas Quadriláteros: GL QUADS Tiras de Quadrados:GL QUAD STRIP Polígonos: GL POLYGON Preenchimento de Polígonos

3 4.3.5 Regras na Criação de Polígonos Sub-divisão de Arestas Buffers Buffer de Profundidade Scissors Cores, Materiais e Luzes Cor Modos de Display Utilização de Cores no OpenGL Shading Cores no Mundo Real Luz Ambiente Luz Difusa Luz Especular Luz de Modo Geral Materiais no Mundo Real Adição de Luzes ao Cenário Fontes de Luz Configurando uma Fonte de luz Efeitos de Iluminação Luz Especular Normal Averaging Especificando um Spotlight Tesselation Cores e Materiais (Continuação) Blending Combinação de Cores Alteração da Equação de Blending Antialiasing Multisampling Nevoeiro (Fog) Accumulation Buffer Imagens no OpenGL Bitmaps Pixmaps Operações com Pixels Outras Operações com Imagens Mapeamento de Texturas Carregamento de Texturas Pipeline do Carregamento de Imagens Utilizando o Color Buffer Actualização de Texturas Mapeamento de Texturas à Geometria Exemplo de Textura 2D Texture Environment Parametrização de Texturas Filtering Básico Texture Wrap Mipmapping Mipmap Filtering Geração de níveis de Mipmapping Geração de Mipmaps por Hardware Level Of Detail (LOD) Bias Texture Objects

4 9 Mapeamento de Texturas: Conceitos Avançados Cor Secundária Anisotropic Filtering Compressão de Texturas Geração de Coordenadas de Texturas Oject Linear Mapping Eye Linear Mapping Sphere Mapping Cube Mapping Carregamento do Cube Map Utilização dos Cube Maps Curvas e Superfícies Superfícies Incorporadas no OpenGL Configuração de Superfícies Quádricas Desenho de Superfícies Quádricas Curvas de Bézier e Superfícies Representação Paramétrica Pontos de Control (control points) Continuidade Evaluators Superfícies 3D Luzes e Vectores Normais Conceitos Avançados Display Lists Prós e Contras A Exemplos 113 A.1 Exemplo Simples B Tabelas 114 B.1 Formato de Imagem (pixmap) B.2 Tipo de Dados (pixmap) C Código Fonte 116 C.1 Example0.java C.2 Imaging.java C.3 Pyramid.java C.4 TexGen.java C.5 CubeMap.java C.6 SnowMan.java C.7 Bezier2D.java C.8 Bezier3D.java C.9 BezierLighting.java

5 Convenções Na medida dos possíveis foram traduzidos os nomes de inglês para português. No entanto, para o desenvolvimento com a API OpenGL, algumas palavras chave são de grande relevo na língua original, o inglês. Para facilitar a localização de métodos nas classes JOGL, estes são apresentados sob a forma: Classe. metodo ( Tipo1 arg1,..., TipoN argn ); Referências Os apontamentos foram elaborados com base nas referências: OpenGL Superbible [?] 4

6 Capítulo 1 Introdução 1.1 A caminho do 3D Os objectos tri-dimensionais podem ser mostrados ou descritos com recurso a três medidas: largura, altura e profundidade. Nos dispositivos gráficos, superfícies inevitavelmente 2D, a forma de dar a sensação de profundidade é conseguida pela introdução de perspectiva (Figura 1.1). Figura 1.1: Wireframe de um cubo 3D A visão humana obtém a percepção tridimensional pela utilização de dois olhos. O nosso cérebro recebe duas imagens bidimensionais ligeiramente diferentes por serem recebidas em ângulos diferentes (Figura 1.2). As duas imagens são então combinadas numa só com o objectivo de produzir uma única imagem, mas desta vez tridimensional. Figura 1.2: Visão tridimensional À medida que um determinado objecto se afasta, o ângulo (θ) entre as duas imagens vai diminuindo. Normalmente os dispositivos gráficos que simulam o efeito de realismo 3D (estereoscópicos) utilizam duas imagens diferentes para cada olho. Os dispositivos gráficos flat utilizam o mesmo mecanismo que a natureza providencia para que pessoas com um único olho possam ver a três dimensões. O artefacto utilizado para conseguir este efeito é, com efeito, a perspectiva. Para além deste artefacto, mesmo com um único olho, o nosso cérebro continua a conseguir discernir profundidade, em grande parte devido aos efeitos presentes nos objectos. 5

7 1.2 Efeitos 3D Uma palavra a ter em mente na computação gráfica é rendering. Rendering consiste na conversão da descrição de um objecto tridimensional numa imagem no ecrã. Os efeitos seguintes são aplicados aquando do rendering de uma imagem. Perspective : A perspectiva refere-se aos ângulos entre as linhas que levam à ilusão de estarmos na presença de três dimensões. Color and Shading: A colocação de cores nas várias faces do cubo, permite replicar níveis de escuridão (shading), reafirmando o aspecto de um objecto sólido. (a) Light & Shadows: Ainda com a utilização de cores é possível dar às superfícies a sensação de iluminação. Adicionando sombra avançamos um passo no caminho do realismo. (b) Texture Mapping: A maneira brute-force de alcançar realismo, pode passar pela adição de mais polígonos (mais detalhe) à imagem, no entanto, á custa de processamento adicional. Outra forma de obter o mesmo efeito, passa pela utilização de imagens nas faces dos objectos - texture mapping. A imagem fornecida para utilizar é chamada de texture Cada elemento da imagem que é aplicado numa face é chamado texel O processo esticar a imagem à face do objecto é denominada de filtering Fog: A adição de nevoeiro poderá contribuir para a credibilidade da imagem. 6

8 Blenging & Transparency: Blending consiste na mistura de objectos ou cores. Através da sobreposição de imagens ou objectos, é possível dar a sensação de transparência ou reflexão. Antialiasing: O Aliasing é provocado pelo processo de rastering nos monitores. Um processo semelhante ao blenging dos pixels com a cor de fundo confere-lhe um aspecto suave. 1.3 Transformações Geométricas As transformações geométricas em OpenGL são efectuadas por intermédio de operações matriciais. Transformações consecutivas resultam na multiplicação de várias matrizes. Deste modo, duas transformações consecutivas são acumulativas. As transformações geométricas podem ser de três tipos: viewing, modeling e projection. A terminologia utilizada no OpenGL para as transformações é: Viewing Especificação da Localização do Observador (ou câmara) Modeling Localização de Objectos na Cena ModelView Dualidade de transformações Viewing e Modeling Projection Modificações no clip e size do volume (clipping volume) da cena Viewport Relacionado com a escala do output final para o utilizador Eye Coordinates As coordenadas do olho representam um ponto virtual absoluto (independente de qualquer transformada), onde está localizado o observador. Na Figura 1.3a, olhamos o nosso sistema cartesiano 3D de frente (o eixo-z não é visível). Na Figura 1.3b o eixo-x e eixo-y foram rodados. À medida que o valor de z aumenta, os objectos ficam mais perto do observador Viweing Transformations As primeiras transformações a serem executadas, são as relacionadas com o ponto para onde o observador está a olhar. Por omissão, a nossa cena contém um observador localizado no ponto O 0 = [x = 0, y = 0, z = 0] e a direcção do olhar aponta para a parte negativa do eixo z de tal forma que os objectos desenhados com z > 0 ficam situados nas costas do utilizador. 7

9 Figura 1.3: Duas perspectivas diferentes (eye coordinates) Modeling Transformations Este tipo de transformações (Figura 1.4), são aplicadas aos objectos no nosso model (modelo 3D). Figura 1.4: Transformações do Modelo (modeling) A ordem das transformações dita o aspecto final da nossa cena uma vez que as transformações são acumulativas. Na Figura 1.5 é mostrada a diferença na ordem da aplicação de duas transformações, ainda que com os mesmos valores. Dualidade Model/Viewing A dualidade é utilizada porque no fim de contas, transformações efectuadas no model ou no viewing têm um efeito semelhante. A diferença é entre mover a referência das coordenadas na nossa direcção (Figura 1.6a) ou aproximarmos-nos da referência (Figura 1.6b), o que representa o mesmo resultado. Basicamente, uma transformação viewing é semelhante a uma transformação modeling que aplicamos a um objecto virtual - o observador Projection Transformations As transformações feitas ao sistema de projecções configuram o volume da área visível da nossa cena. Os principais tipos de projecções são: Orthographic Projection Neste tipo de projecção os objectos são desenhados no ecrã usando linhas paralelas para a definição da perspectiva, o que implica que os objectos apresentam todos tamanho semelhante independentemente da distância. Perspective Projection A aparência dos objectos é mais semelhante à realidade. Objectos mais distantes aparecem mais pequenos que objectos mais próximo. Neste perspectiva, linhas paralelas convergem num ponto distante. 8

10 Figura 1.5: Transformações: rotação/translação e translação/rotação Figura 1.6: Dualidade Model/Viewing Figura 1.7: esquerda: Ortogonal, direita: Perspectiva 9

11 1.3.5 Viewport Transformations No final do pipeline das transformações, obtemos uma imagem 2D que terá que ser mostrada na nossa janela. As transformações de viewport definem a porção do nosso universo 3D que é desenhada na janela e onde. 10

12 Capítulo 2 Princípios Básicos de Programação 3D 2.1 Sistemas de Coordenadas Antes de ser possível colocar um objecto numa cena é preciso um quadro de referência. Num dispositivo flat a localização é feita com recurso a dois valores, um deles normalmente refere-se à distância desde o lado esquerdo e o outro refere-se à distância desde o topo do ecrã. Nas APIs 3D, existem vários sistemas de coordenadas. Ao inicializar a nossa cena o sistema de coordenadas escolhido, define a forma como os valores fornecidos são mapeados em pixels no ecrã Coordenadas Cartesianas - 2D O sistema de coordenadas 2D mais utilizado é o sistema cartesiano. O sistema é composto por uma coordenadas x que define a distância horizontal à origem ([x = 0, y = 0]) e uma coordenada y que define a distância vertical à origem (Figura 2.1). Figura 2.1: Plano Cartesiano Clipping de Coordenadas Antes de começarmos a desenhar pontos e linhas é necessário dizer à API que zona do sistema cartesiano deverá aparecer na janela. Esta zona é normalmente denominada de clipping region (Figura 2.2) Viewport - Mapeamento de coordenadas para pixels Raramente as coordenadas cartesianas do nosso sistema, correspondem ao tamanho em pixels da janelas. É necessário fazer um mapeamento da zona visível do nosso sistema de coordenadas para o espaço mostrado em pixels na janela. Este mapeamento é chamado de viewport. Na Figura 2.3 o tamanho do viewport é o dobro da área de clipping. Na Figura 2.4 o clipping volume, ocupa apenas uma zona da janela. 11

13 Figura 2.2: Duas zonas de clipping diferentes Figura 2.3: Viewport com o dobro da área de clipping Figura 2.4: Viewport com a mesma dimensão da área de clipping 12

14 2.1.3 O Vertex (vértice) Um objecto numa imagem, pode ser decomposto em formas mais pequenas normalmente denominadas de primitives. As primitives podem ser entidades ou superfícies (pontos, linhas, planos ou polígonos) no espaço. O cubo nas imagens da introdução, são compostos de seis faces quadradas. Cada canto destes quadrados, ou de qualquer outra primitive é denominado de vertex. Cada vertex é representado por uma coordenada. O processo de construir geometria em 3D, consiste num jogo de liga-os-pontos Coordenadas Cartesianas 3D Nas coordenadas cartesianas 3D, ao sistema bidimensional, adicionamos profundidade. Um terceiro eixo (z) é perpendicular aos eixos x e y. A Figura 2.5 mostra o nosso sistema cartesiano com uma rotação (y é rodado para a esquerda, x rodado para baixo), caso contrário o eixo z não estaria visível. Figura 2.5: Coordenadas Cartesianas 3D 2.2 Projecções: 3D 2D Por mais que tentemos convencer o olho da sensação de imagem 3D, o nosso display será 2D. O nosso sistema 3D é mostrado em 2D com ajuda de trigonometria e operações matriciais simples. As coordenadas 3D são achatadas ou projectadas numa superfície 2D (o fundo da janela). O resultado obtido é semelhante ao de pintar os contornos de um objecto num vidro de uma janela (Figura 2.6). O tipo de projecção especifica como o volume deve ser transformado na janela. Figura 2.6: Projecção 2D de uma imagem 3D Projecções Ortogonais Numa projecção ortogonal, o volume visível é definido com recurso a uma superfície rectangular. Qualquer objecto fora do volume não é desenhado. Os objectos aparentam todos o mesmo aspecto, independentemente da profundidade em que se encontram. A Figura 2.7 ilustra o volume visível (viewing volume) definido especificando os clipping planes - far, near, left, right, top e bottom. O conjunto das projecções dos planos são então projectados numa imagem 2D. 13

15 Figura 2.7: O clipping volume de uma projecção ortogonal Projecções em Perspectiva Uma projecção em perspectiva é em tudo semelhante à ortogonal. Os objectos mais distantes são, no entanto mais pequenos, dando a sensação de profundidade. O viewing volume é parecido com uma pirâmide com a parte superior cortada. A forma resultante é denominada frustrum (Figura 2.8). Esta projecção é a que confere um maior realismo. Figura 2.8: O clipping volume (frustrum) de uma projecção em perspectiva 14

16 Capítulo 3 Introdução ao OpenGL O OpenGL pode ser definido como uma interface de software para dispositivos gráficos. Consiste de uma biblioteca gráfica de 3D e modeling. É altamente portable (suportada em vários sistemas operativos e dispositivos). Tira partido da aceleração hardware (onde disponível), conseguindo níveis de desempenho elevados. Mais do que uma linguagem ou uma simples API, define um standard. 3.1 O pipeline OpenGL O processo de desenho com recurso a OpenGL, é feito com recurso a um conjunto de passos (stages). O nome pipeline sintetiza numa palavra esta topologia (Figura 3.1). Figura 3.1: Versão simplificada do pipeline OpenGL Os comandos feitos com recurso à API são colocados num fila denominada command buffer (dados dos vértices (vertex), texturas,... ). Quando é dada uma ordem de processamento ao buffer (flush), quer de forma programática ou pelo driver, os dados são passados ao passo seguinte na pipeline. No passo transform and lighting, são efectuadas as transformações matemáticas e geométricas que permitem o cálculo da localização e orientação dos nossos pontos e objectos. Na fase de rasterização a imagem é criada a partir dos dados de geometria, textura e cor do passo anterior. A imagem resultante é então colocada no frame buffer que pode ser considerado como a memória do nosso dispositivo gráfico que finalmente a coloca no ecrã. 3.2 Tipos de Dados A fim de garantir portabilidade, o OpenGL define os seus próprios tipos de dados (data types). Ao fazê-lo, permite ao developer, abstrair-se dos pormenores relacionados com os compiladores de cada sistema operativo. A cada tipo de dados corresponde um sufixo. Este sufixo será utilizado a fim de identificar o tipo de dados de cada função da API. A Tabela 3.1 mostra os tipos de dados, a sua representação em C e o sufixo utilizado na nomenclatura OpenGL Nomes de Funções - Convenção As funções OpenGL seguem uma nomenclatura que ajuda na identificação da biblioteca, comando, número de argumentos e tipo de dados a utilizar nesses argumentos (Figura 3.2), segundo a sintaxe: < biblioteca >< comando >< argumentos >< tipo > O exemplo em cima é uma função da biblioteca gl, o comando Color, que recebe 3 argumentos do tipo float (f). 15

17 Tipo Interno OpenGL Tipo em C Sufixo GLbyte signed char b GLshort short s GLint, GLsizei long l GLfloat, GLclampf float f GLdouble, GLclampd double d GLubyte, GLboolean unsigned char ub GLushort unsigned short us GLuint, GLenum, GLbitfield unsigned long ui Tabela 3.1: Tipos de dados OpenGL Figura 3.2: Função OpenGL 3.3 JOGL - Java OpenGL O JOGL é um binding para a API OpenGL desenvolvido em Java. Um binding representa uma forma de utilizar funcionalidades de uma biblioteca (nativa ou não) do sistema operativo com base numa linguagem diferente da que foi utilizada nessa biblioteca. Para o caso do JOGL, a biblioteca OpenGL (ficheiro.dll no Windows,.so no Linux) do sistema é disponibilizada na linguagem de programação Java. Uma das formas mais comuns de utilizar a API consiste na criação de uma classe que implementa a interface GLEventListener. Esta interface define os métodos: void init ( GLAutoDrawable drawable ); void dispose ( GLAutoDrawable drawable ); void display ( GLAutoDrawable drawable ); void reshape ( GLAutoDrawable drawable, int x, int y, int width, int height ); init(glautodrawable drawable) Este método será invocado imediatamente depois de o contexto OpenGL ser inicializado. Normalmente é utilizado para inicializar a nossa cena, tal como configurar luzes. dispose(glautodrawable drawable) Este método é invocado aquando da libertação de recursos no contexto OpenGL. A chamada tem lugar imediatamente antes de o contexto OpenGL ser destruído. display(glautodrawable drawable) Invocado pelo contexto OpenGL para inicializar o processo de rendering. No caso de double buffering (ver... ), a chamada a este método troca automaticamente os buffers. 16

18 reshape(glautodrawable drawable, int x, int y, int width, int height) Chamada sempre que a janela (ou componente) contendo o viewport, são redimensionados. Permite a actualização e ajuste do viewport ou da visualização em geral, de forma a adequá-lo ao novo tamanho da janela. 3.4 The State Machine O desenho em OpenGL é conseguido com a ajuda de um conjunto de variáveis e atributos que vão sendo definidos ao longo da execução. No entanto, não é fácil ao developer estar consciente de todos esses elementos aquando da adição de nova geometria. Estes elementos fazem parte estado no pipeline. O OpenGL funciona como uma máquina de estados que permite gerir o estado destes elementos. Utilizando a máquina de estados, o OpenGL permite que no mesmo desenho possamos ter, por exemplo, objectos desenhados com lighting e outros sem lighting activando e desactivando uma simples flag. gl. glenable (GL. GL_LIGHTING ); //... // draw geometry with lighting gl. gldisable (GL. GL_LIGHTING ); //... // draw geometry without lighting A verificação do estado de uma determinada flag pode ser feito com recurso a gl.glisenabled(flag). 3.5 O pipeline de Transformações As transformações mais comuns são feitas na projection matrix e na modelview matrix. O caminho desde as coordenadas de simples vertex até à imagem no ecrã está descrito na Figura 3.3. Figura 3.3: Pipeline de transformações de vértices No primeiro passo, cada vector é convertido numa matrix 1 4, contento as coordenadas [x, y, z] e um factor de escala 1. O vertex é então multiplicado pela matriz de transformações Modelview, que contém as transformadas relacionadas com o observador. O resultado é multiplicado pela matriz de transformações Projection, o que elimina todos os objectos fora do nosso volume de clipping 2. No passo seguinte, as coordenadas resultantes são divididas pelo factor w do vertex, com o objectivo de normalizar as coordenadas. 1 Utilizado nas funções de vectores com 4 argumentos, ex.: glvertex4f(x, y, z, w) 2 O que representa uma mais-valia em termos de processamento 17

19 O passo final consiste no mapeamento do nosso sistema de coordenadas a um plano 2D pelas transformações na matriz de transformações Viewport Matriz Modelview Felizmente para os utilizadores da API OpenGL, uma grande parte das transformadas é disponibilizada sob a forma de um conjunto de funções de alto nível. Ainda que estas funções de alto nível permitam ao utilizador abstrair-se das operações matemáticas, existe a possibilidade de efectuar operações avançadas com matrizes específicas 1 Translation Função de Translação: GL. gltranslatef ( float x, float y, float z ) A função recebe como argumentos os valores da translação no x, y e z. O pseudo-código seguinte é ilustrado na Figura 3.4. GL2 gl = drawable. getgl (). getgl2 (); GLUT glut = new GLUT (); // Translacao de y =10 gl. gltranslatef (0f, 10f, 0f); // Desenhar o cubo... glut. glutwirecube (10 f); Figura 3.4: Translation Rotation Função de Rotação: GL. glrotatef ( float angle, float x, float y, float z ) A função recebe como argumentos, o ângulo de rotação. Os valores x, y e z, representam um eixo arbitrário sobre o qual deve ser feita a rotação 2. O pseudo-código seguinte é ilustrado na Figura 3.5. GL2 gl = drawable. getgl (). getgl2 (); GLUT glut = new GLUT (); // Rodar 45 em Torno do vector Vr =[1,1,1] gl. glrotatef (45f, 1f, 1f, 1f); 1 Consultar na referência da API - glloadmatrix* 2 Por exemplo: para obter um eixo perpendicular ao eixo y basta fornecer o vector V y =[0f, 1f, 0f] 18

20 // Desenhar o cubo... glut. glutwirecube (10 f); Figura 3.5: Rotation Scaling Função de Escala: GL. glscalef ( float x, float y, float z ) A função recebe como argumentos os factores de escala em cada um dos eixos x, y e z. O pseudo-código seguinte é ilustrado na Figura 3.6. GL2 gl = drawable. getgl (). getgl2 (); GLUT glut = new GLUT (); // Escalar x =2*x, y =1* x e z =2* z gl. glscalef (2f, 1f, 2f); // Desenhar o cubo... glut. glutwirecube (10 f); Figura 3.6: Scale A Matriz Identidade (Identity Matrix) Ao tentar conseguir o resultado na Figura 3.7, podemos ser tentados a escrever o código: GL2 gl = drawable. getgl (). getgl2 (); GLUT glut = new GLUT (); // Translate y =10 19

21 Figura 3.7: Duas Esferas gl. gltranslatef (0f, 10f, 0f); // Desenhar a primeira esfera glut. glutsolidsphere (1f, 15, 15); // Translate x =10 gl. gltranslatef (10f, 0f, 0f); // Desenhar a segunda esfera glut. glutsolidsphere (1f, 15, 15); No entanto, o resultado final será mais parecido com o da Figura 3.8. Figura 3.8: Duas Esferas (continuação) Isto deve-se ao facto de as transformações no pipeline OpenGL serem acumulativas. O que aconteceu de facto foi uma translação de 10 no eixo-y seguida do desenho da primeira esfera (tudo correcto), depois movemos-nos 10 no eixo-x sem voltar à origem, o que provocou que a esfera final aparecesse com uma translação de [x = 10, y = 10]. Para obter o efeito da Figura 3.7, é preciso repor o sistema de coordenadas original (uma espécie de reset). Isto pode ser obtido pelo carregamento da indentity matrix. O nosso código ficaria então mais parecido com: GL2 gl = drawable. getgl (). getgl2 (); GLUT glut = new GLUT (); // Escolher a Matriz de Transformacoes // MODELVIEW e fazer um reset inicial gl. glmatrixmode ( GL2. GL_MODELVIEW ); gl. glloadidentity (); // Translate y =10 gl. gltranslatef (0f, 10f, 0f); // Desenhar a primeira esfera glut. glutsolidsphere (1f, 15, 15); 20

22 // reset! gl. glloadidentity (); // Translate x =10 gl. gltranslatef (10f, 0f, 0f); // Desenhar a segunda esfera glut. glutsolidsphere (1f, 15, 15); 3.6 Projecções Orthographic Projections A perspectiva ortogonal consiste de um volume com os lados todos iguais (Figura 2.7). Este tipo de projecção é utilizada normalmente em software CAD, onde é necessária uma percepção das dimensões reais dos objectos. No entanto, a sua aproximação à realidade é um pouco vaga (Figura 3.9). (a) Figura 3.9: Ortogonal- Normal/Lado/Frente A função que permite configurar uma projecção ortogonal, tem o seguinte protótipo: GL2. glortho ( double left, double right, double bottom, double top, double near, double far ) Os argumentos representam as distância até à origem do sistema de coordenadas das faces - esquerda (left), direita (right), fundo (bottom), topo (top), a face mais próxima (near) e mais distante (far) do observador (Figura 3.10). Figura 3.10: Projecção Ortogonal O volume de desenho (viweing volume), corresponde ao volume compreendido entre os 6 planos do cubo. Perspective Projections Ao contrário da perspectiva ortogonal, numa projecção de perspectiva, os objectos mais distantes são encolhidos. O viewing volume é agora uma espécie de pirâmide com a parte superior cortada - denominada frustrum (Figura 3.11). 21

23 Figura 3.11: Frustrum A definição deste frustrum pode ser feita com recurso à função glperspective 1 : GL. glperspective ( double fovy, fouble aspect, double znear, doule zfar ); Os parâmetros da função são o campo de visão (field of view) expresso em graus (ângulo vertical), o aspect ratio da altura e largura e as distâncias ao plano mais próximo e mais afastado do volume de visualização (viewing volume), como mostra a Figura Figura 3.12: Frustrum utilizando glperspective Podemos comparar a diferença em relação à perspectiva ortogonal, analisando a Figura (a) Figura 3.13: Perspectiva - Normal/Lado/Frente 3.7 Câmaras e Actores Agora que temos o nosso cenário configurado, seria interessante conseguirmos movimentar-nos, nós os observadores. O conceito de câmara ou actor não existe realmente no OpenGL, o nome serve apenas como metáfora para facilitar a compreensão do conceito. A forma de mimetizarmos esta funcionalidade passa pela utilização da função gllookat: GLU. glulookat ( float eyex, float eyey, float eyez, float atx, float aty, float atz, float upx, float upy, float upz ); 1 Existe a função glfrustrum, no entanto a função glperspective é mais intuitiva 22

24 Figura 3.14: gllookat Os argumentos desta função são, a posição do observador - Eye(x, y, z), o ponto para o qual o observador está a olhar At(x, y, z) e o vector que determina qual a direcção vertical do observador V UP (x, y, z) (Figura 3.14). 23

25 Capítulo 4 Primitivas Geométricas e Buffers Utilizando ferramentas ou bibliotecas de desenho gráfico convencionais, o elemento mais básico é o pixel. Basicamente colocamos um determinado pixel na tela com uma determinada cor e uma posição específica. Desenhar em OpenGL é um pouco diferente, não desenhamos numa determinada específica no ecrã, mas sim em coordenadas no nosso viewing volume. A forma como a nossa cena aparece no ecrã está a cargo do OpenGL. As secções seguintes descrevem como são desenhadas as varias primitivas geométricas com recurso à API OpenGL. 4.1 O ponto 3D - (Vertex) A função utilizada para desenhar um ponto 3D na nossa cena é a função glvertex. O ponto desenhado depende do número de argumentos e tipo utilizados na função. Figura 4.1: Ponto P (50,50,50) Por exemplo, para obter o ponto na Figura 4.1, podemos utilizar: gl. glvertex3f (50f, 50f, 0f); Ou ainda: gl. glvertex2f (50f, 50f); Podemos ainda especificar o factor de escala w (por omissão 1f) utilizando o código: gl. glvertex4f (50f, 50f, 0f, 1f); 4.2 Primitivas Um vertex por si só no espaço, não tem grande significado. Um ponto pode representar a intersecção de duas linhas ou curvas ou então o canto de um polígono ou sólido. 24

26 A forma como um conjunto de pontos é interpretado no nosso espaço 3D é chamada de primitiva. O OpenGL tem 10 tipos de primitivas. Para desenhar com uma determinada primitiva, utilizamos a função glbegin para iniciar, desenhamos os nossos pontos e terminamos utilizando o glend para terminar a utilização da primitiva. Para desenhar vários tipos de primitivas, teremos que utilizar vários blocos glbegin/glend, por exemplo: gl. glbegin ( GL_POINTS ); gl. glvertex3f (0.0f, 0.0f, 0.0 f); gl. glvertex3f (50.0f, 50.0f, 50.0 f); gl. glend (); Pontos: GL POINTS Esta primitiva é a mais simples de todas: pontos. Os vértices desenhados dentro de um bloco GL POINTS, aparecem como pontos. Figura 4.2: Desenho utilizando a primitiva GL POINTS O código utilizado para obter a Figura 4.2 será: float GL_PI = f; // Comecar a Desenhar Pontos gl. glbegin ( GL2. GL_POINTS ); float angle, x, y, z = f; for ( angle =0f; angle <=(2 f* GL_PI )*3 f; angle +=0.1 f) { x = 50f * ( float ) Math. sin ( angle ); y = 50f * ( float ) Math. cos ( angle ); gl. glvertex3f (x, y, z); z += 0.5 f; // Terminar Pontos gl. glend (); O exemplo acima faz variar o x, y de forma a descrever um circulo no plano x, y, onde x = cos(angle) e y = sin(angle). Á medida que o angle varia, vamos aumentando o z por forma a desenhar uma espiral (Figura 4.3). Tamanho de um Ponto O tamanho de um ponto é 1pixel, por omissão. Para alterar o tamanho do ponto, podemos utilizar a função glpontsize(float psize). Dependendo da plataforma, os valores mínimo e máximo possível para o tamanho do ponto podem variar. Para obter os valores possíveis para o mínimo, máximo e step 1, podemos utilizar: float [] sizes = new float [2]; gl. glgetfloatv ( GL2. GL_POINT_SIZE_RANGE, sizes, 0); 1 A mínima diferença possível entre tamanhos consecutivos 25

27 Figura 4.3: Explicação da espiral de pontos float [] step = new float [1]; gl. glgetfloatv ( GL2. GL_ POINT_ SIZE_ GRANULARITY, step, 0); O array size (float[] de tamanho 2) irá conter os valores mínimo (P S min = size[0]) e máximo (P S max = size[1]) possíveis para o tamanho de um ponto, o array step (float[] de tamanho 1) irá conter o valor da diferença mínima (P S step =step[0]) possível entre tamanhos do ponto. Os valor passado à função glpointsize, deverá estar compreendido entre P S min e P S max, sendo a diferença mínima entre eles de P S step. Assim ao utilizar o código em baixo em conjunto com os arrays do exemplo anterior, obtemos a Figura 4.4. float GL_PI = f; float angle, x, y, z = f; float psize = sizes [0]; for ( angle =0f; angle <=(2 f* GL_PI )*3 f; angle +=0.1 f) { x = 50f * ( float ) Math. sin ( angle ); y = 50f * ( float ) Math. cos ( angle ); gl. glpointsize ( psize ); psize += step [0]; // Comecar Pontos gl. glbegin ( GL2. GL_POINTS ); gl. glvertex3f (x, y, z); // Terminar Pontos gl. glend (); z += 0.5 f; A função glpointsize foi invocada fora do bloco glbegin/glend. Algumas funções não podem ser invocadas dentro destes blocos. O tamanho do ponto afecta todos os pontos desenhados para a frente, mas antes do glbegin(gl POINTS), o desenho de pontos ainda não foi iniciado, daí ser invocado fora. De modo geral no OpenGL, se os valores são especificados fora do intervalo possível, eles são truncados ao referido intervalo. Assim para valores acima do permitido, o valor máximo é forçado e para valores abaixo do permitido, o valor mínimo é forçado Linhas: GL LINES Utilizando a primitiva GL LINES, entre dois vértices é desenhada uma linha. gl. glbegin ( GL_LINES ); gl. glvertex3f (0.0f, 0.0f, 0.0 f); 26

28 Figura 4.4: Pontos com vários tamanhos gl. glvertex3f (50.0f, 50.0f, 50.0 f); gl. glend (); Porque as linhas são só desenhadas entre 2 pontos, ao utilizar um número ímpar de pontos, o último é ignorado. O código em baixo ilustra o desenho com o uso da primitiva GL LINES: float z = 0.0 f, angle, x, y; // Comecar Linhas gl. glbegin ( GL2. GL_LINES ); for ( angle = 0.0 f; angle <= GL_PI ; angle += ( GL_PI /20.0 f)) { // Primeira metade do circulo x = 50f * ( float ) Math. sin ( angle ); y = 50f * ( float ) Math. cos ( angle ); gl. glvertex3f (x, y, z); // Segunda metade do circulo angle + π x = 50f * ( float ) Math. sin ( angle + GL_PI ); y = 50f * ( float ) Math. cos ( angle + GL_PI ); gl. glvertex3f (x, y, z); // Terminar Linhas gl. glend (); O resultado do código em cima é o da Figura Tiras de Linha: GL LINE STRIP Esta primitiva permite definir quais os vértices pelos quais a linha deve passar. gl. glbegin ( GL_LINE_STRIP ); gl. glvertex3f (0f, 0f, 0f); // V 0 gl. glvertex3f (50f, 50f, 0f); // V 1 gl. glvertex3f (50f, 100f, 0f); // V 2 gl. glend (); O código em cima desenharia no plano x, y os pontos da Figura Loops de Linha: GL LINE LOOP Da mesma forma que o GL LINE STRIP, podemos utilizar o GL LINE LOOP para definir os pontos pelos quais uma linha passa, mas desta vez, uma última linha é desenhada entre o último vértice e o primeiro. 27

29 Figura 4.5: Desenho com GL LINES Figura 4.6: Tiras de Linhas: GL LINE STRIP Figura 4.7: Loops de Linhas: GL LINE LOOP 28

30 A Figura 4.7 mostra os mesmos vértices da Figura 4.6 desenhados com a primitiva GL LINE LOOP. Exemplo: Aproximação a Curvas com recurso a Tiras de Linha Utilizando o exemplo da Figura 4.2, onde desenhamos uma espiral de pontos e substituindo a primitiva GL POINTS pela primitiva GL LINE STRIP, podemos fazer uma aproximação a uma espiral. Ao diminuir o espaço entre os pontos podemos tornar a sensação de curva ainda mais real. float GL_PI = f; // Comecar a Tiras de Linha gl. glbegin ( GL2. GL_LINE_STRIP ); float angle, x, y, z = f; for ( angle =0f; angle <=(2 f* GL_PI )*3 f; angle +=0.1 f) { x = 50f * ( float ) Math. sin ( angle ); y = 50f * ( float ) Math. cos ( angle ); gl. glvertex3f (x, y, z); z += 0.5 f; // Terminar Tiras de Linha gl. glend (); Ao utilizar o código em cima, obtemos o resultado na Figura 4.8. Figura 4.8: Espiral com Tiras de Linha Largura de uma Linha Da mesma forma que podemos definir o tamanho de um ponto, podemos definir o tamanho de uma linha pela utilização da função gllinewidth. Da mesma forma o argumento tem um valor mínimo, máximo e um step. float [] widths = new float [2]; gl. glgetfloatv ( GL2. GL_LINE_WIDTH_RANGE, widths, 0); float [] step = new float [1]; gl. glgetfloatv ( GL2. GL_ LINE_ WIDTH_ GRANULARITY, step, 0); O array widths (float[] de tamanho 2) irá conter os valores mínimo (LW min = widths[0]) e máximo (LW max = widths[1]) possíveis para a largura de uma linha, o array step (float[] de tamanho 1) irá conter o valor da diferença mínima (LW step =step[0]) possível entre larguras de linhas. Os valor passado à função gllinewidth, deverá estar compreendido entre LW min e LW max, sendo a diferença mínima entre eles de LW step. 29

31 float y, curwidth = widths [0]; gl. glcolor3f (1f, 1f, 1f); for (y= -90f; y <90 f; y +=20 f) { // Alterar a Largura gl. gllinewidth ( curwidth ); // Comecar Tiras gl. glbegin ( GL2. GL_LINE_STRIP ); gl. glvertex2f ( -80f, y); gl. glvertex2f (80f, y); // Terminar Tiras gl. glend (); curwidth += 1f; Com o código em cima, obtemos o desenho na Figura 4.9. Figura 4.9: Linhas de Várias Larguras Padrões de Linha:GL LINE STIPPLE O desenho de linhas baseadas em padrões é conseguindo activando o stippling, o que pode ser feito utilizando: gl. glenable ( GL2. GL_LINE_STIPPLE ); O padrão da linha é estabelecido com a ajuda da função: gl. gllinestipple ( int factor, short pattern ); O padrão consiste de um valor de 16 bits (short) que representa cada segmento da linha. Cada bit representa um elemento nesse segmento de linha que poderá estar on ou off. Por omissão cada bit representa um pixel no nosso desenho. O valor de factor define o número de bits que cada pixel representa. O bit menos significativo (bit 0 - lado direito) é utilizado para o inicio da linha como mostra Figura float y; short pattern = 0 x5555 ; int factor = 1; gl. glcolor3f (1f, 1f, 1f); for (y= -90f; y <90 f; y +=20 f) { // Alterar o Stipple 30

32 Figura 4.10: Padrão Stipple gl. gllinestipple ( factor ++, pattern ); // Comecar Linhas gl. glbegin ( GL2. GL_LINE_STRIP ); gl. glvertex2f ( -80f, y); gl. glvertex2f (80f, y); // Terminar Linhas gl. glend (); O pattern 0x5555 é um valor hexadecimal, que em binário representa , o que resultará numa linha dotted. À medida que o ciclo avança vamos aumentando o factor, pelo que a linha passa de dotted para dashed de forma progressiva, como mostra a Figura Figura 4.11: Desenho com recurso a stippling Triângulos: GL TRIANGLES Até aqui as formas criadas com recurso às primitivas de pontos e linhas, não contém qualquer preenchimento. Para desenhar superfícies sólidas com preenchimento é necessário utilizar polígonos. Um polígono é uma forma fechada que pode estar ou não preenchida com a cor actual de preenchimento. Em OpenGL, todo o desenho de sólidos assenta na composição baseada em polígonos. O polígono mais simples possível é o triângulo e pode ser desenhado com recurso à primitiva GL TRIANGLES. gl. glbegin ( GL2. GL_TRIANGLES ); 31

33 gl. glvertex2f (0f, 0f); // V 0 gl. glvertex2f (25f, 25f); // V 1 gl. glvertex2f (50f, 0f); // V 2 gl. glvertex2f ( -50f, 0f); // V 3 gl. glvertex2f ( -75f, 50f); // V 4 gl. glvertex2f ( -25f, 0f); // V 5 gl. glend (); O código acima desenha dois triângulos preenchidos com a cor de preenchimento actual (definida por glcolor) no plano x, y (Figura 4.12). Figura 4.12: Desenho de Triângulos Winding A ordem pela qual os vértices são desenhados, define o lado para que está virado o polígono por eles definido. Assim o primeiro triângulo (V 0, V 1, V 2 ) é desenhado no sentido dos ponteiros do relógio (clockwise) está de costas para o observador, enquanto que o segundo triângulo (V 3, V 4, V 5 ) foi desenhado no sentido inverso (counterclockwise), está de frente para o observador (Figura 4.13). Figura 4.13: Winding O conceito de winding é importante quando estamos a preencher um determinado polígono com características diferentes à frente e atrás. Para alterar o comportamento do winding podemos forçar o caminho clockwise a representar a face de um polígono activando a flag GL CW: gl. glenable ( GL2. GL_CW ); Para restaurar o comportamento por omissão activamos a flag GL CCW Tiras de Triângulos:GL TRIANGLE STRIP O desenho da maioria das superfícies consiste num conjunto de triângulos. O desenho dessas superfícies pode ser facilitado pela utilização da primitiva de desenho de triângulos GL TRIANGLE STRIP. Os triângulos são desenhados entre os vértices à medida que eles são especificados (Figura 4.14). 32

34 Figura 4.14: Tiras de Triângulos No caso do GL TRIANGLE STRIP, o winding é forçado para counterclockwise independentemente da ordem de desenho. Uma vantagem evidente deste método de desenho é o facto de, depois dos três primeiros vértices, o desenho de triângulos adicionais só precisa de mais um vértice por triângulo Triangle Fans:GL TRIANGLE FANS Nesta primitiva, os triângulos são desenhados em volta de um ponto central, definido pelo primeiro vértice a ser desenhado (V 0 ). Depois dos primeiros três vértices definirem o primeiro triângulo, todos os restantes são definidos com apenas um vértice (Figura 4.15). Figura 4.15: Triangle Fans 4.3 Outras Primitivas A utilização de triângulos na construção de objectos em OpenGL é preferida pelo facto da maior parte do hardware acelerar o seu desenho. No entanto a utilização de outras formas que não o triângulo poderá ser pertinente Quadriláteros: GL QUADS A primitiva GL QUADS permite desenhar um polígono quadrilátero com recurso a quatro vértices. Os vértices teriam que ser complanares (Figura 4.16). Figura 4.16: Quadriláteros 33

35 4.3.2 Tiras de Quadrados:GL QUAD STRIP Da mesma forma que a primitiva GL TRIANGLE SRTIP, a primitiva GL QUAD STRIP permite desenhar uma tira de quadriláteros pela adição de vértices aos quatro primeiros (Figura 4.17). Figura 4.17: Tiras de Quadriláteros Polígonos: GL POLYGON Esta primitiva permite o desenho de polígonos com um número variado de lados. No entanto, a restrição dos vértices serem complanares mantém-se (Figura 4.18). Figura 4.18: Desenho de Polígonos Esta restrição pode ser evitada pela utilização da primitiva GL TRIANGLE FAN em lugar da utilização da primitiva GL POLYGON Preenchimento de Polígonos As duas formas mais utilizadas para preenchimento de polígonos são, a utilização de cores sólidas ou a aplicação de texturas. No entanto, da mesma forma que utilizámos os padrões de preenchimento de linhas, podemos utilizar padrões de preenchimento (stippling) de polígonos. O padrão é agora definido por uma matriz on/off de bits (Figura 4.19). Para construir a máscara que vai ser utilizada para fazer o stippling utilizamos um array de 32 4 bytes 1. Em vez de um array bidimensional é utilizado um array simples. O padrão pode ser aplicado activando o stippling de polígonos e utilizando um array do tipo descrito em cima: byte [] pattern = { 0x00, 0x00, 0x00, 0 x x00, 0x00, 0x10, 0 x00 ; gl. glenable ( GL2. GL_POLYGON_STIPPLE ); gl. glpolygonstipple ( pattern ); Mais uma vez o array é definido ao contrário, sendo o bit menos significativo, o primeiro bit da imagem, ou seja, a primeira linha corresponde à última linha da imagem. 1 1byte = 8bit = 32 4byte = 32 32bit 34

36 Figura 4.19: Padrão de Preenchimento de Polígonos Figura 4.20: Exemplo de Stippling de Polígonos 35

37 4.3.5 Regras na Criação de Polígonos 1. A primeira regra a ter em mente na construção de polígonos é que, todos os seus vértices devem residir no mesmo plano. Um polígono não pode dobrar-se no espaço (Figura 4.21). Figura 4.21: Polígonos Planos/Não-planos Esta primeira regra pende a favor da utilização de triângulos na definição dos nossos polígonos, uma vez que matematicamente um plano é definido por três pontos. 2. Outra regra diz que os segmentos do polígono não devem intersectar-se e o polígono deve ser convexo. O polígono é convexo quando qualquer linha que o atravesse sai e entra apenas uma vez no polígono (Figura 4.22). Figura 4.22: Polígonos válidos e inválidos Sub-divisão de Arestas Apesar de o OpenGL só conseguir desenhar polígonos convexos, existem situações em que polígonos não-convexos fazem sentido, por exemplo ao desenhar uma estrela. A primeira estrela da Figura 4.23 não é convexa, mas ao dividirmos o polígono em vários triângulos obtemos uma figura convexa válida. Figura 4.23: Polígonos não Convexos A fim de evitar que as linhas (edges) no interior da segunda estrela sejam visíveis podemos a edge flag. Esta flag é activa/inactiva pela função gledgeflag(boolean enable). Esta função diz ao OpenGL se os segmentos seguintes são considerados arestas do polígono. 4.4 Buffers O OpenGL não desenha realmente as primitivas no ecrã, utiliza antes um buffer buffer de cor, inicialmente invisível, que posteriormente é colocado no ecrã. Chamamos aos dois buffers de cor, o front buffer (o que se encontra actualmente no ecrã) e o back buffer (o que está a ser desenhado). 36

38 No JOGL a configuração do display é feita alterando as capacidades na classe GLDrawable 1. As capacidades actuais do display podem ser consultadas utilizando: public class MyGl implements GLEventListener public void init ( GLAutoDrawable drawable ) { GLCapabilities cap = drawable. getchosenglcapabilities (); boolean db = cap. getdoublebuffered (); O double buffering encontra-se activo por omissão. Pode no entanto ser activado ou desactivado utilizando o código: GLCapabilities cap = drawable. getchosenglcapabilities (); // Desactivar o double buffer cap. setdoublebuffered ( false ); A troca de buffers pode ser conseguida utilizando a função GLDrawable.swapBuffers() 2. Utilizando Buffer Targets É possível desenhar directamente no front buffer dizendo ao OpenGL qual o buffer de destino (target) para as primitivas que estamos actualmente a desenhar, utilizando: gl. gldrawbuffer ( int mode ); Especificando GL2.GL FRONT, desenhamos directamente no front buffer, utilizando GL2.GL BACK, remetemos o desenho para o back buffer. Outra forma de desenhar directamente no front buffer passa pela desactivação do double buffering. Ao desenhar com recurso a um único buffer é aconselhável a utilização da função glflush ou glfinish para forçar o pipeline a processar a lista de comandos no buffer Buffer de Profundidade O OpenGL suporta mais buffers para além dos buffers de cor. Um deles é o depth buffer que em vez de armazenar valores de cor, armazena valores de profundidade. O teste de profundidade faz corresponder a cada elemento de cor no color buffer, um valor de profundidade no depth buffer. Para utilizar o buffer de profundidade usamos o código: gl. glenable ( GL2. GL_DEPTH_TEST ); Para desactivar temporariamente o teste de profundidade sem descartar os valores actualmente no buffer, podemos utilizar: gl. gldepthmask ( false ); Utilizando true em vez de false, podemos reactivar o teste de profundidade Scissors Afim de optimizar recursos, pode ser pertinente desenhar apenas uma porção do ecrã. O OpenGL permite definir a zona rectangular do ecrã que é renderizada. O rectângulo pode ser definido activando o scissor test com recurso à função glenable(gl2.gl SCISSOR TEST) e definindo a o seu rectângulo, utilizando a função: GL2. glscissor ( int x, int y, int width, int height ); Os valores x e y especificam o canto inferior direito do rectângulo. Os valores width e height definem a largura e altura do rectângulo. 1 No caso da interface GLEventListener, os métodos recebem uma instância de um GLAutoDrawable que é do tipo GLDrawable por herança 2 Quando o double buffering está activo, isto é feito de forma automática 37

39 GL2 gl = drawable. getgl (). getgl2 (); // Activar o Scissor Test gl. glenable ( GL2. GL_SCISSOR_TEST ); gl. glclearcolor (1f, 0f, 0f, 0f); gl. glscissor (50, 50, 200, 200)); gl. glclear ( GL2. GL_COLOR_BUFFER_BIT ); gl. glclearcolor (1f, 1f, 0f, 0f); gl. glscissor (120, 120, 60, 60); gl. glclear ( GL2. GL_COLOR_BUFFER_BIT ); // Desactivar o Scissor Test gl. gldisable ( GL2. GL_SCISSOR_TEST ); gl. glflush (); O código em cima, define uma scissor box inicial com o canto inferior direito [x, y] = [50, 50] e com a largura e altura de 200. Seguidamente a cor de fundo é limpa de vermelho. Uma scissor box mais pequena é então definida e pintada de amarelo (Figura 4.24). Figura 4.24: Scissor Test 38

40 Capítulo 5 Cores, Materiais e Luzes 5.1 Cor A cor é simplesmente um comprimento de onda da luz visível aos nossos olhos. A luz é uma onda que viaja pelo espaço como uma onda num lago, no entanto é modelada, na física, como uma partícula, como uma gota de água que cai no chão. A luz vista como uma onda A luz visível ao nosso olho é realmente uma mistura de diferentes tipos de luz. O que caracteriza cada tipo de luz, é o seu comprimento de onda (Figura 5.1). Figura 5.1: Medida do Comprimento de Onda O espectro visível ao olho humano varia desde os 390 manómetros (luz violeta) e os 720 nanómetros (luz vermelha) (Figura 5.2). Os termos ultra-violeta e infra-vermelho referem-se ao espectro fora do espectro visível. Figura 5.2: Espectro de Luz Visível 39

41 A luz vista como uma partícula A cor que vemos nos objectos é realmente a soma de todas os comprimentos de onda de luz que o objecto consegue reflectir. Por exemplo, o branco é a soma de todos os comprimentos de onda do espectro, enquanto que o preto é a ausência de luz (pelo menos da luz visível). Dependendo do tipo e quantidade de átomos de uma superfície, esta reflecte um determinado comprimento de onda dos fotões de luz que a bombardeiam e absorve os restantes. Cada um destes fotões tem também um comprimento de onda associado (dai a dualidade onda/partícula), o somatório dos comprimentos de onda das partículas reflectidas confere a cor visível aos nossos olhos (Figura 5.3). Figura 5.3: Partículas (fotões) reflectidos dos materiais A retina do olho humano é excitada pelo conjunto de fotões reflectidos pelas superfícies e o cérebro interpreta-os como luz. As células fotossensíveis da nossa retina são sensíveis a três tipos de comprimento de onda - o vermelho, o verde e o azul. A mistura de quantidades diferentes das três componentes resulta na cor interpretada pelo nosso cérebro (Figura 5.4). Figura 5.4: Interpretação da cor pelo olho humano Computador Gerador de Fotões A geração de cores num computador utilizando várias intensidade de Red, Green e Blue (RGB), faz agora algum sentido. Os nossos monitores são compostos de pequenos elementos contendo as três componentes de cor (RGB). Ao mudar as intensidades das várias cores, obtemos a palete de cores visível (Figura 5.5) Modos de Display Hoje em dia, graças aos fabricantes dos sistemas operativos, o desenho nos dispositivos gráficos é feito com recurso a uma camada de virtualização, chamada de driver gráfico, que permite, por intermédio de uma API (tal como o OpenGL), desenhar no ecrã sem ter que conhecer os pormenores do hardware. No entanto, devemos ter presentes algumas palavras chaves na utilização destas APIs. 40

42 Figura 5.5: Computador Gerador de Fotões Resolução As resoluções mais usadas nos monitores actuais varia entre os 640x480 e os 1920x1080 (full hd). Devemos ter sempre em conta o tamanho da janela e ajustar o nosso clipping volume e viewport de forma a manter a imagem que o utilizador visualiza coerente. É de esperar que à medida que a janela é aumentada, a resolução dos objectos será maior. Profundidade de Cor Da mesma forma que mais resolução significa uma imagem mais detalhada, o aumento nos níveis de cor disponíveis (color depth) deverá aumentar a claridade da nossa imagem. Ao utilizar a API OpenGL devemos ter em mente três profundidades de cor: 4-bit: 16 níveis de cor 8-bit: 256 níveis de cor 24-bit: A cor de cada pixel é definida com recurso a 3 componentes de 8-bit ( = 25), o que proporciona mais de 16 milhões de cores A maioria do hardware gráfico actual tem aceleração para os 24-bit de profundidade de cor. Os 16-bit e 32-bit de profundidade foram em tempos utilizados como uma forma de optimizar o desempenho, uma vez que permitem o alinhamento mais eficiente em memória (endereço de 32-bit). No entanto, 32-bit não significa um aumento do número de cores, mas sim um desperdício de 8-bit de memória. 41

43 5.2 Utilização de Cores no OpenGL Podemos representar todas as cores possíveis com a utilização de um cubo, mapeando as componentes Red, Green e Blue nos eixos x, y e z respectivamente (Figura 5.6). Figura 5.6: RGB Colorspace Na origem ([x, y, z] = [0, 0, 0]) encontra-se o preto, no ponto [x, y, z] = [255, 255, 255] encontra-se o branco e nos extremos do cubo em cada um dos eixos encontram-se as cores vermelho (x), verde (y) e azul (z). Alterando a Cor utilizada para desenhar A função utilizada para alterar a cor utilizada para desenho é a função: GL2. glcolor <x><t >( red, green, blue [, alpha ]); Na nome da função, o <x> representa o número de argumentos. No caso de ser 3, a cor será definida com as três componentes RGB, no caso de ser 4, é especificado o valor adicional alpha que define o nível de transparência. O <t> no nome na função especifica o tipo de argumento, que poderá ser b, d, f, i, s, ub, ui, or us, que representam respectivamente, byte, double, float, integer, short, unsigned byte, unsigned integer, and unsigned short. A grande maioria dos programas em OpenGL utilizam o glcolor3f que permite especificar a intensidade de cor entre 0f e 1f (1f = intensidade máxima de cor). No entanto é possível representar, por uma questão de conveniência, o valor da cor entre 0 e 255, utilizando por exemplo: gl. glcolor3ub (0, 255, 128); No entanto, o seu uso é desaconselhado, uma vez que, a tendência no futuro aponta para adição de mais níveis de intensidade (> 255). O OpenGL na realidade representa os níveis de cor internamente utilizando um float, pelo que forçar a utilização de glcolor3ub, implica um passo adicional para a conversão Shading Figura 5.7: Shading de uma linha 42

44 Ao utilizar a função glcolor estamos a dizer ao OpenGL que cor deve ser utilizada para os vértices desenhados a seguir. No entanto, todas as primitivas para além do ponto contém mais do que um vértice. A forma como são desenhados os pontos intermédios dos vértices, nessas primitivas, por exemplo para uma linha, depende do modelo de shading escolhido. A Figura 5.7 mostra como as cores são seleccionadas no caminho entre dois vértices de uma linha, onde o primeiro é preto e o segundo é branco. Pela análise da figura, podemos concluir que a linha aparecerá como um gradiente de preto para branco. O shading de polígonos é um pouco mais complexo. Um triângulo pode ser também desenhado dentro do cubo RGB Colorspace, como mostra a Figura 5.8(a). (a) Cores dos vértices nos eixos de cor (b) Triângulo RGB A imagem 5.8(b), pode ser obtida com o código: GL2 gl = drawable. getgl (). getgl2 ();... // Utilizar smooth shading gl. glshademodel ( GL2. GL_SMOOTH ); gl. glbegin ( GL2. GL_TRIANGLE_STRIP ); // Vermelho gl. glcolor3f (1f, 0f, 0f); gl. glvertex3f (40f, 0f, 0f); // Verde gl. glcolor3f (0f, 1f, 0f); gl. glvertex3f (0f, 60f, 0f); // Azul gl. glcolor3f (0f, 0f, 1f); gl. glvertex3f ( -40f, 0f, 0f); gl. glend (); Figura 5.8: Triângulo no RGB Colorspace O modelo por omissão de shading no OpenGL é o GL2.GL SMOOTH, no qual a transição entre as cores é a descrita em cima. O outro modelo é o GL2.GL FLAT, no qual a cor da superfície utilizada corresponde à cor do ultimo vértice, com a excepção das primitivas GL POLYGON, onde a cor utilizada é do primeiro vértice. Para alterar o shading model utilizado pelo OpenGL, podemos utilizar a função: gl. glshademodel ( int model ); Utilizando como argumento uma das constantes GL2.GL SMOOTH ou GL2.GL FLAT. 43

45 5.3 Cores no Mundo Real O shading dos objectos no mundo real não se resume apenas aos valores RGB das cores. Ao preenchermos superfícies com cores, os nossos modelos estão longe de parecer reais (Figura 5.9). Figura 5.9: Objecto preenchido com cores diferentes em cada polígono O OpenGL simula de forma bastante aproximada as condições de luz num ambiente real. Com a excepção dos objectos que emitem luz própria, todos eles são afectados por três tipos de luz: ambiente, difusa e especular Luz Ambiente A luz ambiente não tem direccionalidade. As superfícies dos objectos de uma cena são afectadas de forma igual e uniforme (Figura 5.10). O resultado de uma cena com uma luz ambiente é semelhante aos exemplos ilustrados até agora onde a cor é uniforme. Figura 5.10: Objecto iluminado com luz ambiente Luz Difusa A luz difusa provém de uma direcção específica mas é reflectida de maneira uniforme pelas superfícies em vários ângulos (Figura 5.11). No entanto, as superfícies iluminadas directamente, são mais claras que as ilmunidadas com um determinado ângulo. Um bom exemplo de luz difusa é uma lâmpada fluorescente. Figura 5.11: Objecto iluminado com Luz Difusa 44

46 5.3.3 Luz Especular A luz especular vem de uma direcção em especifico, é reflectida de maneira uniforme, mas o feixe da sua reflexão continua a ser direccional (Figura 5.12). Os objectos afectados por luz especular costumam mostrar um ponto mais iluminado, onde a luz incide com mais intensidade. Figura 5.12: Objecto iluminado com Luz Especular Luz de Modo Geral Nenhuma cena é composta de um único tipo de luz, é antes composta pelo conjunto das vaŕias componentes com várias intensidades. A titulo de exemplo, imaginemos um feixe de laser vermelho num quarto escuro. O feixe poderá ser comparado com a luz especular, as partículas de pó que reflectem parte da luz do laser podem ser consideradas luz difusa e o matizado vermelho nas paredes do quarto pode ser comparado com a luz ambiente. Da mesma forma que a cor, os vários tipos de luz têm um valor RGBA associado 1. Assim por exemplo para o laser vermelho poderíamos ter os valores na Tabela 5.1. Red Green Blue Alpha Specular Diffuse Ambient Tabela 5.1: Distribuição de Luz e Cor de um Laser Vermelho Pela interpretação da tabela, podemos concluir que o laser vermelho tem uma forte componente especular, uma pequena componente difusa e pouquíssima componente de luz ambiente. O mais certo é que, a presença de partículas, gere uma componente difusa de luz, induzindo luz ambiente no compartimento. As componentes difusa e ambiente são muito semelhantes na natureza e são normalmente combinadas. 5.4 Materiais no Mundo Real A forma como os materiais aparecem no mundo real depende dum conjunto de factores, no entanto, os mais determinantes tem a ver com a sua cor, e as condições de iluminação que o rodeiam. Assim, por exemplo, uma bola azul reflecte a maior parte dos comprimentos de onda azuis e absorve grande parte dos outros. Na maioria dos cenários, a luz é branca, no entanto mudando a luz para amarelo, por exemplo, a nossa bola teria uma cor escura (ou mesmo preto) uma vez que absorve tudo que não seja azul. Propriedades dos Materiais Quando utilizamos luzes, não definimos o material de um determinado polígono só pela cor, dizemos antes, qual a cor da luz que eles reflectem. Os materiais podem reflectir luz especular de uma determinada cor e absorver toda a luz difusa da mesma cor, ou ao contrário. Outra propriedade que é definida nos materiais, é a sua capacidade de gerar luz própria. Adição de Luz aos Materiais Não existe nenhuma regra (como a do RGB Colorspace) para ajudar a definir as propriedades ideais de luzes e materiais. Normalmente os resultados são conseguidos com alguma prática e análise. 1 Para efeitos de luz o alpha é ignorado 45

47 Ao desenhar objectos, o OpenGL decide qual a cor para cada pixel. Cada vértice das nossas primitivas tem um valor RGB diferente baseado no efeito conjunto das 3 componentes de luz ambiente, difusa e especular multiplicado pela reflectividade ambiente, difusa e especular do material. Calculo do Efeito das luzes O cálculo do RGB das três componentes de luz é feito de forma similar. No entanto, a direccionalidade das luzes difusa e especular depende do ângulo de incidência da luz. O cálculo do RGB obtido a partir da incidência da luz (ambiente neste caso) com o RGB (0.5, 0.5, 0.5) numa superfície com propriedades reflectivas da luz ambiente (0.5, 1.0, 0.5) pode ser calculado da seguinte forma; Ou seja, RGB reflected = RGB light RGB material RGB reflected = (0.5, 0.5, 0.5) (0.5, 1.0, 0.5) = (0.25, 0.5, 0.25) Figura 5.13: Compontente de luz ambiente de um Objecto 5.5 Adição de Luzes ao Cenário A fim de consolidar os conceitos teóricos nas secções anteriores, e antes de avançarmos com mais conceitos, é pertinente contextualizá-los no OpenGL. Activação a Luz Para utilizar a luz no OpenGL activamos a flag GL LIGHTING: gl. glenable ( GL2. GL_LIGHTING ); gl. glcolor3f (0.75f, 0.75f, 0.75 f); gl. glbegin ( GL2. GL_TRIANGLES ); gl. glvertex3f (60f, -40, 0f); gl. glvertex3f ( -60f, -40f, 0f); gl. glvertex3f (0f, 40f, 0f); gl. glend (); Ao activar a flag GL LIGHTING, o OpenGL determina a cor de cada vértice com base nos parâmetros dos materiais. Como ainda não foram definidos quaisquer parâmetros dos materiais, os objectos no nosso cenário aparecem escuros e sem qualquer luz (Figura 5.14). Configuração do Modelo de Lighting O primeiro passo depois de activar o cálculo de luzes é configurar o modelo de lighting. As três componentes de luz que afectam o nosso modelo de lighting são definidos com recurso à função: gllightmodelfv ( int mode, float [] params, int offset ); 46

48 Figura 5.14: Polígono sem parâmetros de materiais definidos O argumento mode permite-nos seleccionar qual a(s) componente(s) que estamos a configurar. O segundo argumento é um array contendo os valores RGBA da luz 1. Para definir a componente de luz ambiente utilizamos a variável GL LIGHT MODEL AMBIENT, como mostra o exemplo: gl. glenable ( GL2. GL_LIGHTING ); float [] ambientlight = new float [] {1f, 1f, 1f, 1f; gl. gllightmodelfv ( GL2. GL_ LIGHT_ MODEL_ AMBIENT, ambientlight, 0); Configuração das Propriedades dos Materiais A configuração das propriedades dos materiais é feita antes de os desenhar, definindo as cores que estes reflectem para cada componente. Isto pode ser feito com recurso à função: glmaterialfv ( int face, int pname, float [] params, int offset ) O parâmetro face define qual a face que toma os valores que estamos a definir: GL FRONT: Frente GL BACK: Trás GL FRONT AND BACK: Ambas as faces O parâmetro pname define qual a propriedade que estamos a configurar e pode tomar os valores: GL AMBIENT, GL DIFFUSE, GL SPECULAR: Luz ambiente, difusa e especular GL AMBIENT AND DIFFUSE: Componentes ambiente e difusa (tomarão os mesmos valores). GL EMISSION: Luz própria do objecto. O seguinte exemplo mostra uma possível utilização da função glmaterial: float gray [] = { 0.75f, 0.75f, 0.75f, 1.0 f ; gl. glmaterialfv ( GL2. GL_FRONT, GL2. GL_AMBIENT_AND_DIFFUSE, gray, 0); Na maior parte das vezes, a luz ambiente e difusa tomam valores semelhantes, para tal a flag GL AMBIENT AND DIFFUSE é utilizada. A nossa imagem terá agora o aspecto da Figura A segunda forma de atribuir propriedades aos materiais é activando o color tracking. Com o color tracking, dizemos ao OpenGL para utilizar as cores definidas com recurso a glcolor. Para activar o color tracking, activamos a flag GL COLOR MATERIAL: glenable ( GL2. GL_COLOR_MATERIAL ); Da mesma forma utilizamos a função glcolormaterial para definir a face e a componente de luz afectada: glcolormaterial ( GL2. GL_FRONT, GL2. GL_ AMBIENT_ AND_ DIFFUSE ); 1 O parâmetro offset é específico do binding JOGL. No contexto deste documento tomará sempre o valor 0. 47

49 Figura 5.15: Polígono após definição com glmaterial Juntando tudo no mesmo bloco de código obtemos:... // No metodo init (...) gl. glenable ( GL2. GL_LIGHTING ); float [] ambientlight = new float [] {1f, 1f, 1f, 1f; gl. gllightmodelfv ( GL2. GL_ LIGHT_ MODEL_ AMBIENT, ambientlight, 0); gl. glenable ( GL2. GL_COLOR_MATERIAL );... // No metodo display (...) gl. glcolormaterial ( GL2. GL_FRONT, GL2. GL_AMBIENT_AND_DIFFUSE ); gl. glcolor3f (0.75f, 0.75f, 0.75 f); gl. glbegin ( GL2. GL_TRIANGLES ); gl. glvertex3f (60f, -40, 0f); gl. glvertex3f ( -60f, -40f, 0f); gl. glvertex3f (0f, 40f, 0f); gl. glend (); O resultado final da utilização do GL COLOR MATERIAL, será semelhante ao obtido definindo o material para cada polígono individual (Figura 5.15). A Figura 5.16 mostra os resultados para vários níveis da luz ambiente num objecto mais complexo. 5.6 Fontes de Luz Num cenário real, as fontes de luz podem ser variadas. Para além da cor e intensidade, são providas de uma localização e direccionalidade. Com o OpenGL é possível definir 8 fontes de luzes independentes com uma localização no nosso viewing volume. Ao especificar uma luz, dizemos ao OpenGL a sua localização e para onde se dirige. Ao especificar uma luz direccional, esta incide nos objectos com um determinado ângulo, que determina a forma como o objecto é iluminado. A fim de conseguir calcular o shading (as sombras) numa superfície, o OpenGL deve conhecer o ângulo de incidência da luz. A luz incide numa superfície com um determinado ângulo (A) e é reflectida com outro ângulo (B) em direcção ao observador (Figura 5.17). Estes ângulos são utilizados em conjunto com as propriedades dos materiais, para determinar a cor aparente de cada vértice. Posteriormente pela utilização de smooth shading (GL SMOOTH), é dada a sensação de iluminação do polígono. Se tivermos em consideração que cada polígono é definido por um conjunto de pontos, determinar o ângulo que a luz faz com um ponto pode representar uma dificuldade 1. Para resolver esse problema, cada ponto terá que conter informação acerca do vector que define a sua orientação vertical (upward). 1 O segundo ângulo (B) pode tomar uma infinidade de valores possíveis 48

50 (a) ambientlist =.8,.8,.8 (b) ambientlist =.4,.4,.4 Figura 5.16: Vários níveis de Luz Ambiente Figura 5.17: Reflexão da Luz nos Objectos 49

51 Vectores Normais às Superfícies O vector normal (normal vector) de uma determinada superfície, é um vector que começa num ponto imaginário algures na superfície fazendo um ângulo recto com esta (Figura 5.18). Figura 5.18: Vectores Normais (2D e 3D) É possível especificar normais para os polígonos gerados pelas primitivas OpenGL. No entanto, pode fazer sentido especificar normais para pontos em particular, por exemplo, no caso em que a normal não é totalmente perpendicular ao polígono. Especificação da Normal A Figura 5.19 mostra um plano paralelo ao plano xy no espaço 3D. O vector normal poderá será definido pelo vector entre o ponto (1, 1, 0) e qualquer outro ponto (acima deste) na recta que o atravessa, como por exemplo o ponto (1, 10, 0). Figura 5.19: Exemplo de um vector normal a uma superfície Para especificar o vector normal do exemplo seriam necessários 2 pontos. No OpenGL é possível especificar o vector normal utilizando apenas um ponto, para tal, movemos o vector para a origem (0, 0, 0), subtraindo o primeiro ponto ao segundo, obtendo: V normal = V (1,10,10) V (1,1,0) = V (0,9,0) O ângulo do vector normal inicial mantém-se no vector entre a origem e nosso novo ponto (Figura 5.20). O vector normal pode ser associado a uma superfície utilizando a função glnormal, como mostra o exemplo: gl. glbegin ( GL_TRIANGLES ); gl. glnormal3f (0.0f, -1.0f, 0.0 f); gl. glvertex3f (0.0f, 0.0f, 60.0 f); gl. glvertex3f ( -15.0f, 0.0f, 30.0 f); gl. glvertex3f (15.0f,0.0f,30.0 f); gl. glend (); 50

52 Figura 5.20: Vector Normal movido para a Origem No exemplo, a função glnormal3f especifica o vector normal à superfície definida pelos três vectores subsequentes (neste caso um triângulo), na direcção do eixo-y negativo. Os vectores são desenhados em counterclock-wise quando vistos do lado para que aponta o vector, de forma a manter o winding coerente. Vectores Normais Unitários Todos os vectores normais no OpenGL, devem ser vectores unitários (de comprimento 1). Podemos converter qualquer vector para um vector unitário obtendo o seu cumprimento e dividindo as componentes nos 3 eixos por esse cumprimento: x 1 = Length = x 2 + y 2 + z 2 x Length, y y 1 = Length, z z 1 = Length V 1 = (x 1, y 1, z 1 ) O processo de tornar um vector unitários denomina-se de normalização de vectores. A fim de evitar os cálculos, podemos dizer ao OpenGL para converter automaticamente as nossas normais para vectores unitários, activando a flag: glenable ( GL2. GL_NORMALIZE ); No entanto, isto tem um custo no desempenho. A melhor solução será efectuar o pré-cálculo dos vectores normais já normalizados. Sem mais configuração, a transformação efectuada pela função glscale, altera, junto com a geometria, o tamanho das normais definidas para os nossos polígonos. Para evitar esse efeito podemos activar a flag: glenable ( GL2. GL_RESCALE_NORMALS ); Junto com este documento, foi criado um projecto do eclipse contendo classes de auxílio à programação OpenGL. Uma dessas classes é a classe GlTools que contém um conjunto de funções úteis. Uma dessas funções é a função: GLVector GlTools. normalizevector ( GLVector v); Esta função recebe como argumento um vector (classe GLVector) e devolve uma instância normalizada do vector fornecido. 51

53 Figura 5.21: Um vector normal não trivial Figura 5.22: Produto Vectorial 52

54 Determinando a Normal No caso da Figura 5.21 o vector normal não é tão óbvio. A determinação de um vector normal pode ser feita utilizando 2 vectores (ou 3 pontos) do plano que representa a superfície (Figura 5.22). O produto vectorial desses vectores é um vector perpendicular à superfície. Tomando o vector V 1 ( P 1 P 2 ) e V 2 ( P 1 P 3 ), o produto vectorial (V P = V 1 V 2 ) pode ser obtido utilizando a fórmula: x P = y 1 z 2 y 2 z 1 y P = x 1 z 2 x 2 z 1 z P = x 1 y 2 x 2 y 1 Mais uma vez, com o fim de facilitar o cálculo, foi criado código para facilitar esta tarefa: GLVector v1 = new GLVector (1f, 2f, 3f); GLVector v2 = new GLVector (4f, 5f, 6f); GLVector vp = v1. crossproduct ( v2 ); O exemplo acima, cria dois vectores (v1 e v2) e utiliza a função crossproduct da instância v1 para criar o vector vp com o resultado do produto vectorial Configurando uma Fonte de luz Conhecidos que estão os requisitos para a iluminação de polígonos, podemos adicionar luzes ao nosso cenário. A configuração de luzes é feita utilizando a função: gllightfv ( int light, int pname, float [] params, int offset ); A criação de um ponto de luz pode ser feita da seguinte forma: // na funcao init (...) float [] ambientlight = { 0.1 f, 0.1 f, 0.1 f, 1.0 f ; float [] diffuselight = { 0.4 f, 0.4 f, 0.4 f, 1.0 f ; // Configurar e Activar a Luz 0 gl. gllightfv ( GL2. GL_LIGHT0, GL2. GL_AMBIENT, ambientlight, 0); gl. gllightfv ( GL2. GL_LIGHT0, GL2. GL_DIFFUSE, diffuselight, 0); gl. glenable ( GL2. GL_LIGHT0 ); // na funcao display (...) // Posicionar a luz no cenario float lightpos [] = { -50. f, 50.0 f, f, 1.0 f ; gl. gllightfv ( GL2. GL_LIGHT0, GL2. GL_POSITION, lightpos ); Os arrays ambientlight[] e diffuselight[] contém o RGBA das componentes ambiente e difusa da luz. O array lightpos[] define a posição da luz. A posição da luz é definida na ModelView Matrix uma vez que é um objecto geométrico, daí ser posicionada normalmente na função display(). Quando o último valor da posição da luz é 1f, o array define a posição da luz, quando o seu valor é 0, a luz encontra-se na direcção do vector lightpos[], mas no infinito. Ao desenhar os polígonos dos nossos objectos é necessário definir os vectores normais. Para facilitar o cálculo dos vectores normais foi criada uma função na classe GlTools, que pode ser utilizada da seguinte forma: // Criar uma lista de vectores GLTVectorList vpoints = new GLTVectorList (); vpoints. add (15.0f, 0.0f, 30.0 f); vpoints. add (0.0f, 15.0f, 30.0 f); vpoints. add (0.0f, 0.0f, 60.0 f); // Obter o vector normal ao plano GLVector vnormal = GlTools. getnormalvector ( vpoints ); gl. glnormal3fv ( vnormal. toarray (), 0); // 0 -> ignorar vpoints. draw (); A classe GLTVectorList fornece uma forma simples de criar listas de vectores. O vector normal pode ser obtido com a função GlTools.getNormalVector que recebe como argumento a lista de vectores criada. O cálculo é feito com base nos primeiros 3 vectores adicionados na lista. Para utilizar nas funções do OpenGL, 53

55 classe GLVector fornece o método toarray como forma simples de converter a instância actual para um array de float. Depois de aplicada a nossa fonte de luz, a imagem da Figura 5.16(b) toma o aspecto da Figura Figura 5.23: Imagem com Fonte de Luz Sugestão A fim de aumentar o desempenho da nossa aplicação e uma vez que a geometria normalmente é conhecida à partida, seria boa ideia guardar a lista de vectores (polígonos) e suas normais à priori e apenas desenhá-los no momento oportuno. 5.7 Efeitos de Iluminação A luz ambiente e difusa são suficientes no caso de estarmos a modelar superfícies que não têm componente especular da luz, tais como, madeira, papel, carvão, ou semelhantes. No entanto, em superfícies tais como a pele e metálicas em geral, é desejável a componente especular. Ao adicionar esta componente podemos dar brilho às superfícies, tal como o brilho numa esfera colorida de vidro Luz Especular Podemos adicionar luz especular à fonte de luz definida anteriormente da seguinte forma: // metodo init (...) float [] specularlight = { 1f, 1f, 1f, 1f ;... gl. gllightfv ( GL2. GL_LIGHT0, GL2. GL_SPECULAR, specularlight, 0); O array specularlight[] especifica uma componente especular muito brilhante na nossa fonte de luz (luz branca RBG=[255, 255, 255]). Seguidamente, utilizando a função gllightfv adicionamos à luz GL LIGHT0 a componente especular. A seguir é necessário definir a forma como o nosso objecto reflecte a luz especular, o que pode ser feito com o código: // metodo display (...) // Definir a componente especular dos objectos... float [] specref = { 1.0f, 1.0f, 1.0f, 1.0 f ; gl. glmaterialfv ( GL2. GL_FRONT, GL2. GL_SPECULAR, specref, 0); //.. com um valor alto de brilho gl. glmateriali ( GL2. GL_FRONT, GL2. GL_SHININESS, 128);... Mantendo o color tracking activo, as cores utilizadas são as definidas pela função glcolor. O array specref[] define os valores RGBA para a reflexão especular. Utilizando a cor branca, dizemos que as superfícies reflectem 54

56 praticamente todas as cores da componente especular. Utilizamos depois este array na propriedade GL SPECULAR na face GL FRONT dos nossos objectos (Figura 5.24). Figura 5.24: Adição de Luz Especular Expoente Especular Para obter o efeito de brilho nas zonas onde a luz especular incide e sombra à medida que nos afastamos, alteramos a propriedade GL SHININESS na face do objecto: gl. glmateriali ( GL2. GL_FRONT, GL2. GL_SHININESS, 128); Esta função define o chamado expoente especular dos materiais. Basicamente define o quão pequeno é o foco da luz. Com o valor próximo de 0, o foco é grande e provocando uma incidência semelhante à difusa/ambiente. À medida que aumentamos o valor, a nossa luz vai ficando mais focada provocando um ponto de luz mais definido. O valor do GL SHININESS pode variar entre 1 e Normal Averaging A técnica de normal averaging é um tweaking que permite dar a ilusão de uma superfície suave (smooth) ainda que seja composta por polígonos planos, como o exemplo da Figura Figura 5.25: Esfera composta de quads e triângulos Se especificarmos as normais aos polígonos, o que vamos obter é uma superfície parecida com um diamante. No entanto, se especificarmos as verdadeiras normais, ou seja, nos vértices, o OpenGL interpola de forma suave através da superfície dos polígonos. O resultado é a ilusão de uma superfície suave. A Figura 5.26 ilustra as diferenças entre as normais aos polígonos e aos vértices. No segundo caso as normais são perpendiculares à superfície real do circulo. 55

57 (a) Normais perpendiculares a cada face (b) Normais perpendiculares a cada vértice Figura 5.26: Normal Averaging Calcular este tipo de normal para uma esfera é relativamente simples, uma vez que todas as normais passam pelo seu centro. No entanto, para superfícies mais complexas o cálculo é feito com base nas normais de vários polígonos que partilham o vértice em questão. A normal resultante é a média destas normais, daí o nome normal averaging Especificando um Spotlight Para transformarmos uma fonte de luz num Spotlight basta adicionar-lhe direccionalidade e definir a sua abertura. Podemos conseguir esse efeito utilizando o código: // algures no init (...) gl. gllightf ( GL2. GL_LIGHT0, GL2. GL_SPOT_CUTOFF, 30f); // algures no display (...) float [] spotdir = { -1f, -1f, 0f; gl. gllightfv ( GL2. GL_LIGHT0, GL2. GL_SPOT_DIRECTION, spotdir, 0); O efeito conseguido com a adição de um spotlight será semelhante ao da Figura Figura 5.27: Adição de um Spotlight 56

58 A propriedade GL SPOT CUTOFF define o ângulo de abertura do nosso spotlight, conforme mostra a Figura Figura 5.28: Ângulo do cone do Spotlight A propriedade GL SPOT DIRECTION define a direcção do spot segundo um vector normalizado. Neste caso o vector ( 1, 1, 0) diz que o nosso spot aponta no sentido negativo dos eixos x e y e faz um ângulo de 45 o com o eixo-y para esquerda Tesselation O conjunto de polígonos que descrevem uma superfície denomina-se de tesselation. Quanto maior for o nível de tesselation mais realistas parecem as nossas curvas no caso da esfera. A Figura 5.29 mostra duas esferas com números diferentes de polígonos. Figura 5.29: Tesselation 57

59 Capítulo 6 Cores e Materiais (Continuação) Os exemplos constantes daqui para a frente, serão baseados no código fornecido junto com este item, na classe Example0 (Apêndice C.1). O exemplo contém um torus, definições básicas de luz e um chão como mostra a Figura 6.1. Figura 6.1: Example0 6.1 Blending Já vimos que o OpenGL armazena os valores de cor no buffer de cor (em circustâncias normais) na altura de renderizar. Já vimos também que o mesmo acontece à informação da profundidade de cada um dos elementos (depth buffer). Quando activamos o teste de profundidade (depth test), um elemento substitui outro, apenas se estiverem mais perto no clipping volume ao utilizador. No caso do blending estas regras não se aplicam: glenable ( GL2. GL_BLEND ); Quando activo, novas cores são combinadas com as que existem actualmente no buffer de cor. Esta combinação é feita com base num conjunto de critérios Combinação de Cores A terminologia utilizada para as cores é: destination color: Valores RGBA da cor que se encontra actualmente no buffer de cor source color: Valores RGBA da cor do elemento que vai interagir com a destination color 58

60 A forma como estas duas componentes interagem é controlada pela equação de blending: C f = (C S S) + (C D D) Em que C f é a cor resultante, C S é a source color, C D é a cor de destino, S e D são os factores de blending de origem e destino. Estes factores são configurados com a função: glblendfunc ( int source_ function, int destination_ function ); Os valores possíveis para os factores estão enumerados na Tabela 6.1. Function RGB Blend Factors Alpha Blend Factor GL ZERO (0, 0, 0) 0 GL ONE (1, 1, 1) 1 GL SRC COLOR (R S, G S, B S ) A S GL ONE MINUS SRC COLOR (1, 1, 1) (R S, G S, B S ) 1 As GL DST COLOR (R D, G D, B D ) A D GL ONE MINUS DST COLOR (1, 1, 1) (Rd, Gd, Bd) 1 A D GL SRC ALPHA (A S, A S, A S ) A S GL ONE MINUS SRC ALPHA (1, 1, 1) (As, As, As) 1 A S GL DST ALPHA (Ad, Ad, Ad) Ad GL ONE MINUS DST ALPHA (1, 1, 1) (Ad, Ad, Ad) 1 Ad GL CONSTANT COLOR (Rc, Gc, Bc) Ac GL ONE MINUS CONSTANT COLOR (1, 1, 1) (Rc, Gc, Bc) 1 Ac GL CONSTANT ALPHA (Ac, Ac, Ac) Ac GL ONE MINUS CONSTANT ALPHA (1, 1, 1) (Ac, Ac, Ac) 1 Ac GL SRC ALPHA SATURATE (f, f, f) f=min(as,1 A D ) 1 Tabela 6.1: Factores de Blending do OpenGL Como os valores RGBA são floats (0 1) as operações de soma e subtracção continuam a gerar valores válidos. Ao seleccionar uma das opções GL CONSTANT COLOR, GL ONE MINUS CONSTANT COLOR, GL CONSTANT ALPHA, e GL ONE MINUS CONSTANT ALPHA, podemos introduzir uma cor constante no blending. A cor inicialmente é black (rgba(0, 0, 0, 0)), para alterar essa cor utilizamos: glblendcolor ( float red, float green, float blue, float alpha ); Um exemplo comum de configuração da função de blending poderia ser: glblendfunc ( GL2. GL_SRC_ALPHA, GL2. GL_ONE_MINUS_SRC_ALPHA ); Neste caso a source color (RGBA) seria multiplicada pelo seu valor alpha (GL SRC ALPHA). A destination color seria multiplicada por 1 menos o valor do seu alpha (GL ONE MINUS SRC ALPHA). O resultado final seria a soma das duas cores. Por exemplo: C S = rgba (0, 0, 1,.5) GL_SRC_ALPHA S = 0.5 C D = rgba (1, 0, 0, 0) GL_ONE_MINUS_SRC_ALPHA D = Como C f = (C S S) + (C D D) temos: C f = ( Blue * 0.5) + ( Red * 0.5) Para o exemplo a cor final será uma mistura das duas cores (vermelho + azul). Quanto maior for o valor S, maior será o valor da source color na mistura. O blending é normalmente utilizado para conseguir a ilusão de transparência. Tal ilusão pode ser conseguida, ligando o blending ao desenhar o objecto transparente. O código em baixo utiliza a estrutura do Example0 adicionando um segundo torus com blending: // Limpar o fundo da janela com a cor definida gl. glclear ( GL2. GL_COLOR_BUFFER_BIT GL2. GL_DEPTH_BUFFER_BIT ); gl. glmaterialfv ( GL2. GL_FRONT, GL2. GL_SPECULAR, fbrightlight, 0); gl. glpushmatrix (); gl. gllightfv ( GL2. GL_LIGHT0, GL2. GL_POSITION, flightpos. toarray (), 0); 59

61 // Desenhar um Torus Verde gl. glcolor4f (0, 1f, 0,.5f); drawworld (gl ); // Desenhar um Torus Vermelho com Blending gl. glpushmatrix (); gl. gltranslatef (.1f, 0,.3f); gl. glenable ( GL2. GL_BLEND ); gl. glblendfunc ( GL2. GL_SRC_ALPHA, GL2. GL_ONE_MINUS_SRC_ALPHA ); gl. glcolor4f (1f, 0, 0, drawworld (gl );.5f); gl. gldisable ( GL2. GL_BLEND ); gl. glpopmatrix (); gl. glcolor4f (0.60f,.40f,.10f,.5f); GlUtil. drawground ( FloorSize, 1f); gl. glpopmatrix (); O resultado do código em cima será o da Figura 6.2. Figura 6.2: Exemplo de Blending Modificando ligeiramente o código anterior, podemos obter a sensação de reflexão: gl. glpushmatrix (); // Desenhar a luz Invertida ( mirror Y) gl. gllightfv ( GL2. GL_LIGHT0, GL2. GL_POSITION, flightpos. mirrory (). toarray (), 0); // Desenhar a reflexao do Torus gl. glpushmatrix (); // Ao utiliza y = -1 estamos a inverter a imagem gl. glscalef (1f, -1f, 1f); gl. glfrontface ( GL2. GL_CW ); // Estamos Invertidos drawworld (gl ); gl. glfrontface ( GL2. GL_CCW ); // Repor gl. glpopmatrix (); // Desenhar o Nosso chao, mas agora transparente gl. gldisable ( GL2. GL_LIGHTING ); gl. glenable ( GL2. GL_BLEND ); gl. glblendfunc ( GL2. GL_SRC_ALPHA, GL2. GL_ONE_MINUS_SRC_ALPHA ); gl. glcolor4f (.5f,.5f,.5f,.5f); GlUtil. drawground ( FloorSize, 1f); 60

62 gl. gldisable ( GL2. GL_BLEND ); gl. glenable ( GL2. GL_LIGHTING ); // Desenhar a luz no local correcto gl. gllightfv ( GL2. GL_LIGHT0, GL2. GL_POSITION, flightpos. toarray (), 0); // Desenhar um Torus Verde gl. glcolor4f (0, 1f, 0,.5f); drawworld (gl ); gl. glpopmatrix (); O código acima desenha inicialmente o torus debaixo do chão com a geometria invertida sobre o eixo-y (glscalef(0, -1f, 0)). Porque a geometria está invertida é preciso redefinir a forma como é deterinhada a face dos polígonos, utilizando glfrontface(gl CW). Da mesma forma o nosso ponto de luz tem que ser colocado na posição inversa, de forma a manter a iluminação dos objectos coerentes. Seguidamente activamos o blending e desenhamos o nosso chão com um alpha de.5f. Finalmente repomos a posição da luz e desenhamos o torus com a geometria em posição. O resultado obtido é o da Figura 6.3. Figura 6.3: Ilusão de Reflexão utilizando Blending Alteração da Equação de Blending A equação mostrada anteriormente: C f = (C S S) + (C D D) é a queação por omissão. Podemos, no entanto, escolher de entre um conjunto de equações possíveis para a determinação do blending, utilizando o seguinte código: glblendequation ( int equation ); As equações possíveis para a determinação do blending são as descritas na Tabela 6.2. Mode Function GL FUNC ADD (default) C f = (C S S) + (C D D) GL FUNC SUBTRACT C f = (C S S) (C D D) GL FUNC REVERSE SUBTRACT C f = (C S D) (C D S) GL MIN C f = min(c S, C D ) GL MAX C f = max(c S, C D ) Tabela 6.2: Factores de Blending do OpenGL 61

63 Da mesma forma que deifinimos a função de blending para os valores RGBA source e destination utilizando glblendfunc, podemos utilizar a função glblendfuncseparate para especificar funções diferentes também para o cálculo dos factores alpha: glblendfuncseparate ( int srcrgb, int dstrgb, int srcalpha, int dstalpha ); Sendo o srcrgb a função para o source color, o dstrgb a função para o destination color. Os valores srcalpha e dstalpha permitem definir as funções para o source e destination alpha respectivamente. 6.2 Antialiasing Na maior parte dos casos, fragmentos individuais da nossa renderização, consistem de pixeis no ecrã. Estes pixeis são quadrados (ou quase), podendo quebrar a sensação de realismo. O OpenGL permite definir flags que misturam as bordas de pontos, linhas e polígonos com a vizinhança, suavizando os contornos dos objectos. Para tal, é preciso activar primeiro o blending e definir as funções para o source e destination color. Depois podemos activar as flags: GL POINT SMOOTH (pontos), GL LINE SMOOTH (linhas) e GL POLYGON SMOOTH (polígonos). A Figura 6.4 mostra dois circulos, sendo o de fora desenhado sem antialiasing e o de dentro desenhado com antialiasing. (a) Circulos Com/Sem Antialiasing (b) Zoom Figura 6.4: Antialiasing O código para conseguir o resultado da Figura 6.4(a) poderia ser: gl. glclear ( GL2. GL_COLOR_BUFFER_BIT ); float x, y; gl. gllinewidth (5f); // Desenhar o Primeiro Circulo Sem Antialiasing gl. glbegin ( GL2. GL_LINE_LOOP ); for ( float a =0; a < 2f * GlTools. GL_PI ; a +=.1 f) { x = ( float ) Math. sin (a) / 2f; y = ( float ) Math. cos (a) / 2f; gl. glvertex3f (x, y, 0); gl. glend (); // Activar o Blending / Antialiasing e Desenhar o Circulo de Dentro gl. glenable ( GL2. GL_BLEND ); gl. glblendfunc ( GL2. GL_SRC_ALPHA, GL2. GL_ONE_MINUS_SRC_ALPHA ); // Suavizar as linhas gl. glenable ( GL2. GL_LINE_SMOOTH ); 62

64 gl. glhint ( GL2. GL_LINE_SMOOTH_HINT, GL2. GL_NICEST ); // Desenhar o Circulo de Dentro com Antialiasing gl. glbegin ( GL2. GL_LINE_LOOP ); for ( float a =0; a < 2f * GlTools. GL_PI ; a +=.1 f) { x = ( float ) Math. sin (a) / 2.2 f; y = ( float ) Math. cos (a) / 2.2 f; gl. glvertex3f (x, y, 0); gl. glend (); gl. gldisable ( GL2. GL_LINE_SMOOTH ); gl. gldisable ( GL2. GL_BLEND ); O código em cima desenha um circulo sem antialiasing, depois activa o blending e activa o antialiasing para as linhas (GL LINE SMOOTH) e desenha o circulo mais pequeno. Adicionalmente o algoritmo escolhido para o antialiasing foi o que tem melhor aspecto final utilizando glhint(gl NICEST). Os algoritmos disponíveis para o cálculo do antialiasing são GL NICEST e GL FASTEST, sendo que o último tem um resultado visual mais fraco ainda que seja mais rápido Multisampling Apesar do aspecto visual ser melhorado pela utilização de antialiasing, esta não é a melhor escolha para tornar os objectos na cena mais realísticos. O GL POLYGON SMOOTH não é suportado em todas as plataformas e como utiliza o blending termiamos que desenhar todas as nossa primitivas da frente para trás. Uma adição ao OpenGL 1 permite endereçar esta problema. O multisampling consiste num buffer adicional. Neste buffer os pixeis de cada primitiva são amostrados 2 várias vezes, sendo o resultado mostrado como um único pixel. Se o nosso contexto OpenGL suportar multisampling, podemos activá-lo utilizando: glenable ( GL2. GL_MULTISAMPLE ); Figura 6.5: Normal vs Multisampling 6.3 Nevoeiro (Fog) O OpenGL suporta a adição de nevoeiro ao cenário. A técnica utilizada pelo OpenGL para dar a sensação de fog consiste no blending de uma cor específica com a geometria no final de toda a computação. A quantidade de blending dessa cor (alias: nevoeiro) com cada objecto do cenário depende da distância desse objecto ao observador. A introdução de nevoeiro pode tornar ainda mais real a sensação de profundidade, uma vez que a visibilidade dos objectos é menor à medida que se afastam, o que acontece no mundo real. Podemos activar o nevoeiro utilizando: glenable ( GL2. GL_FOG ); 1 Para versões > sampled 63

65 Figura 6.6: Nevoeiro A configuração do nevoeiro é feita utilizando uma das versões da função glfog: glfogi ( int pname, int param ); glfogf ( int pname, float param ); glfogiv ( int pname, int [] params, int offset ); glfogfv ( int pname, float [] params, int offset ); Onde o primeiro argumento (pname) escolhe a propriedade que estamos a alterar e o segundo argumento define o novo valor para a propriedade. Para configurar o nevoeiro utilizando uma determinada cor, que começa a afectar a geometria à distância 1f do observador, terminando em 30f e utilizando uma variação linear utilizamos: float [] flowlight = { 0.25 f, 0.25 f, 0.25 f, 1.0 f ;... // Definir a cor do Nevoeiro gl. glfogfv ( GL2. GL_FOG_COLOR, flowlight, 0); // A que distancia os objectos comecao a ser afectados gl. glfogf ( GL2. GL_FOG_START, 1.0 f); // Ponto onde o nevoeiro toma conta completamente gl. glfogf ( GL2. GL_FOG_END, 30.0 f); // Equacao do calculo do Nevoeiro gl. glfogi ( GL2. GL_FOG_MODE, GL2. GL_LINEAR ) Analisando em mais detalhe o código temos: gl. glfogfv ( GL2. GL_FOG_COLOR, flowlight, 0); No exemplo (Figura 6.6) podemos observar que o nevoeiro toma a cor do fundo. A cor do nevoeiro é definida alterando o parâmetro GL FOG COLOR e fornecendo um array contendo os valores RGB. // A que distancia os objectos comecao a ser afectados gl. glfogf ( GL2. GL_FOG_START, 1.0 f); // Ate onde vai o nevoeiro gl. glfogf ( GL2. GL_FOG_END, 30.0 f); O parâmetro GL FOG START especifica a que distância do observador o nevoeiro começa a ter efeito sobre os objectos. O parâmetro GL FOG END define o ponto a partir do qual o nevoeiro toma completamente a cor dos objectos. // Equacao do calculo do Nevoeiro gl. glfogi ( GL2. GL_FOG_MODE, GL2. GL_LINEAR ) A transição entre o GL FOG START e o GL FOG END é controlada pelo GL FOG MODE, que no exemplo está configurada para GL LINEAR. A fog equation define o factor de nevoeiro entre 0 e 1, à medida que o objecto se desloca entre o inicio e o fim do nevoeiro. 64

66 Fog Mode Fog Equation GL LINEAR f = end c end start GL EXP f = e d c GL EXP2 f = e (d c)2 Tabela 6.3: Fog Equations A Tabela 6.4 descreve as equações para as várias equações possíveis. Onde c é a distância ao observador, start é o valor de GL FOG START e end é o valor de GL FOG END. O valor d é a densidade do nevoeiro, que pode ser configurada alterando o parâmetro GL FOG DENSITY: glfogf ( GL2. GL_FOG_DENSITY, 0.5 f); Para GL LINEAR o valor da densidade não tem qualquer efeito, no entanto, para GL EXP e GL EXP2 este valor altera o resultado final do nevoeiro. A Figura 6.7 mostra a forma como cada equação faz variar o nevoeiro entre o inicio e o fim para uma densidade de 0.5. Figura 6.7: Equações da Densidade do Nevoeiro O modo como o OpenGL determina a distância a profundidade do nevoeiro para cada elemento no cenário pode ser alterada utilizando o parâmetro GL FOG COORD SRC. Dois valores podem ser utilizados: GL FRAGMENT DEPTH: Utiliza a profundidade do objecto como valor da distância. Permite obter melhores resultados. GL FOG COORD (valor por omissão): Faz a interpolação do nevoeiro entre vértices, o que permite um cálculo mais rápido. A alteração deste parâmetro pode ser feita utilizando: glfogi ( GL2. GL_FOG_COORD_SRC, GL2. GL_FRAGMENT_DEPTH ); // ou glfogi ( GL2. GL_FOG_COORD_SRC, GL2. GL_FOG_COORD ); 6.4 Accumulation Buffer Em adição aos buffers de cor, profundidade e stencil 1, o OpenGL contém um buffer especial que nos permite armazenar os valores do buffer de cor em vez de os enviar para o ecrã. Um conjunto de operações permitem acumular várias iterações do buffer de cor, que pode então ser mostrado no ecrã. O comportamento do buffer de acumulação pode ser controlado pela função: glaccum ( int operation, float value ); O primeiro argumento especifica a operação de acumulação a realizar e o segundo valor especifica um factor de escala para a operação. A operações possíveis estão enumeradas na Tabela??. Devido à quantidade de operações de memória e processador necessários para realizar este tipo de operações, poucas aplicações em tempo-real utilizam este buffer. No entanto, os efeitos visuais conseguidos podem ser de um realismo surpreendente. Por exemplo, é possível recriar vários tipos de blur que podem simular os efeitos de profundidade encontrados nas câmaras de vídeo e fotográficas. O efeito na Figura 6.8 pode ser conseguido utilizando: 1 A ser analisado futuramente 65

67 Operation GL ACCUM GL LOAD GL MULT GL ADD GL RETURN Description Escala os valores actuais do buffer de cor e adiciona-os ao buffer de acumulação Escala os valores actuais do buffer de cor e substitui os valores actuais do buffer de acumulação Escala os valores actuais do buffer e armazena-os no buffer de acumulação Escala os valores actuais do buffer e adiciona os aos valores actualmente no buffer de acumulação Escala os valores actuais do buffer e armazena-os no buffer de cor Tabela 6.4: Fog Equations Figura 6.8: Efeito blur utilizando buffer de acumulação 66

68 float xoff = 0f; // Desenhar os objectos 10 x movendo - os progressivamente para a esquerda for ( int pass = 0; pass < 10; pass ++) { xoff +=.05 f; gl. glpushmatrix (); gl. gltranslatef ( xoff, 0, 0); gl. glcolor3f (0, 1f, 0); drawworld (gl ); gl. glpopmatrix (); // Desenhar o chao gl. glcolor4f (0.60f,.40f,.10f,.5f); GlUtil. drawground ( FloorSize, 1f); if( pass == 0) gl. glaccum ( GL2. GL_LOAD, 0.5 f); // Copiar buffer de cor else // Acumular o buffer de cor actual com o accum buffer gl. glaccum ( GL2. GL_ACCUM, 0.5 f * (.5 f / pass )); // Despejar o buffer de acumulacao no buffer de cor gl. glaccum ( GL2. GL_RETURN, 1.0 f); 67

69 Capítulo 7 Imagens no OpenGL 7.1 Bitmaps O aspecto visual de um bitmap não é o ideal, ainda que seja perfeitamente possível identificar os objectos nele contidos (Figura 7.1(a)). No OpenGL os bitmaps podem ser utilizados para máscaras (polygon stippling), fontes e caracteres e dithering a duas cores. (a) Bitmap (b) Pixmap Figura 7.1: Imagem Bitmap A imagem da Figura 7.1(b), contém 256 níveis de cinzento, sendo denominada de pixmap. Figura 7.2: Imagem Campfire Podemos descrever a imagem utilizada anteriormente para o stippling de polígonos (Figura 7.2), sob a forma de um array de 4 bytes 32 (32 32 bit). Os valores no array de bytes estão em hexadecimal. Como podemos observar, os valores no array estão invertidos, ou seja, a primeira linha do array representa a última linha do bitmap. 68

70 ByteBuffer fire = ByteBuffer. wrap ( new byte [] { ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0xc0, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x01, ( byte ) 0xf0, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x07, ( byte ) 0xf0, ( byte ) 0x0f, ( byte ) 0x00, ( byte ) 0x1f, ( byte ) 0xe0, ( byte ) 0x1f, ( byte ) 0x80, ( byte ) 0x1f, ( byte ) 0xc0, ( byte ) 0x0f, ( byte ) 0xc0, ( byte ) 0x3f, ( byte ) 0x80, ( byte ) 0x07, ( byte ) 0xe0, ( byte ) 0x7e, ( byte ) 0x00, ( byte ) 0x03, ( byte ) 0xf0, ( byte ) 0xff, ( byte ) 0x80, ( byte ) 0x03, ( byte ) 0xf5, ( byte ) 0xff, ( byte ) 0xe0, ( byte ) 0x07, ( byte ) 0xfd, ( byte ) 0xff, ( byte ) 0xf8, ( byte ) 0x1f, ( byte ) 0xfc, ( byte ) 0xff, ( byte ) 0xe8, ( byte ) 0xff, ( byte ) 0xe3, ( byte ) 0xbf, ( byte ) 0x70, ( byte ) 0xde, ( byte ) 0x80, ( byte ) 0xb7, ( byte ) 0x00, ( byte ) 0x71, ( byte ) 0x10, ( byte ) 0x4a, ( byte ) 0x80, ( byte ) 0x03, ( byte ) 0x10, ( byte ) 0x4e, ( byte ) 0x40, ( byte ) 0x02, ( byte ) 0x88, ( byte ) 0x8c, ( byte ) 0x20, ( byte ) 0x05, ( byte ) 0x05, ( byte ) 0x04, ( byte ) 0x40, ( byte ) 0x02, ( byte ) 0x82, ( byte ) 0x14, ( byte ) 0x40, ( byte ) 0x02, ( byte ) 0x40, ( byte ) 0x10, ( byte ) 0x80, ( byte ) 0x02, ( byte ) 0x64, ( byte ) 0x1a, ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x92, ( byte ) 0x29, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0xb0, ( byte ) 0x48, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0xc8, ( byte ) 0x90, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x85, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x03, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x10, ( byte ) 0 x00 ); Os bitmaps são desenhados no ecrã recorrendo ao raster dos seus bits. Precisamos então de dizer ao OpenGL qual será a posição em que deve ser feito o raster da nossa imagem, com recurso à função glrasterpos. A função glrasterpos é pode receber 2 ou 3 argumentos, sendo que na primeira o eixo z toma o valor 0. O exemplo mostra uma possível utilização da função: gl. glclear ( GL2. GL_COLOR_BUFFER_BIT GL2. GL_DEPTH_BUFFER_BIT ); // Bitmap de cor Verde gl. glcolor3f (0.0f, 1.0f, 0.0 f); for ( int i =0; i < 16; i ++) { // Definir coordenadas do Raster gl. glrasterpos3d ( i - 5, 1, i - 5); // Desenhar o bitmap 32 x32 no array de bytes gl. glbitmap (32, 32, 0f, 0f, 0, 0, fire ); gl. glcolor3f (.5f,.5f,.5f); GlUtil. drawground ( GL2. GL_LINE_STRIP, 20f, 1f); No exemplo em cima, são desenhados 16 bitmaps percorrendo uma diagonal que atravessa o ponto (0, 0, 0). O nosso bitmap é desenhado utilizando a função: glbitmap ( int width, int height, float xorig, float yorig, float xmove, float ymove, ByteBuffer bitmap ); O width e height referem-se ao tamanho em bits do bitmap, no nosso caso 32 32, o xorig e o yorig referem-se ao offset x e y em relação à posição raster, o xmove e o ymove definem a posição de raster quando o desenho terminar e o parâmetro bitmap contém os dados a desenhar. Os bits a 1 no nosso bitmap serão 69

71 transformados em fragmentos (pixel) com a cor actualmente definida, os 0 não afectaram as cores actualmente no color buffer. O resultado do código em cima pode ser visualizado na Figura 7.3. Figura 7.3: Utilização de glbitmap/glrasterpos As coordenadas da função glrasterpos são afectadas pela projecção e posição do observador. Se quisermos que o nosso bitmap seja mostrado sempre na mesma posição no ecrã, independentemente do projecção e observador, devemos utilizar a função glwindowpos, por exemplo: gl. glcolor3f (1.0f, 0.0f, 0.0 f); // colocar o raster o canto inferior esquerdo do ecra gl. glwindowpos2i (10, 10); gl. glbitmap (32, 32, 0f, 0f, 0, 0, fire ); 7.2 Pixmaps Os pixmaps são de maior utilidade nos sistemas full-color. O seu layout na memória é parecido ao dos bitmaps, no entanto, cada pixel pode conter mais do que um bit de informação. Cada pixel pode conter informação acerca da intensidade (referida normalmente como luminance) ou acerca dos componentes de cor. Um pixmap pode ser desenhado a partir da posição actual do raster utilizando a função: void gldrawpixels ( int width, int height, int format, int type, Buffer pixels ) Os primeiros dois argumentos (width/height) referem-se ao tamanho do pixmap em pixels. O argumento format refere-se à forma como a informação está disposta, normalmente referido como formato da imagem (ver Tabela B.1). O argumento type define o tipo de dados na informação e o último argumento contém a informação da imagem 1. Ao contrário da função glbitmap, a posição de raster não é alterada. Os formatos GL STENCIL INDEX e GL DEPTH COMPONENT, são utilizados para ler e escrever informação nos stencil e depth buffers. O argumento type define o tipo de dados armazenados no nosso pixmap. Os valores possíveis para o tipo de dados estão descritos na Tabela B No JOGL, em vez de arrays é recomendada a utilização de buffers - releases/nio/ 2 Na tabela estão omissos os packed RGB value, para mais informação consultar - EXT/packed_pixels.txt 70

72 O exemplo em baixo utiliza numa primeira instância o ClassLoader 1 do Java para ler um ficheiro e a classe TGAImage para utilizar o ficheiro como uma imagem (targa neste exemplo). Posteriormente o método getdata da classe TGAImage permite-nos obter uma referência para a informação (pixmap) contida na imagem sob a forma de um ByteBuffer. class Pixmap implements GLEventListener { private TGAImage img ; private ByteBuffer bb; public void init ( GLAutoDrawable drawable ) { GL2 gl = drawable. getgl (). getgl2 (); //... try { InputStream stream = getclass (). getresourceasstream (" fire. tga "); img = TGAImage. read ( stream ); bb = img. getdata (); stream. close (); catch ( IOException e) { // Tratar do erro... //... O bloco try {... catch(exception e) {... permite ao nosso programa estar preparado no caso da leitura do ficheiro não ser bem sucedida. Este bloco é denominado de exception handling no Java 2. Dentro do try o nosso programa lê o ficheiro fire.tga que deverá estar contido no mesmo package da classe Pixmap. Basta agora no método display() da nossa classe mostrar o pixmap de acordo com a posição do raster. // Definir a posicao do raster gl. glrasterpos2i ( img. getwidth ()*3/4, img. getheight ()*3/4); // Redimensionar e inverter a imagem gl. glpixelzoom ( -.5f, -.5f); // Desenhar a Imagem no ByteBuffer gl. gldrawpixels ( img. getwidth (), img. getheight (), // Tamanho da imagem img. getglformat (), // Pixel Format GL2. GL_UNSIGNED_BYTE, bb ); // Restaurar gl. glpixelzoom (1f, 1f); O resultado do código em cima, pode ser visualizado na Figura 7.4. A função glpixelzoom(float xzoom, float yzoom) permite alterar a escala utilizada para desenhar os pixels. Utilizando xzoom/yzoom negativos, estamos a inverter a ordem utilizada para desenhar os pixels, pelo que a posição do raster tem que ser reajustada. 7.3 Operações com Pixels Até agora temos estado a escrever para os buffers (color, depth,... ), no entanto pode ser útil ler a informação contida nestes buffers ou mesmo copiá-la entre eles. A informação para ler a informação dos pixels funciona como a função gldrawpixels só que no sentido inverso. glreadpixels ( int x, int y, int width, int height, int format, int type, Buffer pixels ) 1 Ver detalhes em 2 Ver mais detalhes em 71

73 Figura 7.4: Utilização de gldrawpixels/glpixelzoom Os argumentos x, y, width e height, definem o rectângulo a copiar 1. O format e type são o formato e o tipo de dados utilizados para armazenar o conteúdo do buffer na variável de saída pixels. Independentemente da forma como a informação está armazenada no color buffer, o OpenGL encarrega-se de fazer as conversões necessárias. Pode ser útil ainda copiar informação dentro do mesmo buffer. Para tal definimos o canto inferior esquerdo (com glrasterpos/glwindowpos) da zona a copiar. A função para efectuar a cópia é: glcopypixels ( int x, int y, int width, int height, int type ); Mais uma vez, o x, y, width e height, definem o rectângulo de origem. O argumento type diz o que estamos a copiar, podendo tomar o valor GL COLOR para copiar do color buffer, GL DEPTH para copiar do depth buffer ou GL STENCIL para copiar do stencil buffer. Por omissão estas operações de cópia realizam-se no back buffer em contextos com suporte para double buffering, ou no front buffer em contextos com single buffer. Para alterar a fonte ou destino para a cópia, utilizamos: gldrawbuffer ( int destination ); glreadbuffer ( int source ); O argumento destination da função gldrawbuffer, especifica onde os pixels são escritos pelas operações gldrawpixels/glcopypixels. O argumento source da função glreadbuffer especifica a fonte para os pixels lidos nas operações glreadpixels/glcopypixels. Os valores possíveis para os argumentos source/destination poderão ser: GL NONE, GL FRONT, GL BACK, GL FRONT AND BACK, GL FRONT LEFT, GL FRONT RIGHT,... Um caso prático de utilização das operações com pixels seria, por exemplo, armazenar o conteúdo do color buffer actual num ficheiro de imagem. A fim de ilustrar os conceitos explicados nesta secção, exemplificamos como isso poderia ser feito: // Ler o valor READ BUFFER actual // ( para repor mais tarde ) IntBuffer lastbuffer = IntBuffer. allocate (1); gl. glgetintegerv ( GL2. GL_READ_BUFFER, lastbuffer ); // Vamos ler o FRONT BUFFER 1 sendo x e y o canto inferior esquerdo 72

74 gl. glreadbuffer ( GL2. GL_FRONT ); // O ByteBuffer output ira armazenar temporariamente // a nossa imagem ByteBuffer output = ByteBuffer. allocate ( width * height * 3); // RGB gl. glreadpixels ( 0, 0, // Canto inferior esquerdo width, height, // Tamanho a ler GL2. GL_BGR, // Formato Blue, Green, Red ( targa ) GL2. GL_ UNSIGNED_ BYTE, // Tipo de dados unsigned byte output ); // Criar um TGA a partir do ByteBuffer TGAImage img = TGAImage. createfromdata ( width, height, false, false, output ); try { img. write ("c:/ my.tga "); // Guardar a imagem no disco catch ( IOException e) { // Falha ao escrever o ficheiro // Restaurar o read buffer anterior gl. glreadbuffer ( lastbuffer. get (0)); A função glget<tipo>(int pname,...) 1 permite-nos obter informação das variáveis do OpenGL (neste caso o buffer de leitura actual - GL READ BUFFER). No JOGL a maior parte das funções que retornam valores, utilizam subclasses de Buffer (neste caso IntBuffer) para os armazenar. É importante no nosso código OpenGL, restaurarmos, na medida do possível, o estado anterior das coisas, daí obtermos o lastbuffer e ser feita a sua reposição no fim do bloco de código, utilizando glreadbuffer(lastbuffer.get(0)). Seguidamente especificamos que o buffer para leitura será o que se encontra visível (GL FRONT): gl. glreadbuffer ( GL2. GL_FRONT ); Inicializamos um ByteBuffer com o tamanho da janela (width height) multiplicado por 3, uma vez que vamos armazenar as três componentes de cor RGB, ficando então width height 3. ByteBuffer output = ByteBuffer. allocate ( width * height * 3); Os ficheiros targa armazenam a informação da cor na ordem BGR (Blue, Green, Red), pelo que o formato dos dadosm especificado é GL BGR. O seguinte código copia o conteúdo do front buffer e coloca-o no nosso ByteBuffer. gl. glreadpixels ( 0, 0, // Canto inferior esquerdo width, height, // Tamanho a ler GL2. GL_BGR, // Formato Blue, Green, Red ( targa ) GL2. GL_ UNSIGNED_ BYTE, // Tipo de dados unsigned byte output ); Finalmente, criamos uma instância de TGAImage com base no ByteBuffer output, utilizando a função: TGAImage. createfromdata ( int width, int height, // Tamanho da imagem boolean hasalpha, // Formato contem alpha boolean toptobottom, // A imagem esta armazenada " ao contrario " ByteBuffer output // ByteBuffer com os dados ); Esta função é utilizada da seguinte forma: TGAImage img = TGAImage. createfromdata ( width, height, false, false, output ); Finalmente para armazenar a nossa imagem no disco fazemos: img. write ("c:/ my.tga ") A imagem my.tga irá conter o conteúdo do nosso front buffer

75 7.4 Outras Operações com Imagens Para além das operações descritas, o OpenGL suporta ainda um conjunto de operações especiais aquando da transferência da informação dos pixels para e do color buffer. Abaixo discutimos algumas das operações possíveis, bem como o código necessário para consegui-las (código completo no Apêndice C.2). O progama inicial para a demonstração desta funcionalidade utiliza uma projecção ortogonal configurada com a função: glortho2d ( double left, double right, double bottom, double top ); Em que left/right são as coordenadas dos clipping planes verticais, e bottom/top são as coordenadas dos clipping planes horizontais. Os valores de znear/zfar especificados na função glortho tomam os valores 0 e 1 respectivamente. A nossa projecção ortogonal irá coincidir com o tamanho da janela e do viewport. O método reshape(...) terá o seguinte aspecto: public void reshape ( GLAutoDrawable drawable, int x, int y, int width, int height ) { // Viewport coincide com a janela gl. glviewport (0, 0, width, height ); gl. glmatrixmode ( GL2. GL_PROJECTION ); gl. glloadidentity (); // Configurar a projeccao ortogonal glu. gluortho2d (0, width, 0, height ); //... À semelhança do que aconteceu com o exemplo na secção anterior, será carregado o ficheiro horse.tga com recurso ao ClassLoader do Java e à função TGAImage.read(...) para a variável de classe img e lidos os bytes para um ByteBuffer (bb). A imagem (Figura 7.5) será mostrada no método display(...) utilizando: gl. gldrawpixels ( img. getwidth (), img. getheight (), img. getglformat (), GL2. GL_UNSIGNED_BYTE, bb ); Figura 7.5: Imaging.java mostranto horse.tga Os blocos de código seguinte mostram como podemos implementar os efetios GaussianBlur, Sharpen, Emboss, Invert e Brighten. Alguns dos efeitos são aplicados utilizando matrizes de convolução, que permitem obter o valor de cor de um pixel com base nos que se encontram nas suas imediações 1. O OpenGL permite aplicar este tipo de matrizes às imagens utilizando a função: 1 Mais detalhes e exemplos em 74

76 glconvolutionfilter2d ( int target, int internalformat, int width, int height, int format, int type, Buffer image ); Em que o target toma o valor GL2.GL CONVOLUTION 2D, o internalformat indica o formato interno da nossa matriz de convolução (para o nosso caso GL2.GL RGB), width/height especificam o tamanho da matriz, format indica o formato dos pixels na imagem de destino, type especifica o tipo de dados da imagem e image contém a informação da imagem. Gaussian Blur Para aplicar o efeito de gaussian blur (Figura 7.6) podemos utilizar a seguinte matriz de convolução: Para tal utilizamos o seguinte código: // Matriz ( convolution kernel ) para efectuar gaussian blur float norm = 16 f; // normalizacao : somatorio dos valores da matriz FloatBuffer mgaussian = FloatBuffer. wrap ( new float [] { 1f/norm, 2f/norm, 1f/norm, 2f/norm, 4f/norm, 1f/norm, 1f/norm, 2f/norm, 1f/ norm ); // Aplicar a matriz gl. glconvolutionfilter2d ( GL2. GL_ CONVOLUTION_ 2D, GL2. GL_RGB, 3, 3, GL2. GL_LUMINANCE, GL2. GL_FLOAT, mgaussian ); // Activar convolucao 2D gl. glenable ( GL2. GL_CONVOLUTION_2D ); // Mostrar gl. gldrawpixels ( img. getwidth (), img. getheight (), img. getglformat (), GL2. GL_UNSIGNED_BYTE, bb ); // Desactivar convolucao 2D gl. gldisable ( GL2. GL_CONVOLUTION_2D ); Figura 7.6: Gaussian Blur A forma de aplicar outras matrizes é semelhante. Apenas mudamos o último argumento da função glconvolutionfilter2d de mgaussian para a matriz criada. Como tal interessa apenas referir quais as matrizes utilizadas e como foram inicializadas. 75

77 Emboss A matriz utilizada para o efeito emboss (Figura 7.7) poderá ser: Inicializada com: // Matriz ( convolution kernel ) para efectuar emboss FloatBuffer memboss = FloatBuffer. wrap ( new float [] { 2.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, -1.0f ); Figura 7.7: Emboss Sharpen A matriz utilizada para o efeito sharpen (Figura 7.8) poderá ser: Inicializada com: // Matriz ( convolution kernel ) para efectuar o sharpen FloatBuffer msharpen = FloatBuffer. wrap ( new float [] { 0.0f, -1.0f, 0.0f, -1.0f, 5.0f, -1.0f, 0.0f, -1.0f, 0.0 f ); Brighten A operação de brighten na imagem pode ser implementada de forma simples. Mudando para a matriz de cor utilizando: gl. glmatrixmode ( GL2. GL_COLOR );... podemos utilizar a função glscale uma vez que as transformações são agora operadas na matriz de cor, como mostra o exemplo: 76

78 Figura 7.8: Sharpen // Mudar para o matrix mode Color gl. glmatrixmode ( GL2. GL_COLOR ); // Aumentar todas as cores em 50% gl. glscalef (2f, 2f, 2f); // Voltar ao ModelView gl. glmatrixmode ( GL2. GL_MODELVIEW ); 77

79 Capítulo 8 Mapeamento de Texturas Na computação gráfica convencional, cada elemento de um pixmaps corresponde a um elemento no ecrã, daí o nome de picture element (alias pixel). No entanto, quando mapeados a primitivas geométricas, raramente estes pixmaps têm uma proporção de 1 para 1. Figura 8.1: Mapeamento de Texturas A aplicação de imagens à geometria é referida como texture ou texture mapping. A utilização de texturas pode aumentar dramaticamente o realismo e a qualidade dos nossos cenários. 8.1 Carregamento de Texturas O primeiro passo na aplicação de texturas à nossa geometria, consiste no carregamento da imagem correspondente para a memória. Esta imagem passa a ser considerada o estado actual da textura. O carregamento de imagens sob a forma de texturas pode ser feito utilizando uma das três versões da função gltextimage: glteximage1d ( int target, int level, int internalformat, int width, int border, int format, int type, Buffer pixels ); glteximage2d ( int target, int level, int internalformat, int width, int height, int border, int format, int type, Buffer pixels ); glteximage3d ( 78

80 int target, int level, int internalformat, int width, int height, int depth, int border, int format, int type, Buffer pixels ); Estas três funções permitem-nos dizer ao OpenGL tudo aquilo que ele precisa de saber relativamente à imagem contida no array pixels. A função gltextimage carrega para a memória, a imagem fornecida e torna-a a textura actual a ser aplicada na geometria. Este carregamento para a memória pode ser dispendioso (alternativas discutidas mais à frente na Secção 8.6). O valor do target para cada uma das funções é respectivamente : GL TEXTURE 1D, GL TEXTURE 2D e GL TEXTURE 3D ou GL PROXY TEXTURE 1D, GL PROXY TEXTURE 2D ou GL PROXY TEXTURE 3D. Ao utilizar proxies, o OpenGL faz uma verificação prévia do que o sistema suporta em termos de compatibilidade, no caso de não haver suporte, o estado da imagem é tornado inválido sem que qualquer tipo de erro seja reportado 1. O argumento level define o nível de mipmapping (discutido na Secção 8.5.3), de momento utilizaremos texturas sem mipmapping, especificando o valor 0. O argumento internalformat, especifica quantos componentes de cor são armazenados por texel, o espaço necessário ao armazenamento dos componentes e/ou se a textura é comprimida. A Tabela 8.1 lista os valores mais comuns para este parâmetro. Constante GL ALPHA GL LUMINANCE GL LUMINANCE ALPHA GL RGB GL RGBA Armazenar os texels como: Valores de alpha Valores de luminância Valores de luminância e alpha Componentes de red, green e blue Componentes de red, green, blue e alpha Tabela 8.1: Factores de Blending do OpenGL Os valores de width, height e depth (apropriadamente) especificam as dimensões da textura que estamos a carregar para a memória. Estas dimensões devem ser inteiros com base 2 (2 x = 1, 2, 4, 8,... ), isto não implica que o mapeamento da textura seja quadrado, mas um valor não 2 x provovará que o mapeamento seja implicitamente desabilitado. O argumento border especifica a largura da borda à volta da textura. Esta borda permite acrescentar texels adicionais à textura. Os argumentos format, type, têm o mesmo objectivo que quando utilizados na função gldrawpixels. O argumento pixels contêm a informação da imagem propriamente dita. Para aplicarmos textura à nossa geometria temos que activar o seu estado apropriado. Para tal utilizamos as funções glenable/gldisable com as constantes GL TEXTURE 1D, GL TEXTURE 2D e GL TEXTURE 3D 2, como ilustra o exemplo: gldisable ( GL2. GL_TEXTURE_1D ); glenable ( GL2. GL_TEXTURE_2D ); Pipeline do Carregamento de Imagens O carregamento de imagens no OpenGL (por ex.: utilizando glteximage) obedece a um pipeline de processamento à semelhança do pipeline de transformações do OpenGL. As operações de convolução, pixel zoom, pixel packing,... (discutidas no capítulo anterior) são aplicadas segundo a Figura Utilizando o Color Buffer É possível carregar texturas 1D e 2D a partir do color buffer, utilizando as seguintes funções: glcopyteximage1d ( int target, int level, int internalformat, int x, int y, int width, int border ); 1 Para verificar se foi bem sucedido utiliza-se a função glgettexparameter 2 É boa ideia desactivar os estados não utilizados, uma vez que apenas um destes estados pode existir em simultâneo 79

81 Figura 8.2: Pipeline - Carregamento de Imagens glcopyteximage2d ( int target, int level, int internalformat, int x, int y, int width, int height, int border ); O significado dos argumentos é semelhante aos argumentos da função glteximage, mas neste caso o x, y, width e height especificam a área no color buffer a ler. O source buffer pode ser definido utilizando a função glreadbuffer Actualização de Texturas O carregamento repetido de texturas pode ser dispendioso em termos de processamento. Substituir uma determinada textura pode ser mais rápido, na maior parte das vezes do que o carregamento utilizando glteximage. Para tal utilizamos as funções: gltexsubimage1d ( int target, int level, int xoffset, int width, int format, int type, Buffer data ); gltexsubimage2d ( int target, int level, int xoffset, int yoffset, int width, int height, int format, int type, Buffer data ); gltexsubimage3d ( int target, int level, int xoffset, int yoffset, int zoffset, int width, int height, int depth, int format, int type, Buffer data ); Mais uma vez, os argumentos são semelhantes aos utilizados em glteximage. O xoffset, yoffset e zoffset especificam o local na textura actual para começar a fazer a substituição. O tamanho da textura no argumento data é especificado pelos argumentos width, height e depth. Finalmente um conjunto final de funções permite-nos substituir uma parte de uma textura utilizando informação extraída directamente do color buffer: glcopytexsubimage1d ( int target, int level, int xoffset, int x, GLint y, int width ); glcopytexsubimage2d ( int target, int level, int xoffset, int yoffset, 80

82 int x, GLint y, int width, int height ); glcopytexsubimage3d ( int target, int level, int xoffset, int yoffset, int zoffset, int x, GLint y, int width ); Podem ter reparado que não existe uma função glcopyteximage3d, isto deve-se ao facto do color buffer ser bi-dimensional. No entanto podemos querer copiar informação do color buffer para uma face (plano?) em específico da nossa textura 3D, isso pode ser conseguido utilizando glcopytexsubimage3d. 8.2 Mapeamento de Texturas à Geometria Ao activar o mapeamento de texturas, o OpenGL permite-nos mapear qualquer textura a qualquer uma das primitivas. No entanto, é necessário fornecer ao OpenGL informação acerca de como esse mapeamento é feito, o que é conseguido especificando uma coordenada na textura (texture coordinate) para cada vértice. Os texels 1 não são especificados utilizando posições de memória, tal como nos pixmaps, mas com um sistema de coordenadas mais abstracto. As coordenadas das texturas são normalmente especificadas utilizando valores entre 0.0 e 1.0. Os nomes das coordenadas são s, t, r e q (semelhantes á coordenadas vectoriais x, y, z e w). A Figura 8.3 mostra como os texels são especificados com base em coordenadas 1D, 2D e 3D. Figura 8.3: Coordenadas dos texels numa textura O factor q representa um factor de escala da textura, à semelhança do valor w dos vértices. Ou seja, os valores das coordenadas das texturas são realmente s/q, t/q e r/q. Por omissão q=1.0. A coordenada na textura é especificada utilizando a função gltexcoord. Esta função tem um conjunto de variações para vários objectivos, à semelhança das funções em geral do OpenGL. Algumas formas simples destas funções são: gltexcoord1f ( float s); gltexcoord2f ( float s, float t); gltexcoord3f ( float s, float t, float r); A coordenada da textura é aplicada utilizando estas funções para cada um dos vértices. O OpenGL estica ou encolhe (alias stretching) a textura de forma a aplicá-la na geometria especificada com base nas coordenadas específicadas. A forma como o stretching é feito depende do filtro da textura (texture filter) actual, discutido mais à frente. A Figura 8.4(a) mostra o exemplo de ume textura bi-dimensional aplicada a um GL QUAD. Nos cantos do quad temos as coordenadas correspondentes da textura. A função gltexcoord tem que ser utilizada antes de cada chamada à função glvertex. Esta coincidência entre geometria e textura é rara. Um exemplo mais comum será o da Figura 8.4(b). As coordenadas da textura neste caso não coinicidem com a forma da geometria. 1 Um texel é um fragmento da textura, tal como o pixel de um pixmap 81

83 (a) Textura bi-dimensional aplicada a um quad (b) Textura bi-dimensional aplicada a um triângulo Figura 8.4: Aplicação de textura bi-dimensional Texture Matrix À semelhança da matriz MODELVIEW, PROJECTION e COLOR, é também possível operar transformações na matriz de coordenadas das texturas, podemos fazê-lo passando para a texture matrix: glmatrixmode ( GL2. GL_TEXTURE ); Depois desta chamada todas as transformações são operadas nas coordenadas da textura. No entanto, a stack de tranformações só tem dois níveis de profundidade, o que implica que só podemos utilizar dois glpushmatrix/glpopmatrix encadeados. 8.3 Exemplo de Textura 2D Existe um conjunto de conceitos ainda por adquirir relacionados com as texturas, tais como coordinate wrapping, texture filters e texture environment. A fim de os abordar utilizamos como plataforma um exemplo simples 2D, com configurações comuns destes parâmetros. O código fonte do exemplo Pyramid.java pode ser consultado no Apêndice C.3. Figura 8.5: Exemplo pyramid A Figura 8.5 ilustra a posição dos cantos da pirâmide. A declaração será feita no método init() do nosso GLEventListener da seguinte forma: // Cantos da Piramide ctop = new GLVector (0.0f,.80f, 0.0 f); cbackleft = new GLVector ( -0.5f, 0.0 f, -.50 f); cbackright = new GLVector (0.5 f, 0.0 f, f); cfrontright = new GLVector (0.5 f, 0.0 f, 0.5 f); cfrontleft = new GLVector ( -0.5f, 0.0 f, 0.5 f); Ainda no método init(), carregamos a imagem que irá servir para aplicar textura na nossa geometria, e activamos o TEXTURE 2D: 82

84 //... try { InputStream stream = Imaging. class. getresourceasstream (" stone. tga "); img = TGAImage. read ( stream ); bb = img. getdata (); stream. close (); catch ( IOException e) { e. printstacktrace (); gl. glteximage2d ( GL2. GL_TEXTURE_2D, 0, GL2. GL_RGB, img. getwidth (), img. getheight (), 0, img. getglformat (), GL2. GL_UNSIGNED_BYTE, bb ); // Activar as texturas gl. glenable ( GL2. GL_TEXTURE_2D ); //... A face frontal tem que ser desenhada na ordem CCW para que a nossa textura seja aplicada correctamente. Assim a ordem de desenho correcta será - ctop-cfrontleft-cfrontright. As coordenadas são especificadas de forma semelhante às da Figura 8.4(b). O código em baixo calcula o verctor normal à face frontal (vnormal), especifica as coordenadas da textura para cada vértice (gltexcoord) e desenha-o 1 : // Face da Frente vnormal = GlTools. getnormalvector ( ctop, cfrontleft, cfrontright ); gl. glnormal3fv ( vnormal. toarray (), 0); gl. gltexcoord2f (.5f, 1f); ctop. draw (); gl. gltexcoord2f (0f, 0f); cfrontleft. draw (); gl. gltexcoord2f (1f, 0f); cfrontright. draw (); O desenho das restantes faces do triângulo são feitas de forma semelhante. A Figura 8.6 mostra o output do ficheiro Pyramid.java. Figura 8.6: Output do ficheiro Pyramid.java 1 Por uma questão de conveniência a class GLVector tem um método que desenha o vector actual utilizando a função glvertex 83

85 8.4 Texture Environment No exemplo Pyramid, a pirâmide é desenhada utilizando material de cor branca e a textura é aplicada de forma que as suas cores são escaladas (scaled) segundo a cor da geometria (branca) (Figura 8.7). Figura 8.7: Geometria Branca + Texture = Shaded Texture A forma como a cor dos texels é combinada com a geometria subjacente é controlada pelo texture environment. A sua configuração é feita utilizando a função gltexenv: gltexenvi ( int target, int pname, int param ); gltexenvf ( int target, int pname, float param ); gltexenviv ( int target, int pname, IntBuffer param ); gltexenvfv ( int target, int pname, FloatBuffer param ); Esta função pode ser usada de várias formas, e permite configurar parâmetros avançados das texturas. No exemplo Pyramid, o environment mode é confiurado com o valor GL MODULATE: gl. gltexenvi ( GL2. GL_TEXTURE_ENV, GL2. GL_TEXTURE_ENV_MODE, GL2. GL_MODULATE ); Com a opção GL MODULATE, a cor do texel é multiplicada pela cor da geometria (depois do calculo das luzes). Ao especificar uma cor clara para a geometria (branca, no exemplo) a textura é afectada de forma igual à geometria. Isto permite com a mesma textura obter várias colorizações. Utilizando GL REPLACE, podemos substituir completamente a cor da geometria pela cor do texel. Isto elimina todos os efeitos aplicados à geometria subjacente. Se a textura tiver um alpha channel podemos utilizar este modo para tornar zonas da geometria transparente se a imagem contiver blocos também transparentes, activando o blending. A opção GL DECAL é semelhante à opção GL REPLACE se a imagem não tiver alpha channel. No caso de a imagem ter um alpha channel a cor da geometria transparece pela textura no valor do alpha, de forma que o objecto parece ser blended com os fragmentos subjacentes. Podemos também fazer o blending da geometria com uma cor fixa (Figura 8.8) utilizando: gl. gltexenvi ( GL2. GL_TEXTURE_ENV, GL2. GL_TEXTURE_ENV_MODE, GL2. GL_BLEND ); gl. gltexenvfv ( GL2. GL_TEXTURE_ENV, GL2. GL_ TEXTURE_ ENV_ COLOR, new float [] {1f, 0f, 0f, 0f, 0); Figura 8.8: Utilizando GL BLEND Finalmente podemos fazer a adição do valor da cor dos texels aos fragmentos da geometria, utilizando GL ADD como argumento. Os valores que ultrapassem 1.0 são truncados, o que poderá provocar saturação das cores. 84

86 8.5 Parametrização de Texturas O texturing no OpenGL envolve mais do que o simples mapeamento de uma textura num dos lados de um triângulo. Um conjunto de parâmetros afectam o compotamento e a renderização das texturas aplicadas. Estes parâmetros podem ser configurados com a função gltexparameter, utilizando uma das variantes: gltexparameterf ( int target, int pname, float param ); gltexparameteri ( int target, int pname, int param ); gltexparameterfv ( int target, int pname, FloatBuffer params ); gltexparameteriv ( int target, int pname, IntBuffer params ); O argumento target, especifica o modo da textura para o parâmetro que estamos a configurar (GL TEXTURE 1D, GL TEXTURE 1D, GL TEXTURE 3D). O parâmetro a configurar é especificado em pname e o seu valor é definido no último argumento da função (param/params) Filtering Básico Proque raramente a geometria coincide com a textura em termos de pixels (ao contrário dos pixmaps), as imagens de textura são normalmente deformadas para obedecer às coordenadas especificadas para a geometria. A imagem pode ser encolhida ou esticada, ou ambos na aplicação à geometria. O processo de cálculo dos fragmentos de cor, quando uma textura está a ser aplicada, é chamado de filtering. Podemos especificar os filtros utilizados na altura de encolher (minification) ou de esticar (magnification). Os parâmetros para a configuração destes valores são, respectivamente, GL TEXTURE MIN FILTER e GL TEXTURE MAG FILTER. Podemos especificar dois valores para este parâmetro: (a) Filtering com GL NEAREST (b) Filtering com GL LINEAR Figura 8.9: Aplicação de textura bi-dimensional GL NEAREST: Simples e rápido. São apuradas as coordenadas de cada fragmento para cada texel, a cor correspondente a essa coordenada é utilizada como a cor do fragmento da textura. A técnica de nearest neighbour é caracterizada pelo aparecimento de blocos de uma só cor, quando a geometria é aumantada (Figura 8.9(a)). Pode ser configurado utilizando: gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_TEXTURE_MAG_FILTER, GL2. GL_NEAREST ); gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_TEXTURE_MIN_FILTER, GL2. GL_NEAREST ); GL LINEAR: Requer mais processamento, mas o resultado justifica. O custo de processamento do linear filtering é, nos computadores actuais despresível. O valor da cor de cada fragmento da textura é conseguido pela interpolação linear (média ponderada) dos texels que rodeiam a sua coordenada. Pode ser configurado utilizando: gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_TEXTURE_MAG_FILTER, GL2. GL_LINEAR ); gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_TEXTURE_MIN_FILTER, GL2. GL_LINEAR ); 85

87 8.5.2 Texture Wrap Normalmente especificamos as coordenadas das texturas com valores entre 0.0 e 1.0 relativamente ao texture map. A forma como são tratados os valores que saem fora do intervalo [0.0, 1.0] é definida no parâmetro texture wrap. O valor deste parâmetro é definido individualmente para as coordenada s, t e r, utilizando a função gltexparameteri com o pname - GL TEXTURE WRAP S, GL TEXTURE WRAP T, or GL TEXTURE WRAP R. Os modos disponíveis para o wrapping são: GL REPEAT: Neste modo a textura é repetida na direcção do valor que ultrapassou o intervalo. Isto permite utilizar uma textura pequena para superfcícies grandes. Se a imagem for bem escolhida podemos dar a sensação de uma textura muito maior à custa de uma porção mais pequena. GL CLAMP: Os texels são obtidos a partir da cor borda da imagem. Esta cor é especificada no parâmetro GL TEXTURE BORDER COLOR (configurado com gltexparameterfv). GL CLAMP TO EDGE: Faz com que os valores fora da borda não sejam utilizados no cálculo da interpolação linear. GL CLAMP TO BORDER: Utiliza os valores da borda quando as coordenadas da textura caem fora do intervalo [0.0, 1.0]. A escolha do tipo de wrapping influencia o modo como o filtering funciona, principalmente quando estamos a usar GL LINEAR. Como o valor do fragmento é calculado com base na vizinhança, o cálculo junto das bordas da textura pode representar um problema se nos limitarmos a fazer clamping. O problema pode ser resolvido de forma simples quando utilizamos GL REPEAT. Os novos texels são obtidos a partir da linha/coluna adjacentes, que no repeat mode são tirados a partir do outro extremo da imagem (como se juntássemos as duas arestas opostas da imagem). Isto funciona especialmente bem quando usamos texturas em que um lado encaixa perfeitamente no outro (por ex.: esferas). Uma aplicação comum para o clamping pode ser vista no mapping de texturas que não caberiam em memória pelo seu tamanho. Em vez disso, são utilizados mosaicos. No entanto, a não utilização de GL CLAMP TO EDGE pode levar ao aparecimento de artefactos indesejados no texture mapping Mipmapping O mipmapping é uma técnica que permite melhorar a performance de renderização e a qualidade visual de uma cena. O melhoramento é feito endereçando dois problemas comuns na aplicação de textura à geometria: 1. Scintillation: Consiste de artefactos de aliasing que aparecem nas superfcícies quando os objectos são muito renderizados muito pequenos, comparados com a textura que lhes é aplicada. Este efeito é mais notório quando existe movimento na cena, ou quando o observador se encontra em movimento. 2. Performance: Uma grande quantidade de memória deve ser carregada com texturas e processada (filtering) para renderizar um conjunto limitado (ou pequeno) de fragmentos no ecrã. O que provoca um decréscimo na performance à medida que a quantidade e tamanho das texturas aumenta. Uma solução para estes dois problemas poderia passar pela utilização de uma textura mais pequenta. No entanto, quando nos aproximamos do objecto, essa textura será inevitavelmente escalada, tornando as nossas menos nítidas ou cheias de artefactos. A solução deveras eficaz passa pela utilização de mipmapping 1. O mipmapping consiste na utilização de várias imagens com diferentes tamanhos e resoluções para a mesma textura. O OpenGL utiliza então tiras das imagens para aplicar à geometria de forma apropriada e com base num novo conjunto de filtros. Isto poderá ser feito à custa de um pouco mais de memória e/ou processamento. Uma textura mipmapped consiste de um conjunto de imagens, onde cada uma é metade da anterior até que atingem o tamanho 1x1 (Figura 8.10). As imagens não precisam de ser necessariamente quadradas, neste caso quando uma coordenada chega a 1 a outra é dividida repetidamente até que chega a 1x1. A utilização de mipmapping poderá ocupar até 3 mais memória de textura que a não utilização. Os níveis de mipmap para cada imagem são especificados no segundo argumento (level) da função glteximage aquando do seu carregamento. O primeiro nível será 0, depois 1, 2, 4 e por aí fora numa base 2 x em que x é a iteração da imagem. Quando o mipmapping não está a ser utilizado, a imagem especificada no valor 0 é tomado por omissão. 1 Palavra proveniente de multum in parvo - muitas coisas num local pequeno 86

88 Figura 8.10: Conjunto de imagens Mipmapped Por omissão, para utilizar o mipmapping, temos que especificar uma imagem para cada nível de mip. Podemos, no entanto, definir qual o valor base e máximos utilizando os parâmetros GL TEXTURE BASE LEVEL e GL TEXTURE MAX LEVEL, como mostra o exemplo: gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_ TEXTURE_ BASE_ LEVEL, 0); gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_ TEXTURE_ MAX_ LEVEL, 4); Desta forma, serão apenas utilizados os níveis 0, 1, 2 e 4 de mipmapping para aplicar à nossa geometria. Podemos ainda especificar os valores mínimos e máximos de detalhe a ser utilizados alterandos os valores de GL TEXTURE MIN LOD e GL TEXTURE MAX LOD Mipmap Filtering Com o mipmapping ganhamos um novo conjunto de modos de filtering de texturas. Estes novos modos estão descritos na Tabela 8.2. Constante GL NEAREST GL LINEAR GL NEAREST MIPMAP NEAREST GL NEAREST MIPMAP LINEAR GL LINEAR MIPMAP NEAREST GL LINEAR MIPMAP LINEAR Descrição Calcular com base no vizinho mais próximo no nível de mip actual Calcular com base na interpolação linear da vizinhança no nível de mip actual Seleccionar o nível de mip mais próximo e operar filtro nearest Interpolação linear entre níveis de mip e operar filtro nearest Seleccionar o nível de mip mais próximo e operar filtragem linear Interpolação linear entre níveis de mip e operar filtragem linear (alias trilinear mipmapping) Tabela 8.2: Mipmap Filtering O simples facto de especificarmos o nível de mip na função glteximage não activa o mipmapping. Se o filtro da textura estiver configurado para GL LINEAR ou GL NEAREST, os níveis de mip 0 são ignorados. Um dos filtros de mipmapping deve ser especificado para que o mipmapping seja usado. As constantes tomam a forma GL <FILTRO> MIPMAP <SELECTOR>, onde o FILTRO especifica o tipo de filtragem operado no nível de mip seleccionado. O SELECTOR, como o nível de mip é seleccionado. Se seleccionarmos um modo de filtering que activa o mipmapping sem carregar os níveis de mip correspondente, desactivamos o mapping de texturas. A escolha do filtro depende um pouco da aplicação e dos requisitos de performance. Utilizando o filtro GL NEAREST MIPMAP NEAREST, conseguimos um desempenho melhor e um valor de scintillation reduzido, no entanto o aspecto visual final não é o mais agradável. O GL LINEAR MIPMAP NEAREST é utilizado normalmente para acelerar jogos, mantendo um aspecto visual melhorado, ainda que a seleccção do nível de mip seja feita por proximidade. A utilização de nearest para a seleccção do nível de mip, poderá também conduzir ao aparecimento de artefactos indesejados. Quando vista de uma forma obliqua, é perceptível a transição de um nível para o outro de mip. A utilização de uma selecção LINEAR (GL * MIPMAP LINEAR) permite uma interpolação adicional entre níveis para eliminar esta zona de transição, ainda que à custa de processamento adicional Geração de níveis de Mipmapping Poderiamos chamar de forma reptida a função glteximage para conseguirmos popular todos os níveis de mip. No entanto, isto pode ser uma tarefa ardua, sendo que nem sempre o developer tem acesso a todos tamanhos da 87

89 imagem da textura. A biblioteca GLU fornece um conjunto de funções que permitem convenientemente gerar os vários níveis para cada imagem. Estas funções carregam ainda a imagem automaticamente utilizando a função glteximage. As variantes da função são: glubuild1dmipmaps ( int target, int internalformat, int width, int format, int type, Buffer data ); glubuild2dmipmaps ( int target, int internalformat, int width, int height, int format, int type, Buffer data ); glubuild3dmipmaps ( int target, int internalformat, int width, int height, int depth, int format, int type, Buffer data ); A utilização destas funções é semelhante à utilização da função glteximage, no entanto, não especificamos o argumento level uma vez que os níveis de mip são gerados de forma automática. A imagem é redimensionada utilizando um box filter, que poderá não ter o mesmo efeito que utilizando um programa de desenho (como o Photoshop). Para o caso de querermos especificar o nível de mip a que uma imagem se refere 1 aquando da geração dos níveis podemos ainda utilizar: glubuild1dmipmaplevels ( int target, int internalformat, int width, int format, int type, int level, int base, int max, Buffer data ); glubuild2dmipmaplevels ( int target, int internalformat, int width, int height, int format, int type, int level, int base, int max, Buffer data ); glubuild3dmipmaplevels ( int target, int internalformat, int width, int height, int depth, int format, int type, int level, int base, int max, Buffer data ); Aqui o level especifica o nível de mip a que a imagem (data) se refere e o base e max, definem o nível mínimo e máximo de mip. Estas funções são utilizadas para gerar os níveis dentre base e max Geração de Mipmaps por Hardware Se soubermos que queremos utilizar todos os níveis de mipmapping, podemos utilizar a aceleração de hardware do OpenGL para os gerar de forma rápida. Isto é conseguido fazendo: gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_ GENERATE_ MIPMAP, GL2. GL_TRUE ); Quando o valor de GL GENERATE MIPMAP é GL TRUE, as chamadas subsequentes a glteximage e gltexsubimage que actualizam o nível 0, actualizam de forma automática todos os outros níveis 2. A utilização desta funcionalidade permite um ganho em desempenho relativamente à utilização de glubuildmipmaps. 1 Por exemplo: temos a imagem para o nível 4 de mip e estamos a gerar do 0 ao 8 2 Esta funcionalidade está disponível apenas para versões do OpenGL

90 8.5.7 Level Of Detail (LOD) Bias O OpenGL calcula o nível de mip a utilizar com base no número de níveis disponíveis no tamanho da geometria a renderizar. Podemos, no entanto, dizer ao OpenGL para polarizar o valor do seu critério (valores de mip mais baixos) ou diminuir essa polarização (valores mais altos de mip). O ajuste deste valor poderá aumentar a performance (utilizando os níveis mais baixos de mip) ou aumentar a fidelidade das nossas texturas (utilizando níveis mais altos de mip). O valor desta polarização pode ser configurado utilizando, por exemplo: gl. gltexenvf ( GL2. GL_ TEXTURE_ FILTER_ CONTROL, GL2. GL_ TEXTURE_ LOD_ BIAS, -1.5); No exemplo em cima, o detalhe das texturas é aumentado ligeiramente (nível de mip mais baixo), resultando num cenário com aspecto melhorado, ainda que à custa de processamento adicional. 8.6 Texture Objects O carregamento e gestão das texturas representam uma porção importante no desenvolvimento de qualquer aplicação 3D, tal como os jogos, em particular. As funções glteximage, gltexsubimage e glubuildmipmaps, movem grandes quantidades de memória, pelo que a troca entre texturas seria uma operação dispoendiosa, em termos de processamento. Os texture objects permitem-nos carregar mais do que um estado de textura de cada vez e trocar entre elas de forma rápida. O estado das texturas é armazenado e rotulado com um identificador inteiro. A alocação de texturas com identificadores é feita utilizando: glgentextures ( int n, IntBuffer textures ); O argumento n especifica o número de texturas que queremos armazenar e o argumento textures é um array de inteiros (IntBuffer) que irá conter os identificadores gerados. Para fazer o bind de uma textura a um destes estados fazemos: glbindtexture ( int target, int texture ); Mais uma vez o target pode tomar o valor GL TEXTURE 1D, GL TEXTURE 2D ou GL TEXTURE 3D. O argumento texture é o identificador ao qual vamos fazer o bind. O carregamentos de texturas e parametrizações subsequentes afectaram apenas o estado da textura representado pelo identificador texture. Para apagar um determinado estado utilizamos a função: gldeletetextures ( int n, IntBuffer textures ); O significado dos argumentos é o mesmo da função glbindtexture. Podemos verificar se um determinado identificador contém um estado válido utilizando a função: boolean glistexture ( int texture ); O valor de retorno da função será GL TRUE no caso de ter sido alocado um estado a este identificador. 89

91 Capítulo 9 Mapeamento de Texturas: Conceitos Avançados 9.1 Cor Secundária Antes de aplicar as texturas à geometria, o OpenGL calcula os valores individuais de cada fragmento, incluindo a componente de LIGHTING. O valor de cada fragmento é mais tarde combinado com os texels (depois do processo de filtering) dando origem à textura. Este processo diminui drásticamente a visibilidade da componente especular. A solução para este problema passa pela aplicação da componente especular da luz apenas após ter sido aplicada a textura. Esta técnica é designada de secondary specular color. Apesar de poder ser aplicada de forma manual, o OpenGL contém já um mecanismo que faz esse trabalho de forma automática. Para tal basta-nos alterar o nosso light model, da seguinte forma: gllightmodeli ( GL2. GL_ LIGHT_ MODEL_ COLOR_ CONTROL, GL2. GL_ SEPARATE_ SPECULAR_ COLOR ); As Figuras 9.1(a) e 9.1(b) mostram as diferenças sem e com a separação da componente especular. (a) Sem GL SEPARATE SPECULAR COLOR (b) Com GL SEPARATE SPECULAR COLOR Figura 9.1: Utilização de Secondary Color Para retomar o light model anterior podemos utilizar: gllightmodeli ( GL2. GL_ LIGHT_ MODEL_ COLOR_ CONTROL, GL2. GL_ COLOR_ SINGLE ); 9.2 Anisotropic Filtering Apesar de não fazer parte da espeficicação do OpenGL, a técnica de Anisotropic Filtering é suportada pela maior parte dos fabricantes. A sua utilização permite um melhoramento das operações de filtering das texturas. 90

92 No processo de filtering, o OpenGL utiliza os texels na vizinhança de uma determinada posição para fazer o sampling da textura 1. Com este processo obtemos resultados perfeitos quando a textura é vista de frente (perpendicularmente à geometria), no entanto, quando a geometria é vista de forma oblíqua podemos observar a perda de informação da imagem (como que uma desfocagem). Para evitar este efeito a área da vizinhança utilizada no filtering tem agora uma forma adequada à posição do observador (Figura 9.2). Isto implica que vários samples da imagem sejam feitos, relativamente ao observador, resultado numa imagem anisotrópica. Figura 9.2: Textura normal vs Anisotropic Filtering Podemos aplicar o anisotropic filtering a texturas básicas e mipmapped. Para tal são efectuados 3 passos: 1. Verificamos se a extensão para anisotropic filtering está disponível: GL2 gl =...; gl. isextensionavailable (" GL_ EXT_ texture_ filter_ anisotropic "); 2. Obtemos valor máximo de anisotpropia suportado: // Array temporario de saida para a funcao glgetfloatv (...) FloatBuffer out = FloatBuffer. allocate (1); gl. glgetfloatv ( GL2. GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, out ); // Valor maximo de anisotropia esta na posicao 0 de out float largest = out. get (0); 3. Finalmente definimos a quantidade de anisotropia utilizando: gl. gltexparameterf ( GL2. GL_TEXTURE_2D, GL2. GL_ TEXTURE_ MAX_ ANISOTROPY_ EXT, largest ); Quando maior o valor de anisotropia definido, maior será a quantidade de texels que são utilizados no processo de filtering. Pegando no exemplo Tunnel.java dos capítulos anteriores, as texturas serão carregadas da seguinte forma no método init(): //... // Se aflargest se mantiver a 0 nao suporta anisotropic filtering float aflargest = 0f; // Se o anisotropic filtering for suportado obtemos o valor maximo // e armazenamos em aflargest if(gl. isextensionavailable (" GL_EXT_texture_filter_anisotropic ")) { FloatBuffer out = FloatBuffer. allocate (1); gl. glgetfloatv ( GL2. GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, out ); aflargest = out. get (0); for ( int i = 0; i < texturenames. size (); i ++) { 1 Utilizando por exemplo GL NEAREST e GL LINEAR 91

93 // Fazer o bind do estado da textura ao identificador gl. glbindtexture ( GL2. GL_TEXTURE_2D, textures. get (i )); // Carregar e Ler a imagem para a nossa textura TGAImage img = loadtexture ( texturenames. get ( i )); ByteBuffer bb = img. getdata (); glu. glubuild2dmipmaps ( GL2. GL_TEXTURE_2D, GL2. GL_RGBA, img. getwidth (), img. getheight (), img. getglformat (), GL2. GL_UNSIGNED_BYTE, bb ); // Parametros da textura ( ignorar para ja) gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_ TEXTURE_ MAG_ FILTER, GL2. GL_LINEAR ); gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_ TEXTURE_ MIN_ FILTER, GL2. GL_LINEAR_MIPMAP_LINEAR ); gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_TEXTURE_WRAP_S, GL2. GL_CLAMP_TO_EDGE ); gl. gltexparameteri ( GL2. GL_TEXTURE_2D, GL2. GL_TEXTURE_WRAP_T, GL2. GL_CLAMP_TO_EDGE ); // Se aflargest for > 1f o anisotropic filtering e suportado if( aflargest > 1f) gl. gltexparameterf ( GL2. GL_TEXTURE_2D, GL2. GL_ TEXTURE_ MAX_ ANISOTROPY_ EXT, aflargest ); As Figuras 9.3(a) e 9.3(b) ilustram a diferença entre o filtering e sem e com utilização de anisotropic filtering. (a) Sem Anisotropic Filtering (b) Com Anisotropic Filtering Figura 9.3: Utilização de Anisotropic Filteing 9.3 Compressão de Texturas A indiscutível melhoria introduzida pelas texturas é normalmente acompanhada por uma quantidade importante de memória ocupada e algum overhead de processamento. No entanto, o mais preocupante é realmente o espaço ocupado (normalmente na memória gráfica). O OpenGL permite ao utilizador fazer o carregamento de texturas comprimidas 1. Os dados da textura mantém-se comprimidos na memória gráfica, o que pode representar um ganho no desempenho aquando do swapping de texturas, bem como uma menor quantidade de memória ocupada. 1 Na maior parte das implementações 92

94 As texturas carregadas não precisam de estar inicialmente comprimidas. Na altura do carregamento destas podemos solicitar a compressão ao OpenGL, alterando o internalformat para um dos valores na Tabela 9.1. Formato Comprimido GL COMPRESSED ALPHA GL COMPRESSED LUMINANCE GL COMPRESSED LUMINANCE ALPHA GL COMPRESSED INTENSITY GL COMPRESSED RGB GL COMPRESSED RGBA Formato Base GL ALPHA GL LUMINANCE GL LUMINANCE ALPHA GL INTENSITY GL RGB GL RGBA Tabela 9.1: Formatos de Texturas Comprimidas Ao utilizar os formatos de texturas comprimidos, é adicionado um ligeiro overhead no carregamento inicial das texturas. No entanto, este overhead é despresível face as melhorias na utilização da memória. Se por algum motivo a textura não for carregada com o formato comprimido solicitado, o OpenGL alterna para o formato base correspondente (Tabela 9.1). Quando utilizamos estes formatos para a compressão de texturas, o OpenGL tenta determinar a melhor forma de comprimir a textura. Podemos dizer ao OpenGL para escolher um algortimo mais rápido ou com melhor qualidade utilizando a função glhint: Método mais rápido: gl. glhint ( GL2. GL_TEXTURE_COMPRESSION_HINT, GL2. GL_FASTEST ); Método com melhor qualidade: gl. glhint ( GL2. GL_TEXTURE_COMPRESSION_HINT, GL2. GL_NICEST ); Deixar o OpenGL decidir: gl. glhint ( GL2. GL_TEXTURE_COMPRESSION_HINT, GL2. GL_DONT_CARE ); 9.4 Geração de Coordenadas de Texturas Como vimos no capítulo anterior, a atribuição das coordenadas das texturas a geometria é uma tarefa simples quando estamos a lidar com superfícies simples (triângulos, quadrados, etc... ). No entanto, para superfícies complexas, o cálculo das coordenadas correctas pode ser uma tarefa complexa. Até certo ponto, o OpenGL consegue gerar automáticamente estas coordenadas das texturas para cada vértice. Para activar/desactivar a geração das coordenadas (s, r, t e q), utilizamos as funções glenable()/gldisable() com as flags - GL TEXTURE GEN S, GL TEXTURE GEN R, GL TEXTURE GEN T e GL TEXTURE GEN Q. Quando a geração de coordenadas está activa, quaisquer chamadas subsequentes às funções gltextcoord são ignoradas. A função utilizada pelo o OpenGL para o cálculo destas coordenadas é definida utilizando uma das funções: gltexgenf ( int coord, int pname, float param ); gltexgenfv ( int coord, int pname, FloatBuffer param ); O argumento coord pode tomar um dos valores - GL S, GL T, GL R ou GL Q. O argumento pname deverá ser um de - GL TEXTURE GEN MODE, GL OBJECT PLANE ou GL EYE PLANE. O argumento param define os valores para a função utilizada no argumento pname. Para exemplificar a utilização das funções de cálculo das coordenadas foi criado o programa TexGen.java (ver Apêndice C.4). O programa permite ao utilizador alterar a função de cálculo em runtime, utilizando as teclas 1 = Object Linear, 2 = Eye Linear e 3 = Sphere Map Oject Linear Mapping Quando a função para a geração das texturas é GL OBJECT LINEAR, as coordenadas das texturas são geradas com base na seguinte função: Coord OLM = P 1 x + P 2 y + P 3 z + P 4 w 93

95 Onde x, y, z e w são as coordenadas dos vértices do objecto onde está a ser aplicada a textura e os valores P i (i = [1; 4]) são os coeficientes de uma equação do plano. Nesta caso, as coordenadas da textura são projectadas sobre a geometria, sob o ponto de vista do plano descrito pela equação. O excerto de código em baixo do programa TexGen.java, projecta as coordenadas s e t, a partir do plano z = 0: FloatBuffer zplane = FloatBuffer. wrap ( new float [] {0f, 0f, 1f, 0f ); gl. gltexgeni ( GL2.GL_S, GL2. GL_TEXTURE_GEN_MODE, GL2. GL_OBJECT_LINEAR ); gl. gltexgeni ( GL2.GL_T, GL2. GL_TEXTURE_GEN_MODE, GL2. GL_OBJECT_LINEAR ); gl. gltexgenfv ( GL2.GL_S, GL2. GL_OBJECT_PLANE, zplane ); gl. gltexgenfv ( GL2.GL_T, GL2. GL_OBJECT_PLANE, zplane ); De notar que é ainda possível definir funções diferentes para cada coordenada (neste caso s e t). Esta técnica mapeia as coordenadas da texturas em coordenadas no objecto, independentemente das tranformações em curso. O resultado final pode ser observado na Figura 9.4. Na Figura é possível observar o objecto com a textura aplicada e a textura propriamente dita. Figura 9.4: Função Object Plange Eye Linear Mapping Quando a função de geração das coordenadas é GL EYE LINEAR, as coordenadas são geradas de forma semelhante a GL OBJECT LINEAR, mas neste caso os valores de x, y, z e w referem-se agora à localização do observador. A equação do plano têm também os seus coeficientes invertidos. Coord ELM = P 1 x eye P 2 y eye P 3 z eye P 4 w eye A textura parece deslizar sobre a geometria à medida que é afectada pelas transformações geométricas. O excerto do programa TexGen.java abaixo mostra como podemos utilizar o eye linear mapping para o mesmo plano z = 0: FloatBuffer zplane = FloatBuffer. wrap ( new float [] {0f, 0f, 1f, 0f ); gl. gltexgeni ( GL2.GL_S, GL2. GL_TEXTURE_GEN_MODE, GL2. GL_EYE_LINEAR ); gl. gltexgeni ( GL2.GL_T, GL2. GL_TEXTURE_GEN_MODE, GL2. GL_EYE_LINEAR ); gl. gltexgenfv ( GL2.GL_S, GL2. GL_EYE_PLANE, zplane ); gl. gltexgenfv ( GL2.GL_T, GL2. GL_EYE_PLANE, zplane ); O resultado pode ser observado nas Figuras 9.5(a) e 9.5(b). 94

96 (a) GL EYE LINEAR (b) GL EYE LINEAR após ligeira rotação Figura 9.5: Função GL EYE LINEAR Sphere Mapping Ao utilizar o GL SPHERE MAP o OpenGL calcula as coordenadas das texturas de tal forma que ficamos com a impressão de que o objecto actual está a reflectir a textura que lhe aplicámos. O excerto do programa TexGen.java em baixo exemplifica a utilização da função sphere mapping: gl. gltexgeni ( GL2.GL_S, GL2. GL_TEXTURE_GEN_MODE, GL2. GL_SPHERE_MAP ); gl. gltexgeni ( GL2.GL_T, GL2. GL_TEXTURE_GEN_MODE, GL2. GL_SPHERE_MAP ); Para obter uma sensação de reflexão convincente, uma textura é normalmente adquirida utilizando uma lente fish-eye. Apesar de o sphere mapping ter sido substituído pelo cube mapping (Secção 9.5), ainda se encontram alguns casos de uso, na medida em que apenas uma textura é necessária, ao contrário do cube mapping onde são necessárias 6!. Se apenas queremos dar a sensação de reflexão e não realismo, o sphere mapping é uma boa escolha. Um exemplo em que o sphere mapping faz um match perfeito, é o caso das superfícies que não reflectem o ambiente de forma não espelhada, como por exemplo uma peça de metal não uniforme. No programa TexGen.java foi utilizada a imagem de fundo (constante em todos os exemplos) para aplicar na textura com a função sphere map. Quando aplicamos transformações, o torus parece reflectir o ambiente (Figura 9.6). 9.5 Cube Mapping Os últimos dois modos de geração de coordenadas são o GL REFLECTCION MAP e o GL NORMAL MAP, ambos requerem a utilização de um tipo especial de textura de ambiente (environment texture) - o cube map. A Figura 9.7 mostra a disposição das seis texturas nas faces do cube map utilizado no programa CubeMap.java (ver Apêndice C.5). Este mapa será uma aproximação das vistas (frente, trás, esquerda, direita, tecto e chão) de um cenário real. Utilizando o modo GL REFLECTION MAP, é possível criar uma reflexão bastante precisa Carregamento do Cube Map O cube mapping adiciona 6 novos valores para o primeiro argumento da função glteximage2d: GL TEXTURE CUBE MAP POSITIVE X GL TEXTURE CUBE MAP NEGATIVE X GL TEXTURE CUBE MAP POSITIVE Y GL TEXTURE CUBE MAP NEGATIVE Y 95

97 Figura 9.6: Sphere Map Figura 9.7: Cube Map do programa CubeMap.java 96

98 GL TEXTURE CUBE MAP POSITIVE Z GL TEXTURE CUBE MAP NEGATIVE Z As constantes representam a direcção no ambiente real para a textura que estamos a carregar. Por exemplo para definirmos a textura para a direcção x positiva, poderiamos utilizar a função glteximage2d da seguinte forma: TGAImage img = loadimage (" facex. tga "); glteximage2d ( GL2. GL_ TEXTURE_ CUBE_ MAP_ POSITIVE_ X, 0, img. getglformat (), img. getwidth (), img. getheight (), 0, GL_RGBA, GL_ UNSIGNED_ BYTE, img. getdata ()); O excerto de código em baixo pertence ao programa CubeMap.java, e ilustra a forma como as texturas poderiam carregadas para o cube map: // Obter os identificadores IntBuffer textures = IntBuffer. allocate ( NumTextures ); gl. glgentextures ( NumTextures, textures ); //... // Direccoes para as texuras do cubo List < String > texturenames = new ArrayList < String >(); private static final int [] CubeDirection = { GL2. GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL2. GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL2. GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL2. GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL2. GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL2. GL_TEXTURE_CUBE_MAP_NEGATIVE_Z ; //... // Texturas do Cube Map texturenames. add (" cubemap / right. tga "); texturenames. add (" cubemap / left. tga "); texturenames. add (" cubemap /up.tga "); texturenames. add (" cubemap / down. tga "); texturenames. add (" cubemap / backward. tga "); texturenames. add (" cubemap / forward. tga "); //... // Carregar as texturas do Cubo gl. glbindtexture ( GL2. GL_ TEXTURE_ CUBE_ MAP, textures. get ( CubeStartIndex )); // Parametros das texturas do cube map gl. gltexparameteri ( GL2. GL_TEXTURE_CUBE_MAP, GL2. GL_TEXTURE_MAG_FILTER, GL2. GL_LINEAR ); gl. gltexparameteri ( GL2. GL_TEXTURE_CUBE_MAP, GL2. GL_TEXTURE_MIN_FILTER, GL2. GL_LINEAR ); gl. gltexparameteri ( GL2. GL_TEXTURE_CUBE_MAP, GL2. GL_TEXTURE_WRAP_S, GL2. GL_REPEAT ); gl. gltexparameteri ( GL2. GL_TEXTURE_CUBE_MAP, GL2. GL_TEXTURE_WRAP_T, GL2. GL_REPEAT ); gl. gltexparameteri ( GL2. GL_TEXTURE_CUBE_MAP, GL2. GL_TEXTURE_WRAP_R, GL2. GL_REPEAT ); // Restantes texturas preenchem o cubo for ( int i = CubeStartIndex ; i < texturenames. size (); i ++) { // Carregar e Ler a imagem para a nossa textura TGAImage img = loadtexture ( texturenames. get ( i )); ByteBuffer bb = img. getdata (); gl. glteximage2d ( CubeDirection [ i - CubeStartIndex ], 0, GL2. GL_RGBA, img. getwidth (), img. getheight (), 0, img. getglformat (), GL2. GL_UNSIGNED_BYTE, bb ); 97

99 O valor utilizado no primeiro argumento das funções relacionadas com as texturas passa agora a ser GL TEXTURE CUBE MAP. O mesmo valor é utilizado para activar o cube mapping: gl. glenable ( GL2. GL_TEXTURE_CUBE_MAP ); No caso de GL TEXTURE CUBE MAP e GL TEXTURE 2D estarem activos simultâneamente, o cube map prevalece. De notar que a utilização do gltexparameter no cube map afecta as 6 texturas de uma só vez. Para todos os efeitos, os cube maps são tratados como texturas 3D, com coordenadas s, t e r Utilização dos Cube Maps A utilização mais comum para o cube map é a reflexão do ambiente. No exemplo CubeMap.java, a cena é capturada mudando o ponto de vista 6 vezes utilizando um field of view de 90 o. Para conseguir o efeito de reflexão com a composição das seis imagens, utilizamos: gl. gltexgeni ( GL2.GL_S, GL2. GL_TEXTURE_GEN_MODE, GL2. GL_REFLECTION_MAP ); gl. gltexgeni ( GL2.GL_T, GL2. GL_TEXTURE_GEN_MODE, GL2. GL_REFLECTION_MAP ); gl. gltexgeni ( GL2.GL_R, GL2. GL_TEXTURE_GEN_MODE, GL2. GL_REFLECTION_MAP ); Ao desenhar a nossa geometria (no exemplo um torus e uma sphere), desactivamos temporáriamente o GL TEXTURE 2D e activamos o GL TEXTURE CUBE MAP, activamos a geração das coordenadas das texturas e desenhamos a geometria normalmente. Seguidamente restauramos o estado anterior reactivando o GL TEXTURE 2D: // Desactivar temporariamente TEXTURE_ 2D gl. gldisable ( GL2. GL_TEXTURE_2D ); // Activar o Cube Map gl. glenable ( GL2. GL_TEXTURE_CUBE_MAP ); gl. glbindtexture ( GL2. GL_ TEXTURE_ CUBE_ MAP, textures. get ( CubeStartIndex )); gl. glenable ( GL2. GL_TEXTURE_GEN_S ); gl. glenable ( GL2. GL_TEXTURE_GEN_T ); gl. glenable ( GL2. GL_TEXTURE_GEN_R ); // Desenhar a Geometria que reflecte o cube map gl. gltranslatef (0,.5f, -.3f); glut. glutsolidsphere (.15, 61, 37); gl. glrotatef (( float ) Math. todegrees ( torusrot ), 0, 1f, 0); glut. glutsolidtorus (.1f,.3f, 61, 37); // Colocar tudo como estava gl. gldisable ( GL2. GL_TEXTURE_GEN_S ); gl. gldisable ( GL2. GL_TEXTURE_GEN_T ); gl. gldisable ( GL2. GL_TEXTURE_GEN_R ); gl. gldisable ( GL2. GL_TEXTURE_CUBE_MAP ); gl. glenable ( GL2. GL_TEXTURE_2D ); O output do programa CubeMap.java pode ser analisado na Figura

100 Figura 9.8: CubeMap.java 99

101 Capítulo 10 Curvas e Superfícies 10.1 Superfícies Incorporadas no OpenGL Disponíveis na biblioteca GLU 1, estão disponíveis um conjunto de funções que renderizam superfícies quádricas 2. São suportados três tipos de superfícies quádricas - esferas, cilindros e discos. Para desenhar um cone, por exemplo, podemos utilizar um cilindro, tendo um dos lados raio=0. Os discos permitem especificar um buraco no centro. A Figura 10.1 mostra algumas formas conseguidas com recurso a estas superfícies. Figura 10.1: Formas Quádricas Para conseguir formas mais complexas, podemos utilizar composições contendo as várias superfícies quádricas do OpenGL. Como por exemeplo, os eixos unitários 3D (Figura 10.2), que são construídos com a ajuda de 1 esfera, 3 cilindros e 3 cones. Figura 10.2: Eixos unitários (x, y, z) desenhados com quádricas 1 OpenGL Utility Library 2 Conjunto dos pontos do espaço tridimensional cujas coordenadas formam um polinómio de segundo grau, com um máximo três variáveis equação cartesiana da superfície 100

102 Os eixos 3D servem de auxílio ao posicionamento e à visualização no sistema de coordenadas de um modo geral. Para desenhar os eixos pode ser utilizada a função GlUtil.drawUnitAxes() fornecida na biblioteca de apoio à cadeira de Computação gráfica Configuração de Superfícies Quádricas O desenho de superfícies quádricas fornece alguma flexibilidade no que respeita a normais, coordenadas de texturas e outros parâmetros. No entanto, a colocação de todos estes parâmetros numa única função tornaria a sua utilização pouco prática. Em vez disso, é utilizada uma abordagem orientada a objectos. Um objecto quádrico é criado e os parâmetros de renderização são definidos com um conjunto de funções, como mostra o exemplo: GLU glu = new GLU (); // Criar o objecto para a superficie quadrica GLUquadric quad = glu. glunewquadric (); // Configurar parametros // Desenhar as superficies // Apagar o objecto glu. gludeletequadric ( quad ); A função GLU.gluNewQuadric() retorna um objecto do tipo GLUquadric sobre o qual vamos alterar as preferências. Depois de o objecto ser desenhado, podemos libertar o objecto anteriormente criado utilizando a função GLU.gluDeleteQuadric(). Existem quatro funções para alterar a forma com os quadrics são desenhados. A primeira função é: GLU. gluquadricdrawstyle ( GLUquadric quad, int drawstyle ); O primeiro parâmetro da função é o objecto criado previamente. O segundo parâmetro toma o valor de uma das constantes descritas na Tabela Constante GLU.GLU FILL GLU.GLU LINE GLU.GLU POINT GLU.GLU SILHOUETTE Descrição Quadrics desenhados como objectos sólidos Quadrics desenhados como wireframes Quadrics desenhados como pontos Parecido com o wireframe, mas faces adjacentes dos polígonos não são desenhadas Tabela 10.1: Estilos de Desenho dos Quadrics A função seguinte permite definir a forma como as normais são criadas para a geometria: GLU. gluquadricnormals ( GLUquadric quad, int normals ); Os valores possíveis para o parâmetro normals são: GLU NONE - superfície desenhadas sem normais GLU SMOOTH - as normais são calculadas para cada vértice, dando uma aparência suave à superfície GLU FLAT - as normais são calculadas com base no conjunto dos vértices de cada polígono (triângulo) A orientação das normais pode ser especificada com: GLU. gluquadricorientation ( GLUquadric quad, int orientation ); Neste caso, o parâmetro orientation, pode tomar um dos valores GLU OUTSIDE ou GLU INSIDE. Por omissão, os quadrics são desenhados com a face para fora (CCW). Esta função é útil para o caso de querermos alterar a face sobre a qual a luz incide, por exemplo, no interior de uma esfera especificaríamos GLU INSIDE. A última função permite activar a geração de coordenadas para a superfície: GLU. gluquadrictexture ( GLUquadric quad, boolean texture ); Neste caso quanto texture é true, é activada a geração, caso contrário é desactivada. As esferas e cilindros são embrulhados na textura, como se a textura os envolvesse. No caso dos discos, o centro da textura coincie como centro do disco e as bordas da textura coincidem com as bordas do disco. 101

103 Desenho de Superfícies Quádricas Depois de um objecto ter sido configurado de forma satisfatória, pode ser desenhado com uma única função. No caso da esfera, utilizamos: GLU. glusphere ( GLUQuadric quad, double radius, int slices, int stacks ); O argumento quad representa o nosso objecto GLUquadric previamente criado. O argumento radius define o raio da esfera. A esfera é desenhada utilizando um conjunto de triângulos 1 dispostos numa stack (pilha) desde o fundo até ao topo. O número de elementos da pilha é definido no parâmetro stacks. O parâmetro slices, define o número de triângulos (ou quads) utilizados para desenhar à volta da esfera (Figura 10.3). Os valores são semelhantes, conceptualmente, à latitude e longitude do globo terrestre. Figura 10.3: Stacks e Slices A esfera é desenhada com o centro na origem das coordenadas e com o eixo-z positivo a sair do topo da esfera. Figura 10.4: Esfera desenhada com quadrics O resultado da Figura 10.4 pode ser obtido com o código: GlUtil. drawunitaxes (); GLUquadric quad = glu. glunewquadric (); glu. gluquadricdrawstyle (quad, GLU. GLU_LINE ); glu. glusphere (quad,.75, 16, 16); glu. gludeletequadric ( quad ); O cilindro é desenhado de forma semelhante à esfera. Um conjunto de stacks são desenhadas ao longo do eixo-z positivo. A função para desenhar o cilindro é: 1 Ou quads dependendo da implementação da biblioteca GLU 102

104 GLU. glucylinder ( GLUquadric quad, double base, double top, double height, int slices, int stacks ); Com esta função especificamos o raio da base e topo (base e top), sendo a base localizada na origem. O parâmetro height define o coprimento do cilindro (Figura 10.5). Figura 10.5: Cilindro desenhado com quadrics Para desenhar um cone basta colocar o raio do topo (top) a 0 (Figura 10.6). Figura 10.6: Cone desenhado com quadrics A última superfície é o disco. Os discos são desenhados com recurso a loops de trinângulos (ou quads) dispostos por vários slices. A função utilizada para desenhar um disco é: gludisk ( GLUquadric quad, double inner, double outer, int slices, int loops ); Para desenhar o disco especificamos um raio interno (inner) e um raio exterior (outer) (Figura 10.7). Para conseguir um disco sólido, especificamos inner=0. Com um valor de inner diferente de 0 obtemos um disco com um orificio no meio. 103

105 (a) inner=0 (b) inner=0.25 Figura 10.7: Disco desenhado com quadrics O disco é desenhado no plano xy. A composição de diferentes quadrics permite a criação de objectos, tal como o exemplo Snowman.java da Figura 10.8 (ver Apêndice C.6). Figura 10.8: Snowman.java 10.2 Curvas de Bézier e Superfícies Os quadrics fornecem um meio de desenhar superfícies facilmente modeladas com equações algébricas. No entanto, para desenhar superfícies mais complexas, tais como curvas ou superfícies não lineares, onde não existe uma especificação matemática inicial, a tarefa não é trivial. Pierre Bézies, um designer da industria automóvel, reconheceu esta dificuldade e criou uma forma de desenhar curvas com recurso a um conjunto de pontos de controlo (control points). Para além da facilidade na representação das curvas, os pontos de controlo representam uma forma interactiva de mudar a forma da curva ou superfície. 104

106 Representação Paramétrica Antes de passar ao desenho de curvas, convém estabelecer algum vocabulário e relembrar alguns conceitos matemáticos. Se estivermos a pensar em linha recta, a representação no plano-xy pode ser feita com recurso à equação: y = m x + b O valor m representa a inclinação da recta, enquanto que o valor b define a coordenada y onde a recta se cruza com o eixo-y. Outra forma de representar uma curva (ou recta), consiste na parametrização das suas coordenadas em função de uma outra variável que não tem necessáriamente a ver com o sistema de coordenadas. Por exemplo, podemos especificar a forma como as coordenadas variam, ao longo do tempo (t). Assim para cada coordenada teremos uma função que varia com o tempo: x = f(t) y = g(t) z = h(t) No OpenGL, as curvas são definidas utilizando uma equação paramétrica. A curva é definida por um parâmetro u e pelo conjunto dos seus valores no domínio da curva. Para a definição de superfícies utilizamos um valor adicional v (Figura 10.9). É importante reter que os valores u e v não representam coordenadas reais da curva, são antes valores de parametrização da mesma. Desta forma, uma curva será definida com base nos seus domínios u e v 1. Figura 10.9: Representação Paramétrica de Curvas e Superfícies Pontos de Control (control points) Uma curva pode ser representada por um conjunto de pontos de controlo que determinam o comportamento da curva. O primeiro e último pontos da curva pertencem às coordenadas da curva, no entanto, os restantes pontos estão fora da curva e representam uma espécie de pontos magnéticos que atraém a curva no seu percurso (Figura 10.10). Figura 10.10: Pontos de Controlo 1 Sendo um domínio, o conjunto dos valores possíveis para um parâmetro na curva em questão 105

107 A curva da Figura 10.10b é uma curva quadrática (2 pontos de controlo) e a curva da Figura 10.10c é uma curva cúbica (3 pontos de controlo). Estas últimas são as mais utilizadas Continuidade Quando duas curvas lado-a-lado partilham um ponto (breakpoint), formam uma secção curva (Figura 10.11). A forma como as curvas se encontram define a continuidade da secção. As categorias de continuidade são: none - Quando as curvas não se encontram de todo positional (C0) - As curvas encontram-se num ponto tangetial (C1) - As curvas partilham a mesma tangente no breakpoint curvature (C2) - Para além de partilharem a mesma tangente, a aproximação à tangente é semelhante nas duas curvas Figura 10.11: Continuidade de Curvas Os tipos de continuidade mais utilizados, quando estamos a juntar um grande conjunto de curvas, são os tipo tangential e curvature Evaluators O OpenGL fornece uma forma simples de desenhar curvas e superfícies de Bézier. Para tal, especificamos os pontos de controlo e o domínio dos valores paramétrics u e v. Finalmente ao invocar o evaluator apropriado, o OpenGL gera os pontos que definem a curva ou superfície. Uma curva 2D O programa Bezier2D.java (ver Apêndice C.7), mostra como pode ser desenhada uma curva de Bézier 2D. A melhor forma de explicar o programa passa pela explicação de cada bloco de código. Começamos por definir uma perspectiva ortogonal entre +10 e -10, a fim de facilitar a visualização: gl. glmatrixmode ( GL2. GL_PROJECTION ); gl. glloadidentity (); glu. gluortho2d ( -10f, 10f, -10f, 10f); Criamos os pontos de controlo com recurso à classe GLVectorList: // Definir Pontos de Controlo ctrlpoints = new GLVectorList (); ctrlpoints. add ( -4f, 0f, 0f); // Start ctrlpoints. add ( -6f, 4f, 0f); // Control 106

108 ctrlpoints. add (6f, -4f, 0f); // Control ctrlpoints. add (4f, 0f, 0f); // End Depois de limpar o color buffer, criamos o mapping para a curva utilizando a função glmap1f: gl. glclear ( GL2. GL_COLOR_BUFFER_BIT ); float umin = 0f; // Valor minimo do u float umax = 100 f; // Valor maximo do u gl. glmap1f ( GL2. GL_ MAP1_ VERTEX_ 3, // Tipo de dados gerados umin, // Valor minimo do u umax, // Valor maximo do u 3, // Distancia entre pontos ctrlpoints. size (), // Numero de pontos de controlo ctrlpoints. tofloatbuffer () // FloatBuffer contendo pontos de controlo ); O primeiro argumento da função glmap1f define o tipo de evaluator a utilizar para gerar os vértices da linha. O segundo e terceiros argumentos definem o valor de u para o ponto inicial da curve e o valor de u para o ponto final da curva. Os pontos intermédios representam uma posição na curva 1. O terceiro argumento representa o número de elementos em cada posição do array contendo os pontos de controlo (neste caso um FloatBuffer). Para o programa Bezier2D.java, estamos a utilizar as coordenadas x, y e z, daí o valor ser 3. O quarto argumento define o número de pontos de controlo que pretendemos utilizar e finalmente o último argumento é o buffer (ou array) contendo os pontos de controlo. Por uma questão de conveniência, foi criado o método tofloatbuffer() na classe GLVectorList que devolve um FloatBuffer contendo as posições x, y e z dos vectores adicionados (via add(x, y, z)). No passo seguinte activamos o evaluator que utilizámos na função glmap1f e desenhamos os vértices gerados com a ajuda da função glevalcoord: // Activar o Evaluator gl. glenable ( GL2. GL_MAP1_VERTEX_3 ); // Desenhar os vertices da curva gl. glcolor3f (0f, 0f, 0f); gl. glbegin ( GL2. GL_LINE_STRIP ); for ( float i= umin ; i< umax ; i ++) gl. glevalcoord1f (i); gl. glend (); A fim de facilitar a compreensão dos pontos de controlo, desenhamo-los também: // Desenhar Pontos de Controlo gl. glpointsize (5.0 f); gl. glcolor3f (1f, 0f, 0f); gl. glbegin ( GL2. GL_POINTS ); for ( GLVector point : ctrlpoints ) point. draw (); gl. glend (); O resultado final do nosso programa Bezier2D pode ser visualizado na Figura Por uma questão de eficiência e a fim de tornar o código mais compacto, o OpenGL permite-nos desenhar a curva utilizando apenas as 2 funções glmapgrid e glevalmesh, de forma que o código: gl. glbegin ( GL2. GL_LINE_STRIP ); for ( float i= umin ; i< umax ; i ++) gl. glevalcoord1f (i); gl. glend (); Seria re-escrito da seguinte forma: // Mapear uma grelha de 100 pontos com u min=0 e u max =100 gl. glmapgrid1d (100, umin, umax ); // Fazer o evaluate da grelha anterior utilizando linhas ( GL_LINE ) gl. glevalmesh1 ( GL2. GL_LINE, ( int )umin, ( int ) umax ); 1 Neste caso, o valor 50 representa o ponto no meio da curva, o 25 a um quarto da curva, etc

109 Figura 10.12: Curva de Bézier 2D Superfícies 3D A forma de criar uma superfície de Bézier é muito semelhante à criação das curvas. Adicionamos apenas o parâmetro v que corresponde a um segundo domínio. O código completo do exemplo seguinte pode ser consultado no Apêndice C.8 referente ao programa Bezier3D.java. A diferença, à partida, em relação ao exemplo Bezier2D, é que neste utilizamos 3 conjuntos de 3 pontos de controlo cada. Começamos então por definir os pontos de controlo, 3 na direcção de u por 3 na direcção de v: // Definir Pontos de Controlo ctrlpoints = new GLVectorList (); // v0 ctrlpoints. add ( -4f, 0f, 4f); // Start (u0) ctrlpoints. add ( -2f, 4f, 4f); // Control (u0) ctrlpoints. add (4f, 0f, 4f); // End (u0) // v1 ctrlpoints. add ( -4f, 0f, 0f); // Start (u1) ctrlpoints. add ( -2f, 4f, 0f); // Control (u1) ctrlpoints. add (4f, 0f, 0f); // End (u1) // v2 ctrlpoints. add ( -4f, 0f, -4f); // Start (u2) ctrlpoints. add ( -2f, 4f, -4f); // Control (u2) ctrlpoints. add (4f, 0f, -4f); // End (u2) Seguidamente geramos o mapa bidmimensional de pontos para a superfície, utilizando a função glmap2f com o primeiro argumento tendo o valor GL2.GL MAP2 VERTEX 3, em vez da função glmap1f, da seguinte forma: float umin = 0f; // Valor minimo do u float umax = 10 f; // Valor maximo do u float vmin = 0f; // Valor minimo do v float vmax = 10 f; // Valor maximo do v gl. glmap2f ( GL2. GL_ MAP2_ VERTEX_ 3, // Tipo de dados gerados umin, // Valor minimo do u umax, // Valor maximo do u 108

110 ); 3, // Distancia entre pontos ( dominio u) 3, // Numero de pontos de controlo ( dominio u) vmin, // Valor minimo do v vmax, // Valor maximo do v 9, // Distancia entre pontos ( dominio v) 3, // Numero de pontos de controlo ( dominio v) ctrlpoints. tofloatbuffer () // FloatBuffer contendo pontos de controlo O segundo e terceiro argumentos definem os valores mínimo e máximo no domínio u. O quarto e quinto argumentos definem, respectivamente, o intervalo entre os pontos do domínio u no buffer de dados e o número de pontos de controlo. O intervalo de dados para u é de 3 pela mesma razão do exemplo anterior. O número de pontos de controlo ao longo de u é de 3. O sexto e sétimo argumentos representam o valor mínimo e máximo do domínio v. O oitávo e nono argumentos representam, respectivamente, o intervalo entre os pontos no domínio v e o número de pontos de controlo. O intervalo no caso do domínio v é de 9, uma vez que para cada iteração de v existem 3 pontos em u (3 3 = 9). O número de pontos de controlo ao longo de v é igualmente de 3. O último argumento é o FloatBuffer contendo os pontos de controlo. Finalmente podemos desenhar a nossa superfície de forma semelhante à utilizada para o exemplo anterior: // Desenhar os vertices da superficie gl. glcolor3f (0f, 0f, 0f); // Mapear uma grelha de pontos com u entre u min e u max e v entre v min e v max gl. glmapgrid2d (10, umin, umax, 10, vmin, vmax ); // Fazer o evaluate da grelha anterior utilizando linhas gl. glevalmesh2 ( GL2. GL_LINE, ( int )umin, ( int )umax, ( int )vmin, ( int ) vmax ); O resultado final do programa Bezier3D pode ser analisado na Figura Figura 10.13: Superfície 3D de Bézier Luzes e Vectores Normais A fim de utilizar luzes com as nossas superfícies basta-nos substituir o código: gl. glevalmesh2 ( GL2. GL_LINE, ( int )umin, ( int )umax, ( int )vmin, ( int ) vmax ); Pelo código: gl. glevalmesh2 ( GL2. GL_FILL, ( int )umin, ( int )umax, ( int )vmin, ( int ) vmax ); gl. glenable ( GL2. GL_AUTO_NORMAL ); O que produz o resultado da Figura 10.14, que pode ser conseguido correndo o programa BezierLighting.java (ver Apêndice C.9). 109

111 Figura 10.14: Superfície de Bézier com Lighting 110

OpenGL. http://www.opengl.org. Alberto B. Raposo

OpenGL. http://www.opengl.org. Alberto B. Raposo OpenGL http://www.opengl.org Alberto B. Raposo OpenGL: o que é? API Interface para programador de aplicação Aplicação API abstrata API Hardware & Software Dispositivo de saída Dispositivo de entrada Por

Leia mais

INTRODUÇÃO A OPENGL. Computação Gráfica

INTRODUÇÃO A OPENGL. Computação Gráfica INTRODUÇÃO A OPENGL Computação Gráfica OpenGL (Open Graphic Library) Biblioteca de rotinas gráficas e de modelagem, bi e tridimensional, extremamente portável e rápida. Não é uma linguagem de programação,

Leia mais

Prof. Fernando V. Paulovich http://www.icmc.usp.br/~paulovic paulovic@icmc.usp.br. 3 de maio de 2011. SCC0250 - Computação Gráca

Prof. Fernando V. Paulovich http://www.icmc.usp.br/~paulovic paulovic@icmc.usp.br. 3 de maio de 2011. SCC0250 - Computação Gráca Introdução à Opengl com Java SCC0250 - Computação Gráca Prof. Fernando V. Paulovich http://www.icmc.usp.br/~paulovic paulovic@icmc.usp.br Instituto de Ciências Matemáticas e de Computação (ICMC) Universidade

Leia mais

Pipeline de Visualização Câmara Virtual

Pipeline de Visualização Câmara Virtual Pipeline de Visualização Câmara Virtual Edward Angel, Cap. 5 Instituto Superior Técnico Computação Gráfica 2009/2010 1 Na última aula... Transformações Geométricas Composição de Transformações Deformação

Leia mais

CG com OpenGL. Paulo Gandra de Sousa Sistemas Gráficos e Interactivos Instituto Superior de Engenharia do Porto

CG com OpenGL. Paulo Gandra de Sousa Sistemas Gráficos e Interactivos Instituto Superior de Engenharia do Porto CG com OpenGL Paulo Gandra de Sousa psousa@dei.isep.ipp.pt Sistemas Gráficos e Interactivos Instituto Superior de Engenharia do Porto Conteúdo O que é? Exemplos API do OpenGL demos Desenho, iluminação,

Leia mais

Introdução a Prática em OpenGL

Introdução a Prática em OpenGL Introdução a Prática em OpenGL Universidade de São Paulo USP Disciplina de Computação Gráfica Profª Maria Cristina PAE: Thiago Silva Reis Santos Agosto de 2010 Sumário Bibliotecas Necessárias Instalação

Leia mais

Atividade: matrizes e imagens digitais

Atividade: matrizes e imagens digitais Atividade: matrizes e imagens digitais Aluno(a): Turma: Professor(a): Parte 01 MÓDULO: MATRIZES E IMAGENS BINÁRIAS 1 2 3 4 5 6 7 8 Indique, na tabela abaixo, as respostas dos 8 desafios do Jogo dos Índices

Leia mais

GeoMafra Portal Geográfico

GeoMafra Portal Geográfico GeoMafra Portal Geográfico Nova versão do site GeoMafra Toda a informação municipal... à distância de um clique! O projecto GeoMafra constitui uma ferramenta de trabalho que visa melhorar e homogeneizar

Leia mais

Introdução à Programação em OpenGL. Prof. Márcio Bueno {cgtarde,cgnoite}@marciobueno.com

Introdução à Programação em OpenGL. Prof. Márcio Bueno {cgtarde,cgnoite}@marciobueno.com Introdução à Programação em OpenGL Prof. Márcio Bueno {cgtarde,cgnoite}@marciobueno.com OPENGL (Open Graphical Library) OpenGL é uma interface de software (API Aplication Program Interface) para aceleração

Leia mais

Imagem e Gráficos. vetorial ou raster?

Imagem e Gráficos. vetorial ou raster? http://computacaografica.ic.uff.br/conteudocap1.html Imagem e Gráficos vetorial ou raster? UFF Computação Visual tem pelo menos 3 grades divisões: CG ou SI, AI e OI Diferença entre as áreas relacionadas

Leia mais

OpenGL. Uma Abordagem Prática e Objetiva. Marcelo Cohen Isabel Harb Manssour. Novatec Editora

OpenGL. Uma Abordagem Prática e Objetiva. Marcelo Cohen Isabel Harb Manssour. Novatec Editora OpenGL Uma Abordagem Prática e Objetiva Marcelo Cohen Isabel Harb Manssour Novatec Editora Capítulo 1 Introdução A Computação Gráfica é uma área da Ciência da Computação que se dedica ao estudo e ao desenvolvimento

Leia mais

Trabalho Prático n. 2

Trabalho Prático n. 2 Trabalho Prático n. 2 Programação com Quadtrees Métodos de Programação I 2003/04 Preâmbulo Este trabalho prático é constituído por duas secções. A primeira contém questões obrigatórias, e a segunda questões

Leia mais

Projeções e Visualização

Projeções e Visualização Computação Gráfica 5385: Licenciatura em Engenharia Informática Cap. 4 Projeções e Visualização Projeções e Visualização Sumário Pipeline de Visualização em OpenGL x y z w vértice original MODELVIEW matrix

Leia mais

Manual Processamento de Imagem. João L. Vilaça

Manual Processamento de Imagem. João L. Vilaça Manual Processamento de Imagem João L. Vilaça Versão 1.0 31/1/2014 Índice 1. Sistema de eixo e movimentos possíveis do Drone... 3 2. Imagem... 3 3. Espaços de cor... 4 4.1 RGB... 5 4.2HSV... 5 4.3 GRAY...

Leia mais

1º Teste Computação Gráfica

1º Teste Computação Gráfica 1º Teste Computação Gráfica LEIC-Tagus/LERCI Prof. Mário Rui Gomes Prof. João Brisson Lopes 23 de Abril de 25 Nº Nome: Responda às questões seguintes justificando adequadamente todas as respostas. O Teste

Leia mais

Optimização de um Mundo Virtual

Optimização de um Mundo Virtual secção 3.2 Optimização de um Mundo Virtual Dadas as limitações impostas pela actual tecnologia, um mundo virtual que não seja cuidadosamente optimizado torna-se necessariamente demasiado lento para captar

Leia mais

Paulo Sérgio Rodrigues. Exercícios de Laboratório

Paulo Sérgio Rodrigues. Exercícios de Laboratório Paulo Sérgio Rodrigues Exercícios de Laboratório Iluminação São Bernardo do Campo, SP Abril de 2010 Iluminação Como é possível observar na Fig. 1, a imagem gerada não possui uma qualidade satisfatória.

Leia mais

6. Geometria, Primitivas e Transformações 3D

6. Geometria, Primitivas e Transformações 3D 6. Geometria, Primitivas e Transformações 3D Até agora estudamos e implementamos um conjunto de ferramentas básicas que nos permitem modelar, ou representar objetos bi-dimensionais em um sistema também

Leia mais

Ferramentas Web, Web 2.0 e Software Livre em EVT

Ferramentas Web, Web 2.0 e Software Livre em EVT E s t u d o s o b r e a i n t e g r a ç ã o d e f e r r a m e n t a s d i g i t a i s n o c u r r í c u l o d a d i s c i p l i n a d e E d u c a ç ã o V i s u a l e T e c n o l ó g i c a Anim8or M a n

Leia mais

Representação de Imagens

Representação de Imagens Representação de Imagens Primitivas Gráficas As primitivas gráficas são os elementos básicos que formam um desenho. Exemplos: Ponto, segmento, polilinha, polígono, arco de elipse, etc. Primitivas já definidas

Leia mais

Computação Gráfica - OpenGl 02

Computação Gráfica - OpenGl 02 Universidade Federal do Vale do São Francisco Curso de Engenharia da Computação Computação Gráfica - OpenGl 02 Prof. Jorge Cavalcanti jorge.cavalcanti@univasf.edu.br www.univasf.edu.br/~jorge.cavalcanti

Leia mais

TIPOS DE REFLEXÃO Regular Difusa

TIPOS DE REFLEXÃO Regular Difusa Reflexão da luz TIPOS DE REFLEXÃO Regular Difusa LEIS DA REFLEXÃO RI = raio de luz incidente i normal r RR = raio de luz refletido i = ângulo de incidência (é formado entre RI e N) r = ângulo de reflexão

Leia mais

Periféricos e Interfaces Ano lectivo 2003/2004 Docente: Ana Paula Costa. Aula Teórica 20

Periféricos e Interfaces Ano lectivo 2003/2004 Docente: Ana Paula Costa. Aula Teórica 20 Sumário: Os subsistemas vídeo. A RAM vídeo. Aula Teórica 20 Leitura Recomendada: Capítulo 37 - Hans-Peter Messmer, The Indispensable PC Hardware Book, Addison-Wesley. Capítulos 4 e 11 - Peter Norton, Peter

Leia mais

Módulo III. Folhas de Cálculo

Módulo III. Folhas de Cálculo Módulo III Ferramentas do Office Folhas de Cálculo Ferramentas de produtividade 1 Folhas de Cálculo O que é: Uma Folha de Cálculo é, por tradição, um conjunto de células que formam uma grelha ou tabela

Leia mais

Computação Gráfica 3D Studio Max 2008.1 www.damasceno.info Prof.: Luiz Gonzaga Damasceno

Computação Gráfica 3D Studio Max 2008.1 www.damasceno.info Prof.: Luiz Gonzaga Damasceno 10 Iluminação e Sombras Lembre-se que iluminar é estabelecer uma relação entre luz e sombras. Se o ambiente estiver muito claro pode destruir áreas importantes de sombras. Este Tutorial mostra como simular

Leia mais

GeoMafra SIG Municipal

GeoMafra SIG Municipal GeoMafra SIG Municipal Nova versão do site GeoMafra Toda a informação municipal... à distância de um clique! O projecto GeoMafra constitui uma ferramenta de trabalho que visa melhorar e homogeneizar a

Leia mais

Computação Gráfica. 5385: Licenciatura em Engenharia Informática. Cap. 3 Janelas e Visores. Janelas e Visores

Computação Gráfica. 5385: Licenciatura em Engenharia Informática. Cap. 3 Janelas e Visores. Janelas e Visores Computação Gráfica 5385: Licenciatura em Engenharia Informática Cap. 3 Janelas e Visores Janelas e Visores Sumário Definições domínio de imagem (ecrã) janela de ecrã domínio da cena (IR 2 ) janela visor

Leia mais

OpenGL. Sumário COMPUTAÇÃO GRÁFICA E INTERFACES. Introdução. Introdução. Carlos Carreto

OpenGL. Sumário COMPUTAÇÃO GRÁFICA E INTERFACES. Introdução. Introdução. Carlos Carreto Sumário COMPUTAÇÃO GRÁFICA E INTERFACES OpenGL Carlos Carreto Curso de Engenharia Informática Ano lectivo 2003/2004 Escola Superior de Tecnologia e Gestão da Guarda Introdução Utilização Tipos de dados

Leia mais

Orientação a Objetos

Orientação a Objetos 1. Domínio e Aplicação Orientação a Objetos Um domínio é composto pelas entidades, informações e processos relacionados a um determinado contexto. Uma aplicação pode ser desenvolvida para automatizar ou

Leia mais

Visão humana. Guillermo Cámara-Chávez

Visão humana. Guillermo Cámara-Chávez Visão humana Guillermo Cámara-Chávez Cor e visão humana Como uma imagem é formada? Uma imagem é formada a partir da quantidade de luz refletida ou emitida pelo objeto observado. Cor e visão humana Cor

Leia mais

Enquadramento e Conceitos Fundamentais

Enquadramento e Conceitos Fundamentais Licenciatura em Engenharia Informática e de Computadores Computação Gráfica Enquadramento e Conceitos Fundamentais Edward Angel, Cap. 1 Questão 9, exame de 29/06/11 [0.5v] Identifique e descreva os três

Leia mais

ZS Rest. Manual Profissional. BackOffice Mapa de Mesas. v2011

ZS Rest. Manual Profissional. BackOffice Mapa de Mesas. v2011 Manual Profissional BackOffice Mapa de Mesas v2011 1 1. Índice 2. Introdução... 2 3. Iniciar ZSRest Backoffice... 3 4. Confirmar desenho de mesas... 4 b) Activar mapa de mesas... 4 c) Zonas... 4 5. Desenhar

Leia mais

Roteiro 23 Difração e Interferência de ondas bidimensionais num meio líquido

Roteiro 23 Difração e Interferência de ondas bidimensionais num meio líquido Roteiro 23 Difração e Interferência de ondas bidimensionais num meio líquido 1 INTRODUÇÃO As ondas podem sofrer o efeito de diversos fenômenos, dentre eles estão a difração e a interferência. A difração

Leia mais

Múltiplos Estágios processo com três estágios Inquérito de Satisfação Fase II

Múltiplos Estágios processo com três estágios Inquérito de Satisfação Fase II O seguinte exercício contempla um processo com três estágios. Baseia-se no Inquérito de Satisfação Fase II, sendo, por isso, essencial compreender primeiro o problema antes de começar o tutorial. 1 1.

Leia mais

Luz e Cor. Sistemas Gráficos/ Computação Gráfica e Interfaces FACULDADE DE ENGENHARIA DA UNIVERSIDADE DO PORTO

Luz e Cor. Sistemas Gráficos/ Computação Gráfica e Interfaces FACULDADE DE ENGENHARIA DA UNIVERSIDADE DO PORTO Luz e Cor Sistemas Gráficos/ Computação Gráfica e Interfaces 1 Luz Cromática Em termos perceptivos avaliamos a luz cromática pelas seguintes quantidades: 1. Matiz (Hue): distingue entre as várias cores

Leia mais

COMPUTAÇÃO GRÁFICA REPRESENTAÇÃO DE IMAGENS

COMPUTAÇÃO GRÁFICA REPRESENTAÇÃO DE IMAGENS COMPUTAÇÃO GRÁFICA REPRESENTAÇÃO DE IMAGENS Curso: Tecnológico em Análise e Desenvolvimento de Sistemas Disciplina: COMPUTAÇÃO GRÁFICA 4º Semestre Prof. AFONSO MADEIRA ARQUITETURA GRÁFICA Frame-buffer

Leia mais

Copiright de todos artigos, textos, desenhos e lições. A reprodução parcial ou total desta aula só é permitida através de autorização por escrito de

Copiright de todos artigos, textos, desenhos e lições. A reprodução parcial ou total desta aula só é permitida através de autorização por escrito de 1 No início do nível intermediário, falamos brevemente sobre a perspectiva e a aplicação de alguns dos seus elementos, como o ponto de fuga, a linha de horizonte e a relação dos objetos com o olho do observador.

Leia mais

De seguida vamos importar a imagem da lupa File > Import e abrir a imagem Lupa.png que está no Cd-rom.

De seguida vamos importar a imagem da lupa File > Import e abrir a imagem Lupa.png que está no Cd-rom. LUPA Introdução A base que está por detrás deste tutorial são duas imagens, uma com 50% do tamanho original colocada numa layer e outra imagem com o tamanho original colocada numa Mask layer dentro de

Leia mais

Frederico Damasceno Bortoloti. Adaptado de: Claudio Esperança Paulo Roma Cavalcanti

Frederico Damasceno Bortoloti. Adaptado de: Claudio Esperança Paulo Roma Cavalcanti Fundamentos de Representação Gráfica Frederico Damasceno Bortoloti Adaptado de: Claudio Esperança Paulo Roma Cavalcanti Estrutura do Curso Avaliação através de Prova Estudo / Seminário Nota parcial NP

Leia mais

MÓDULO 9. A luz branca, que é a luz emitida pelo Sol, pode ser decomposta em sete cores principais:

MÓDULO 9. A luz branca, que é a luz emitida pelo Sol, pode ser decomposta em sete cores principais: A COR DE UM CORPO MÓDULO 9 A luz branca, que é a luz emitida pelo Sol, pode ser decomposta em sete cores principais: luz branca vermelho alaranjado amarelo verde azul anil violeta A cor que um corpo iluminado

Leia mais

2º Exame Computação Gráfica

2º Exame Computação Gráfica 2º Exame Computação Gráfica LEIC-T Prof. Mário Rui Gomes 17 de Julho 2007 Nº Nome: Antes de começar: Identifique todas as folhas com o seu número. Responda às questões seguintes justificando adequadamente

Leia mais

Curso de Computação Gráfica (CG) 2014/2- Unidade 1- Modelagem de objetos. Exercício 1 (individual) - Entrega: quarta 13/08

Curso de Computação Gráfica (CG) 2014/2- Unidade 1- Modelagem de objetos. Exercício 1 (individual) - Entrega: quarta 13/08 Curso de Computação Gráfica (CG) 2014/2- Unidade 1- Modelagem de objetos Exercício 1 (individual) - Entrega: quarta 13/08 Escolha um objeto entre os que possivelmente compõem uma clínica médica de exames

Leia mais

INTRODUÇÃO À TRIDIMENSIONALIDADE Step by step Maja`s House 16 11 2015

INTRODUÇÃO À TRIDIMENSIONALIDADE Step by step Maja`s House 16 11 2015 INTRODUÇÃO À TRIDIMENSIONALIDADE Step by step Maja`s House 16 11 2015 PARTE II: luminação. Visualizações realistas (renders). ILUMINAÇÃO Por omissão, o AutoCAD ilumina o desenho 3D com duas luzes distantes

Leia mais

SSS Slide Show System

SSS Slide Show System SSS Slide Show System Licenciatura em Ciências da Computação Programação Imperativa 2009 Segundo Projecto Versão de 21 de Março de 2009 Alberto Simões José C. Ramalho Instruções Este projecto deve ser

Leia mais

AULA 6 - Operações Espaciais

AULA 6 - Operações Espaciais 6.1 AULA 6 - Operações Espaciais Essa aula descreve as operações espaciais disponíveis no TerraView. Antes de iniciar sua descrição é necessário importar alguns dados que serão usados nos exemplos. Exercício:

Leia mais

Laboratório de Sistemas e Sinais L1: Matrizes, Sons e Imagens

Laboratório de Sistemas e Sinais L1: Matrizes, Sons e Imagens Laboratório de Sistemas e Sinais L1: Matrizes, Sons e Imagens Luís Caldas de Oliveira Março de 2009 O objectivo deste laboratório é o de explorar a utilização de matrizes em Matlab e de usá-las para construir

Leia mais

Desenho e Apresentação de Imagens por Computador

Desenho e Apresentação de Imagens por Computador Desenho e Apresentação de Imagens por Computador Conteúdo s: Aspetos genéricos sobre o trabalho com imagens computacionais. Imagens computacionais e programas que criam ou manipulam esse tipo de imagens.

Leia mais

Como Começar? Criação Páginas. Etapas. Apresentação INTERNET

Como Começar? Criação Páginas. Etapas. Apresentação INTERNET Como Começar? Criação Páginas Apresentação Etapas Como começar Para que um site tenha sucesso é necessário um correcto planeamento do mesmo. Todos os aspectos de desenho de um site devem ser pensados de

Leia mais

Utilização do SOLVER do EXCEL

Utilização do SOLVER do EXCEL Utilização do SOLVER do EXCEL 1 Utilização do SOLVER do EXCEL José Fernando Oliveira DEEC FACULDADE DE ENGENHARIA DA UNIVERSIDADE DO PORTO MAIO 1998 Para ilustrar a utilização do Solver na resolução de

Leia mais

Centro de Competência Entre Mar e Serra. Guia

Centro de Competência Entre Mar e Serra. Guia SMART Notebook Software Guia O Software Notebook permite criar, organizar e guardar notas num quadro interactivo SMART Board (em modo projectado e não-projectado), num computador pessoal e, em seguida,

Leia mais

Prof. Fernando V. Paulovich http://www.icmc.usp.br/~paulovic paulovic@icmc.usp.br. 3 de maio de 2011. SCC0250 - Computação Gráca

Prof. Fernando V. Paulovich http://www.icmc.usp.br/~paulovic paulovic@icmc.usp.br. 3 de maio de 2011. SCC0250 - Computação Gráca Transformações Geométricas 3D SCC0250 - Computação Gráca Prof. Fernando V. Paulovich http://www.icmc.usp.br/~paulovic paulovic@icmc.usp.br Instituto de Ciências Matemáticas e de Computação (ICMC) Universidade

Leia mais

REFLEXÃO DA LUZ: ESPELHOS 412EE TEORIA

REFLEXÃO DA LUZ: ESPELHOS 412EE TEORIA 1 TEORIA 1 DEFININDO ESPELHOS PLANOS Podemos definir espelhos planos como toda superfície plana e polida, portanto, regular, capaz de refletir a luz nela incidente (Figura 1). Figura 1: Reflexão regular

Leia mais

1. Criem um novo documento no Flash MX 2004. Atribuam as dimensões do filme, Width e Height para 300 e 200.

1. Criem um novo documento no Flash MX 2004. Atribuam as dimensões do filme, Width e Height para 300 e 200. Timeline Effects Uma das evoluções que se denotam logo à partida no Flash MX 2004, são os efeitos da timeline. Os efeitos da timeline são uma colecção de efeitos especiais que podem ser personalizados

Leia mais

ICORLI. INSTALAÇÃO, CONFIGURAÇÃO e OPERAÇÃO EM REDES LOCAIS e INTERNET

ICORLI. INSTALAÇÃO, CONFIGURAÇÃO e OPERAÇÃO EM REDES LOCAIS e INTERNET INSTALAÇÃO, CONFIGURAÇÃO e OPERAÇÃO EM REDES LOCAIS e INTERNET 2010/2011 1 Protocolo TCP/IP É um padrão de comunicação entre diferentes computadores e diferentes sistemas operativos. Cada computador deve

Leia mais

MICROSOFT POWERPOINT

MICROSOFT POWERPOINT MICROSOFT POWERPOINT CRIAÇÃO DE APRESENTAÇÕES. O QUE É O POWERPOINT? O Microsoft PowerPoint é uma aplicação que permite a criação de slides de ecrã, com cores, imagens, e objectos de outras aplicações,

Leia mais

O mundo à nossa volta é povoado de formas as mais variadas tanto nos elementos da natureza como nos de objetos construídos pelo homem.

O mundo à nossa volta é povoado de formas as mais variadas tanto nos elementos da natureza como nos de objetos construídos pelo homem. TRIDIMENSIONALIDADE O mundo à nossa volta é povoado de formas as mais variadas tanto nos elementos da natureza como nos de objetos construídos pelo homem. As formas tridimensionais são aquelas que têm

Leia mais

Que imagens têm ou não têm simetria?

Que imagens têm ou não têm simetria? O mundo da simetria Que imagens têm ou não têm simetria? Isometrias Isometria: Transformação geométrica que preserva as distâncias; as figuras do plano são transformadas noutras geometricamente iguais.

Leia mais

Iluminação e sombreamento

Iluminação e sombreamento OpenGL Iluminação e sombreamento Sombreamento OpenGL calcula a cor de cada pixel e parte disso depende de qual é a iluminação usada no cenário e de como os objetos no cenário refletem ou absorvem a luz

Leia mais

GDC I AULA TEÓRICA 09

GDC I AULA TEÓRICA 09 GDC I AULA TEÓRICA 09 Perspectiva linear de quadro plano: - O perspectógrafo completo (Plano Geometral e a Linha de Terra). - A marcação de pontos por coordenadas. - Determinação dos traços de planos e

Leia mais

Nosso objetivo será mostrar como obter informações qualitativas sobre a refração da luz em um sistema óptico cilíndrico.

Nosso objetivo será mostrar como obter informações qualitativas sobre a refração da luz em um sistema óptico cilíndrico. Introdução Nosso objetivo será mostrar como obter informações qualitativas sobre a refração da luz em um sistema óptico cilíndrico. A confecção do experimento permitirá também a observação da dispersão

Leia mais

Realidade Aumentada. Introdução. Sumário da Apresentação. Realidade Aumentada 28/08/2013. Prof. Sementille 1

Realidade Aumentada. Introdução. Sumário da Apresentação. Realidade Aumentada 28/08/2013. Prof. Sementille 1 Realidade Aumentada 2. Ferramentas para Desenvolvimento de Aplicações de Realidade Aumentada Prof. Dr. Antonio Carlos Sementille Sumário da Apresentação Visão geral da hierarquia das principais ferramentas

Leia mais

Dispositivos de Entrada e Saída

Dispositivos de Entrada e Saída Dispositivos de Entrada e Saída Prof. Márcio Bueno {cgtarde,cgnoite}@marciobueno.com Fonte: Material do Prof. Robson Pequeno de Sousa e do Prof. Robson Lins Dispositivos de Entrada Teclado, Mouse, Trackball,

Leia mais

CorelDRAW 11 1. UM PROGRAMA DE DESIGN

CorelDRAW 11 1. UM PROGRAMA DE DESIGN CorelDRAW 11 1. UM PROGRAMA DE DESIGN Com o Corel você vai trabalhar com um dos aplicativos mais usados no campo do design e da auto-edição, já que permite operar com dois tipos de gráficos (vetoriais

Leia mais

Entendendo o Astigmatismo. Introdução. Lentes especiais sem astigmatismo MAS450/854. 9 de março de 2003

Entendendo o Astigmatismo. Introdução. Lentes especiais sem astigmatismo MAS450/854. 9 de março de 2003 Entendendo o Astigmatismo MAS450/854 Primavera 2003 9 de março de 2003 Introdução Lentes especiais sem astigmatismo Lentes cilíndricas cruzadas com astigmatismo o Foco horizontal o Foco vertical o Plano

Leia mais

Interrupções. As interrupções são casos especiais de chamadas de procedimentos.

Interrupções. As interrupções são casos especiais de chamadas de procedimentos. Interrupções Uma interrupção é equivalente a uma chamada de procedimento. A chamada é equivalente a um CALL gerado pela execução de uma instrução. As interrupções são casos especiais de chamadas de procedimentos.

Leia mais

www.educandusweb.com.br

www.educandusweb.com.br Sistema Terra-Lua-Sol Índice 1. Introdução... 3 2. Simulador... 3 2.1 Painel Principal... 3 O que ocorreu com dimensões e distâncias dos corpos estudados?... 5 2.2 Visualização - Wireframe/Texturizada...

Leia mais

PROGRAMAÇÃO ESTRUTURADA. CC 2º Período

PROGRAMAÇÃO ESTRUTURADA. CC 2º Período PROGRAMAÇÃO ESTRUTURADA CC 2º Período PROGRAMAÇÃO ESTRUTURADA Aula 06: Ponteiros Declarando e utilizando ponteiros Ponteiros e vetores Inicializando ponteiros Ponteiros para Ponteiros Cuidados a serem

Leia mais

Sistemas de numeração

Sistemas de numeração E Sistemas de numeração Aqui estão apenas números ratificados. William Shakespeare A natureza tem algum tipo de sistema de coordenadas geométrico-aritmético, porque a natureza tem todos os tipos de modelos.

Leia mais

8. Síntese de Imagens: Cálculo de Cor

8. Síntese de Imagens: Cálculo de Cor 8. Síntese de Imagens: Cálculo de Cor O processo de determinar a aparência (ou seja, a textura e a cor) das superfícies visíveis é chamado de shading. Essa aparência da superfície depende das propriedades

Leia mais

Comandos Complementares

Comandos Complementares Comandos Complementares Nesta parte do curso vou apresentar comandos que geralmente não são ensinados em cursos rápidos porém são fáceis de se aprender e vão facilitar bastante o uso do CAD. Dist Esse

Leia mais

Lista de Revisão Óptica na UECE e na Unifor Professor Vasco Vasconcelos

Lista de Revisão Óptica na UECE e na Unifor Professor Vasco Vasconcelos Lista de Revisão Óptica na UECE e na Unifor Professor Vasco Vasconcelos 0. (Unifor-998. CE) Um objeto luminoso está inicialmente parado a uma distância d de um espelho plano fixo. O objeto inicia um movimento

Leia mais

Animação e Visualização Tridimensional

Animação e Visualização Tridimensional Animação e Visualização Tridimensional Mestrado em Engenharia Informática e de Computadores Alameda º mini-teste 22 de Outubro de 204 O mini-teste tem a duração máxima de 45 minutos, tolerância incluída.

Leia mais

AMBIENT REFLECTIVE OCCLUSION SHADER

AMBIENT REFLECTIVE OCCLUSION SHADER Universidade Lusófona Curso - de Cinema e Multimédia Disciplina - Animação Docente Pedro Miguel Sousa MENTAL RAY Nota: Abra o ficheiro OcclusionShader.max Mental Ray é um motor de renderização com um enorme

Leia mais

Transformações 3D. Soraia Raupp Musse

Transformações 3D. Soraia Raupp Musse Transformações 3D Soraia Raupp Musse 1 Translação Coord. Homogêneas x y 1 t x 1 t y 1 x y x y x + t x y + t y t p p r r r + ' 2 x y x + t x y + t y + y Escala Coord. Homogêneas x y s x s y 1 x y x y s

Leia mais

WEB DESIGN ELEMENTOS GRÁFICOS

WEB DESIGN ELEMENTOS GRÁFICOS ELEMENTOS GRÁFICOS Parte 4 José Manuel Russo 2005 24 A Imagem Bitmap (Raster) As imagens digitais ou Bitmap (Raster image do inglês) são desenhadas por um conjunto de pontos quadrangulares Pixel alinhados

Leia mais

Usando o Excel ESTATÍSTICA. A Janela do Excel 2007. Barra de título. Barra de menus. Barra de ferramentas padrão e de formatação.

Usando o Excel ESTATÍSTICA. A Janela do Excel 2007. Barra de título. Barra de menus. Barra de ferramentas padrão e de formatação. Barra de deslocamento ESTATÍSTICA Barra de menus Barra de título Barra de ferramentas padrão e de formatação Barra de fórmulas Conjuntos e Células (Intervalos) Área de trabalho Separador de folhas Barra

Leia mais

Introdução Programando com OpenGL Exemplos. O que é OpenGL? [1]

Introdução Programando com OpenGL Exemplos. O que é OpenGL? [1] Sumário ao OpenGL Exemplos Leandro Tonietto Processamento Gráfico / Computação Gráfica Jogos Digitais ltonietto@unisinos.br http://www.inf.unisinos.br/~ltonietto Mar-2008 Alguns slides são provenientes

Leia mais

Interação Humana com Computador

Interação Humana com Computador Interação Humana com Computador Tecnologias de Computadores André Ferraz N.º24881 Jason Costa N.º25231 Ana Pereira N.º25709 IHC Estudo, planeamento e desenho de uma interação entre o utilizador e computadores.

Leia mais

PIXEL - DO DESENHO À PINTURA DIGITAL

PIXEL - DO DESENHO À PINTURA DIGITAL F PIXEL - DO DESENHO À PINTURA DIGITAL Carga Horária: 96 horas/aulas Módulo 01: Desenho de observação DESCRIÇÃO: Neste módulo o você irá praticar sua percepção de linhas e formas, bem como a relação entre

Leia mais

Universidade da Beira Interior Cursos: Matemática /Informática e Ensino da Informática

Universidade da Beira Interior Cursos: Matemática /Informática e Ensino da Informática Folha 1-1 Introdução à Linguagem de Programação JAVA 1 Usando o editor do ambiente de desenvolvimento JBUILDER pretende-se construir e executar o programa abaixo. class Primeiro { public static void main(string[]

Leia mais

Tópicos de Física Moderna ano 2005/2006

Tópicos de Física Moderna ano 2005/2006 Trabalho Prático Nº 3 ESTUDO DA DIFRAÇÃO Tópicos de Física Moderna ano 005/006 Objectivos: Familiarização com os fenómenos de interferência e difracção da luz, com utilização de uma rede de difracção para

Leia mais

DEIDepartamento. Programação III Engenharia Informática e Comunicações. Engenharia

DEIDepartamento. Programação III Engenharia Informática e Comunicações. Engenharia Engenharia DEIDepartamento Informática Morro do Lena, Alto Vieiro Apart. 4163 2401 951 Leiria Tel.: +351 244 820 300 Fax.: +351 244 820 310 E-mail: estg@estg.iplei.pt http://www.estg.iplei.pt Programação

Leia mais

Introdução a OpenGL. Profª. Alessandra Martins Coelho

Introdução a OpenGL. Profª. Alessandra Martins Coelho Introdução a OpenGL Profª. Alessandra Martins Coelho março/ 2013 OpenGL OpenGL é uma API gráfica que permite a criação de imagens gráficas 2D e 3D, através da definição de objetos (2D/3D) por um conjunto

Leia mais

Introdução à Programação

Introdução à Programação Introdução à Programação Introdução a Linguagem C Construções Básicas Programa em C #include int main ( ) { Palavras Reservadas } float celsius ; float farenheit ; celsius = 30; farenheit = 9.0/5

Leia mais

5/Dez/2012 Aula 21. 21. Polarização das ondas EM 21.1 Por absorção 21.2 Por reflexão 21.3 Por birrefringência 21.4 Equações de Fresnell

5/Dez/2012 Aula 21. 21. Polarização das ondas EM 21.1 Por absorção 21.2 Por reflexão 21.3 Por birrefringência 21.4 Equações de Fresnell 5/Dez/2012 Aula 21 21. Polarização das ondas EM 21.1 Por absorção 21.2 Por reflexão 21.3 Por birrefringência 21.4 Equações de Fresnell 7/Dez/2012 Aula 22 22. Óptica geométrica 22.1 Espelhos planos 22.2

Leia mais

Algoritmos e Programação (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br

Algoritmos e Programação (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br Introdução O computador como ferramenta indispensável: Faz parte das nossas vidas; Por si só não faz nada de útil; Grande capacidade de resolução

Leia mais

JSP - ORIENTADO A OBJETOS

JSP - ORIENTADO A OBJETOS JSP Orientação a Objetos... 2 CLASSE:... 2 MÉTODOS:... 2 Método de Retorno... 2 Método de Execução... 2 Tipos de Dados... 3 Boolean... 3 Float... 3 Integer... 4 String... 4 Array... 4 Primeira:... 4 Segunda:...

Leia mais

Figura 1 - O computador

Figura 1 - O computador Organização e arquitectura dum computador Índice Índice... 2 1. Introdução... 3 2. Representação da informação no computador... 4 3. Funcionamento básico dum computador... 5 4. Estrutura do processador...

Leia mais

I Encontro Brasileiro de usuários QGIS

I Encontro Brasileiro de usuários QGIS I Encontro Brasileiro de usuários QGIS Uso do QGIS no Processamento Digital de Imagens de Sensoriamento Remoto Jorge Santos jorgepsantos@outlook.com www.processamentodigital.com.br Dicas, tutoriais e tudo

Leia mais

Linguagem de Programação Introdução a Linguagem Java

Linguagem de Programação Introdução a Linguagem Java Linguagem de Programação Introdução a Linguagem Java Rafael Silva Guimarães Instituto Federal do Espírito Santo Campus Cachoeiro de Itapemirim Definição A linguagem Java foi desenvolvida pela Sun Microsystems,

Leia mais

O cursor se torna vermelho e uma Paleta de Edição contendo as instruções mais utilizadas é apresentada.

O cursor se torna vermelho e uma Paleta de Edição contendo as instruções mais utilizadas é apresentada. Editor de Ladder para VS7 Versão Teste O editor de ladder é um software de programação que permite que o VS7 e o µsmart sejam programados em linguagem de contatos. Esse editor está contido na pasta Público

Leia mais

Conceitos importantes

Conceitos importantes Conceitos importantes Informática Informação + Automática Tratamento ou processamento da informação, utilizando meios automáticos. Computador (Provem da palavra latina: computare, que significa contar)

Leia mais

Oficina de Construção de Páginas Web

Oficina de Construção de Páginas Web COMPETÊNCIAS BÁSICAS EM TIC NAS EB1 Oficina de Construção de Páginas Web Criação e Publicação Guião Páginas WWW com o editor do Microsoft Office Word 2003 1. Introdução. 2. Abrir uma página Web. 3. Guardar

Leia mais

O AMBIENTE DE TRABALHO DO WINDOWS

O AMBIENTE DE TRABALHO DO WINDOWS O AMBIENTE DE TRABALHO DO WINDOWS O Windows funciona como um Sistema Operativo, responsável pelo arranque do computador. Um computador que tenha o Windows instalado, quando arranca, entra directamente

Leia mais

Configuração do Ambiente de Trabalho

Configuração do Ambiente de Trabalho pag. 1 Configuração do Ambiente de Trabalho 1. Utilização da Área de Trabalho Criação de Atalhos: O Windows NT apresenta um Ambiente de Trabalho flexível, adaptável às necessidades e preferências do utilizador.

Leia mais

Informática Aplicada a Radiologia

Informática Aplicada a Radiologia Informática Aplicada a Radiologia Apostila: Imagem Digital parte I Prof. Rubens Freire Rosa Imagem na forma digital A representação de Imagens na forma digital nos permite capturar, armazenar e processar

Leia mais

Guia de Estudo Criação de Apresentações Microsoft PowerPoint

Guia de Estudo Criação de Apresentações Microsoft PowerPoint Tecnologias da Informação e Comunicação Guia de Estudo Criação de Apresentações Microsoft PowerPoint Aspectos genéricos sobre o trabalho com imagens computacionais Imagens computacionais e programas que

Leia mais

Dadas a base e a altura de um triangulo, determinar sua área.

Dadas a base e a altura de um triangulo, determinar sua área. Disciplina Lógica de Programação Visual Ana Rita Dutra dos Santos Especialista em Novas Tecnologias aplicadas a Educação Mestranda em Informática aplicada a Educação ana.santos@qi.edu.br Conceitos Preliminares

Leia mais

Jogo do NEEC. Primeiramente, criamos uma nova Actividade. File > New > Class

Jogo do NEEC. Primeiramente, criamos uma nova Actividade. File > New > Class Jogo do NEEC Jogo do NEEC Primeiramente, criamos uma nova Actividade File > New > Class Source folder: JogoDoNEEC/src Package: org.neecist.jogodoneec Name: JogoDoNEEC Superclass: android.app.activity Browse

Leia mais