Computação Gráfica 11569 - Engenharia Informática Transformações de Visualização Computação Gráfica 1
Definições janela de dominio da cena HOUSE CLIP ecrã janela de interface visor! Sistema de Coordenadas Globais (Espaço do Objecto ou Domínio da Cena) - É o referencial do espaço em que se encontram os objectos geométricos. - É neste espaço que o modelo de aplicação é definido; ex: R 2. - É neste espaço que a geometria do objecto é definida.! Janela de Domínio da Cena (Subespaço do Domínio de Cena) - Rectângulo que define a parte do domínio da cena que pretendemos visualizar! Sistema de Coordenadas do Ecrã (Espaço de Imagem) - Espaço no qual a imagem é mostrada; ex: 800x600 pixéis. - Espaço no qual a imagem rasterizada do objecto é definida.! Janela de Interface (Subespaço de Imagem) - Representação visual do sistema de coordenadas do ecrã para sistemas de saída baseados em janelas (sistema de coordenadas move-se com a janela de interface) Definições (cont.) janela do domínio de cena ecrã HOUSE CLIP ecrã janela de interface visor! Transformações de visualização (viewing Transformations)! Processo de mapeamento de uma janela do domínio de cena (world coordinates) para um visor (screen coordinates).! Visor (Subespaço de Imagem)! Um rectângulo no ecrã rasterizado (ou janela de interface) que define onde a imagem irá aparecer, ou na totalidade do ecrã ou numa janela de interface.! Portanto, em princípio, a mesma imagem pode ser replicada em diferentes visores (ou viewports) dentro do ecrã ou duma janela de interface. 2
Transformação Janela-Visor Dada uma janela e um visor, qual é a matriz de transformação que mapeia um ponto da janela em coordenadas globais num pixel do visor em coordenadas de ecrã? Esta matriz pode ser dada como a composição de 3 transformações, como é sugerido pela seguinte sequência de figuras: v y (x max,y max ) y v (u max,v max ) (x min,y min ) x x u (u min,v min ) u janela em coordenadas globais (ou de domínio de cena) janela transladada para a origem janela com visor transladado por tamanho alterado (u min,v min ) igual ao tamanho do visor para a posição final Transformação Janela-Visor: representação matricial v y (x max,y max ) y v (u max,v max ) (u min,v min ) (x min,y min ) x x u u 3
Transformação Janela-Visor: como é feita? v y (x max,y max ) Mantendo a proporcionalidade no mapeamento de (x,y) para (u,v) (u max,v max ) (u min,v min ) (x min,y min ) x variação de translação tamanho translação u x min x x max u min u u max y max v max y v y min v min Transformação Janela-Visor: exemplo y v (x max,y max ) (u max,v max ) (x min,y min ) janela(10.0,5.0,40.0,30.0) x (u min,v min ) u visor(100,50,250,300) 4
Transformação Janela-Visor: em OpenGL! gluortho2d(left, right, bottom, top)! Define uma região de visualização ortogonal 2D ou janela de domínio de cena. É definida por dois planos verticais de recorte left e right e dois planos horizontais de recorte bottom e top.! A janela por defeito é (-1,1,-1,1).! Define uma matriz de projecção ortogonal 2-D.! Define ainda a transformação janela-visor, o que requer a definição do visor através da seguinte função: Transformação Janela-Visor: em OpenGL! gluortho2d(left, right, bottom, top) A definição do visor é feita através da seguinte função:! glviewport(x, y, width, height)! Define o visor na janela de interface, onde x,y especificam o canto inferior esquerdo e width, height as suas dimensões.! Por defeito, o visor ocupa a área gráfica total da janela de interface.! Podem existir vários visores dentro da janela de interface. 5
Sequência de Transformações OpenGL coordenadas do olho coordenadas de recorte coordenadas do visor da janela de interface Vertex Modelview Matrix Projection Matrix Viewport GL_MODELVIEW mode! gltranslate()! glrotate()! glscale()! glloadmatrix()! glmultmatrix()! glulookat()! GL_PROJECTION mode! glortho()! gluortho2d()! glfrustum()! gluperspective()! glviewport()! Exemplos em OpenGL! Visor por defeito! Um único visor! Dois visores 6
Exemplo 1: visor por defeito! Como já foi referido, se glviewport(x, y, width, height) NÃO é EXPLICITAMENTE usada no programa, o visor por defeito é toda a área gráfica da janela de interface.! Veja-se o exemplo do próximo programa que retrata esta situação. O visor por defeito tem a área 500x500 e é definido por glutinitwindowsize(500,500) no programa principal. Exemplo 1: visor por defeito // Header files first void draw(){ // Make background colour yellow glclearcolor( 100, 100, 0, 0 ); glclear ( GL_COLOR_BUFFER_BIT ); // Sets up the PROJECTION matrix glmatrixmode(gl_projection); glloadidentity(); gluortho2d(0.0,50.0,-10.0,40.0); // also sets up world window // Draw BLUE rectangle glcolor3f( 0, 0, 1 ); glrectf(0.0,0.0,10.0,30.0); // display rectangles glutswapbuffers(); } // end of draw() 7
Exemplo 1: visor por defeito (cont.) // Keyboard method to allow ESC key to quit void keyboard(unsigned char key,int x,int y) { if(key==27) exit(0); } int main(int argc, char ** argv) { glutinit(&argc, argv); // Double Buffered RGB display glutinitdisplaymode( GLUT_RGB GLUT_DOUBLE); // Set window size glutinitwindowsize( 500,500 ); glutcreatewindow( Default viewport spans the whole interface window"); // Declare the display and keyboard callback functions glutdisplayfunc(draw); glutkeyboardfunc(keyboard); // Start the Main Loop glutmainloop(); return 0; } Exemplo 2: 1 visor! Um visor é EXPLICITAMENTE definido pela função glviewport(x,y, width,height)! O visor pode ou não ocupar toda a área gráfica da janela de interface.! Podem existir vários visores na janela de interface simultaneamente.! Note-se que a janela de interface e os seus visores são definidos antes da janela de domínio de cena, sendo esta última definida através de gluortho2d(left, right, bottom, top) porque esta função também define a transformação janela-visor. 8
Exemplo 2: 1 visor //Header files first. void draw(){ // Make background colour yellow glclearcolor( 100, 100, 0, 0 ); glclear ( GL_COLOR_BUFFER_BIT ); // Sets up viewport spanning the left-bottom // quarter of the interface window glviewport(0,0,250,250); // Sets up the PROJECTION matrix glmatrixmode(gl_projection); glloadidentity(); gluortho2d(0.0,50.0,-10.0,40.0); // also sets up world window // Draw BLUE rectangle glcolor3f( 0, 0, 1 ); glrectf(0.0,0.0,10.0,30.0); // display rectangles glutswapbuffers(); }// end of draw() Exemplo 2: 1 visor (cont.) // Keyboard method to allow ESC key to quit void keyboard(unsigned char key,int x,int y) { if(key==27) exit(0); } int main(int argc, char ** argv) { glutinit(&argc, argv); // Double Buffered RGB display glutinitdisplaymode( GLUT_RGB GLUT_DOUBLE); // Set window size glutinitwindowsize( 500,500 ); glutcreatewindow( Viewport spans the left-bottom interface window quarter"); // Declare the display and keyboard functions glutdisplayfunc(draw); glutkeyboardfunc(keyboard); // Start the Main Loop glutmainloop(); return 0; } 9
Exemplo 3: 2 visores // Header files first void draw(){ // Make background colour yellow glclearcolor( 100, 100, 0, 0 ); glclear ( GL_COLOR_BUFFER_BIT ); // Sets up FIRST viewport spanning the left-bottom quarter of the interface window glviewport(0,0,250,250); // Sets up the PROJECTION matrix glmatrixmode(gl_projection); glloadidentity(); gluortho2d(0.0,50.0,-10.0,40.0); // also sets up world window // Draw BLUE rectangle glcolor3f( 0, 0, 1 ); glrectf(0.0,0.0,10.0,30.0); // Sets up SECOND viewport spanning the right-top quarter of the interface window glviewport(250,250,250,250); // Sets up the PROJECTION matrix glmatrixmode(gl_projection); glloadidentity(); gluortho2d(0.0,50.0,-10.0,40.0); // also sets up world window } // Draw RED rectangle glcolor3f( 1, 0, 0 ); glrectf(0.0,0.0,10.0,30.0); // display rectangles glutswapbuffers(); Exemplo 3: 2 visores (cont.) // Keyboard method to allow ESC key to quit void keyboard(unsigned char key,int x,int y) { if(key==27) exit(0); } int main(int argc, char ** argv) { glutinit(&argc, argv); // Double Buffered RGB display glutinitdisplaymode( GLUT_RGB GLUT_DOUBLE); // Set window size glutinitwindowsize( 500,500 ); glutcreatewindow( Two viewports: left-bottom and right-top quarters"); // Declare the display and keyboard functions glutdisplayfunc(draw); glutkeyboardfunc(keyboard); // Start the Main Loop glutmainloop(); return 0; } 10
Transformação Janela-Visor: nota importante Quando a janela de dominío da cena aumenta de tamanho:! a imagem no visor dimimui, e! vice-versa. janela do domínio de cena HOUSE CLIP Transformação Janela-Visor: aplicações! Panning! Mover a janela no domínio de cena! Zooming! Redução/Aumento do tamanho da janela 11
Activação automática do visor sem distorção de imagem! Qual a maior imagem não-distorcida que ocupa o ecrã?! R = Razão de aspecto da janela do domínio de cena! Duas situações são possíveis.! 1ª - A janela é pequena em altura ajustada à largura do visor da janela de interface, mas algum espaço sobrará em cima/baixo.! Portanto, no máximo, o visor terá largura W e altura W/R. y R>W/H interface window screen world window viewport H W/R aspect ratio R x W Activação automática do visor sem distorção de imagem! Qual a maior imagem não-distorcida que ocupa o ecrã?! R = Razão de aspecto da janela do domínio de cena! Duas situações são possíveis.! 2ª - A janela é alta e estreita comparada com a janela de interface. y world window R<W/H interface window screen! O visor com a mesma razão de aspecto R ocupará toda área gráfica da janela de interface em altura, mas sobrará algum espaço à esquerda/ direita. aspect ratio R x viewport W H.R H! Portanto, no máximo, o visor terá largura H.R e altura H. 12
Activação automática do visor sem distorção de imagem y world window R>W/H interface window screen y world window R<W/H interface window screen aspect ratio R viewport W/R H aspect ratio R viewport H.R H x W x W glviewport(0,0,w,w/r);! glviewport(0,0,h*r,h);! Normalmente este ajuste é feito na callback reshape Exemplo 4: janela baixa! Se a janela tem razão de aspecto R=2.0 e a janela de interface tem altura H=200 e largura W=360, então W/H=1.8. y world window R>W/H interface window screen! Portanto, estamos no primeiro caso, e o visor é activado com 180 pixéis de altura e 360 pixéis de largura. aspect ratio R x viewport W/R W H glviewport(0,0,w,w/r);! glviewport(0,0,360,360/2);! 13
Exemplo 5: janela alta! Se a janela tem razão de aspecto R=1.6 e o ecrã da janela de interface tem H=200 e W=360, então W/H=1.8. y world window R<W/H interface window screen! Portanto, estamos no segundo caso, e o visor é activado com 200 pixéis de altura e 320 pixéis de largura. aspect ratio R x viewport W H.R H glviewport(0,0,h*r,h);! glviewport(0,0,320,200);! Manutenção das proporções na passagem da janela para o visor! Mas para manter o visor e evitar distorção, há que mudar o tamanho da janela do domínio de cena em conformidade.! Para isso, assumindo a priori que a janela da cena é um quadrado cujos lados têm comprimento L.! Uma solução possível é mudar a janela da cena sempre que o ecrã da janela de interface for alterada. Assim, a callback reshape(glsizei w, GLsizei h) tem de ser alterada por forma a incluir o código seguinte: if (w <= h)! gluortho2d(-l, L, -L * h/w, L * h/w);! else! gluortho2d(-l * w/h, L * w/h, -L, L);! 14
Exemplo 6: Mapeamento janela-visor sem distorção //Header files first void draw(){ // Make background colour yellow glclearcolor( 100, 100, 0, 0 ); glclear ( GL_COLOR_BUFFER_BIT ); // Draw triangle glcolor3f( 0, 0, 1 ); glrectf(0.0,0.0,30.0,30.0); glcolor3f(1,0,0); glbegin(gl_triangles); glvertex3f(0.0,30.0,1.0); glvertex3f(30.0,30.0,1.0); glvertex3f(15.0,40.0,1.0); glend(); // display glutswapbuffers(); }// end of draw() Exemplo 6: (cont.) // Keyboard method to allow ESC key to quit GLvoid reshape(glsizei w, GLsizei h) { GLfloat L = 100.0f; if (h == 0) h=1; if (w == 0) w=1; glviewport(0,0,w,h); // prevent a divide by zero // prevent a divide by zero // set viewport to window dimensions glmatrixmode(gl_projection); // reset projection matrix stack glloadidentity(); if (w <= h) gluortho2d(-l, L, -L * h/w, L * h/w); else gluortho2d(-l * w/h, L * w/h, -L, L); } glmatrixmode(gl_modelview); glloadidentity(); // reset model-view matrix stack 15
Exemplo 6: (cont.) // Keyboard method to allow ESC key to quit void keyboard(unsigned char key,int x,int y) { if(key==27) exit(0); } int main(int argc, char ** argv) { glutinit(&argc, argv); // Double Buffered RGB display glutinitdisplaymode( GLUT_RGB GLUT_DOUBLE); // Set window size glutinitwindowsize( 500,500 ); glutcreatewindow( Single viewport"); // Declare the display, reshape, and keyboard functions glutdisplayfunc(draw); glutreshapefunc(reshape); glutkeyboardfunc(keyboard); // Start the Main Loop glutmainloop(); return 0; } Recorte Gráfico! Algoritmo de Cohen-Sutherland! 16
Recorte Gráfico?! É o processo pela qual todas as primitivas gráficas geradas passam obrigatoriamente (recorte ou clipping). Recorte Gráfico (cont.)! Recorte de Linhas! Recorte de uma linha contra uma área rectangular resulta sempre num segmento de recta.! A parte que recai dentro da área de recorte é visualizada.! As restantes são ignoradas. C C 17
Recorte Gráfico (cont.)! Os pontos extremos podem ser facilmente testados para averiguar se estão dentro ou fora da área de recorte.! Seja a área de recorte definida por: xmin, xmax, ymin, ymax Então: O ponto extremo (x, y) está dentro da área de recorte sse xmin<= x <= xmax ymin<= y <= ymax e! Basta que uma destas 4 condições não seja satisfeita para concluirmos que o ponto (x, y) se encontra fora da região de recorte. Recorte Gráfico (cont.)! Casos simples:! Totalmente dentro da área de recorte;! Totalmente fora da área de recorte sem que exista intercepção com a área de recorte. 18
Recorte Gráfico (cont.)! Casos complicados:! Dois pontos fora mas intercepta a área de recorte;! Um ponto dentro e outro fora. Recorte Gráfico (cont.)! Algoritmo de Cohen-Sutherland para recorte de linhas! Codifica as 9 regiões com 4 bits:! 1º bit: fora do meio-plano da aresta de topo (y > ymax)! 2º bit: fora do meio-plano da aresta abaixo (y < ymin)! 3º bit: fora do meio-plano da aresta direita (x > xmax)! 4º bit: fora do meio-plano da aresta esquerda (x < xmin) 19
Algoritmo de Cohen- Sutherland (cont.)! Codifica os extremos do segmento de recta.! Analisa os resultado da codificação usando o AND lógico (i.e., &) Situação CodP1 = CodP2 = 0000 CodP1 & CodP2 0000 CodP1 & CodP2 = 0000 Acção Aceitação Rejeição Subdivisão Algoritmo de Cohen- Sutherland (cont.)! Exemplo 1! CodG = 0100 e CodH = 0010 CodG & CodH = 0000 --> Subdivisão! Calcula-se uma intercepção G com CodG = 0000! Calcula-se a outra intercepção H G G H H 20
Algoritmo de Cohen- Sutherland (cont.)! Exemplo 2! CodG = 0100 e CodH = 0010 CodG & CodH = 0000 --> Subdivisão! Calcula-se uma intercepção G com CodG = 0010 H CodG & CodH 0000 Rejeição G G Visualização 2D/3D e Projecções 21
Pipeline de Renderização em OpenGL MODELVIEW matrix PROJECTION matrix perspective division viewport transformation vértice original (object coordinates) vértice no sistema de coordenadas do olho (eye coordinates) projecção 2D do vértice no plano de projecção (clip coordinates) coordenadas normalizadas do dispositivo de saída (normalized device coordinates) coordenadas do pixel no visor da janela de interface (window coordinates) Sistema de câmara! Para criar uma vista duma cena é necessário:! uma descrição da geometria da cena! uma câmara ou definição do ponto de vista (ou observador)! um plano de projecção! Por omissão, a câmara OpenGL está localizada na origem e direccionada no sentido do eixo z negativo. 22
Sistema de câmara! A definição da câmara permite a projecção da geometria da cena 3D numa superfície 2D para efeitos de saída gráfica.! Esta projecção pode ser feita de várias maneiras:! ortogonal (paralelismo das linhas é preservado)! ortogonal oblíqua! perspectiva: 1-ponto, 2-pontos ou 3- pontos de fuga Tipos de câmara! Modelo da câmara clássica (pinhole camera model) é o mais usado:! profundidade infinita do campo (infinite depth of field): tudo é focado! Modelo de câmara dos sistemas avançados de renderização! lentes duplas de Gauss são usadas por muitas câmaras profissionais! modela a profundidade de campo e óptica não-linear (incluindo lens flare)! Sistemas de renderização foto-realística empregam muitas vezes o modelo físico do olho humano para renderizar imagens! modela a resposta dos olhos face aos níveis de brilho e cor! modela a óptica interna do próprio olho (difracção pelas fibras da lente etc.) 23
Modelo da câmara clássica Renderização foto-realística baseada na resposta do olho 24
Sistemas baseados na câmara de lentes duplas Um modelo de câmara implementado na Princeton University (1995) Sistema de visualização! Nesta altura só estamos preocupados com a geometria da visualização.! A posição e a orientação da câmara definem um viewvolume ou view-frustrum.! objectos completa ou parcialmente dentro deste volume serão potencialmente visíveis no visor (viewport).! objectos completamente fora deste volume não são vistos clipped clipped view frustrum clipping planes 25
Modelo da câmara! Cada vértice tem de ser projectado no plano da janela 2D da câmara (plano de projecção) por forma a visualizá-lo no ecrã.! A CTM é empregue para determinar a localização de cada vértice no sistema de coordenadas da câmara:! Depois, aplicamos a matriz de projecção definida por GL_PROJECTION para mapear coordenadas da câmara para as coordenadas da janela 2D do plano de projecção.! Finalmente, estas coordenadas 2D são mapeadas para as coordenadas do dispositivo de saída através da utilização da definição dum visor (viewport) na janela de interface (dado por glviewport()). CTM= Current Transformation Matrix Modelação da câmara em OpenGL sistema de coordenadas da câmara sistema de coordenadas da janela 2D sistema de coordenadas do dispositivo/ecrã glmatrixmode(gl_modelview)... glviewport(0,0,xres,yres) glmatrixmode(gl_projection)... 26
Projecção 3D " 2D! Tipo de projecção depende dum conjunto de factores:! localização e orientação do plano de projecção! direcção da projecção (descrita por um vector)! tipo de projecção: Projecção Perspectiva Paralela 1-ponto Ortogonal 2-pontos Axonométrica 3-pontos Oblíqua 53 Projecções paralelas - projectantes são paralelas - observador no infinito axonométrica ortogonal oblíqua 54 27
Projecções paralelas ortogonais! A mais simples de todas as projecções: as projectantes são perpendiculares ao plano de projecção.! Normalmente, o plano de projecção está alinhado com os eixos (muitas das vezes em z=0) Projecções paralelas axonométricas: isométrica, dimétrica e cavaleira! Se o objecto está alinhado com os eixos, o resultado é uma projecção ortogonal;! Caso contrário, é uma projecção axonométrica.! Se o plano de projecção intersecta os eixos XYZ à mesma distância relativamente à origem, o resultado é uma projecção isométrica. 28
Projecções paralelas em OpenGL glortho(xmin, xmax, ymin, ymax, zmin, zmax); Projecções múltiplas! Às vezes é útil ter várias projecções disponíveis para visualização! normalmente: vista de frente, planta e alçado direito perspectiva planta vista de frente alçado direito 29
Projecções em perspectiva - projectantes não são paralelas - observador encontra-se a distância finita perspectiva com 3-pontos perspectiva com 1-ponto perspectiva com 2-pontos Projecções em perspectiva! Projecções em perspectiva são mais complexas e exibem concorrência das projectantes ou raios visuais (as linhas paralelas parecem convergir para um ponto localizado a uma distância finita).! Parâmetros:! centro de projecção (COP)! campo de vista (θ,φ)! direcção de projecção! direcção up do eixo da câmara ou do observador 30
Projecções em perspectiva Considere uma projecção em perspectiva com o ponto de vista na origem e a direcção de observação orientada ao longo eixo -z e o plano de projecção localizado em z = -d d y y -z PROJECTION matrix perspective division 61 Projecções em perspectiva: alternativa Objectos dentro do frustum são projectados no plano paralelo ao plano XY segundo as seguintes igualdades: z=-d z y x (x,y,-d) (x,y,z) 62 31
Projecção em perspectiva! Dependendo da aplicação, pode usar-se mecanismos diferentes para especificar uma vista em perspectiva. Exemplo: os ângulos do campo de vista podem ser inferidos se a distância ao plano de projecção é conhecida.! Exemplo: a direcção de observação pode ser obtida se, além do COP, se especificar um ponto na cena para onde o observador olha.! OpenGL suporta estes dois mecanismos de especificar uma vista em perspectiva através de:! glulookat, glfrustum e gluperspective Projecções em perspectiva glfrustum(xmin, xmax, ymin, ymax, zmin, zmax); 64 32
glfrustum! Note-se que todos os pontos na linha definida pelo COP e (xmin,ymin,-zmin) são mapeados para o canto inferior esquerdo da janela.! Também todos os pontos na linha definida pelo COP e (xmax,ymax,-zmin) são mapeados para o canto superior direito da janela.! A direcção de observação é sempre paralela a -z! Não é necessário ter um frustrum simétrico como: glfrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 50.0);! Um frustrum não-simétrico introduz obliquidade na projecção.! zmin e zmax são especificados como distâncias positivas ao longo de -z! 65 Projecções em perspectiva gluperspective(fov, aspect, near, far); 33
gluperspective! Uma função para simplificar a especificação de vistas ou projecções em perspectiva.! Só permite a criação de volumes de visualização simétricos.! O ponto de vista do observador (COP) está na origem e a direcção de observação é o eixo -z.! O ângulo do campo de vista, fov, tem de pertencer ao intervalo [0,180].! aspect permite a criação dum frustrum com a mesma razão de aspecto do visor (viewport) por forma a eliminar distorção. Projecções em perspectiva 68 34
Posicionamento da câmara! As projecções anteriores têm limitações:! COP fixo e direcção de projecção (ou observação) fixa! Para obter uma posição e orientação arbitrárias da câmara temos de manipular a matriz MODELVIEW antes da criação dos modelos. Desta forma, posiciona-se a câmara relativamente aos objectos da cena.! Por exemplo, há duas possibilidades para posicionar a câmara em (10, 2, 10) em relação ao referencial do domínio da cena:! mudar o referencial do domínio da cena antes de criar os objectos usando translatef e rotatef: gltranslatef(-10,-2,-10);! usar glulookat para posicionar a câmara relativamente ao referencial do domínio da cena: glulookat(10,2,10, );! Estas duas possibilidades são equivalentes. Posicionamento da câmara glulookat(eyex, eyey, eyez, lookx, looky, lookz, upx, upy, upz); equivalente a: gltranslatef(-eyex, -eyey, -eyez); glrotatef(theta, 1.0, 0.0, 0.0); glrotatef(phi, 0.0, 1.0, 0.0); 35
Janela de projecção! A matriz de projecção define a transformação de coordenadas 3D do domínio da cena numa janela 2D que pertence ao plano de projecção.! As dimensões da janela de projecção são definidas como parâmetros da projecção: (r,t,-n)! glfrustum(l,r,b,t,n,f) (l,b,-n)! gluperspective(f,a,n,f 1 )! (w,h,-n) (-w,-h,-n) Transformação janela-visor: revisão! Como vimos já, é preciso mapear os pontos do sistema de coordenadas da janela de projecção para os pixéis do sistema de coordenadas do visor, por forma a determinar o pixel associado a cada vértice dos objectos da cena. coordenadas do dispositivo normalizado coordenadas do visor da janela da interface 36
Transformação janela-visor: revisão! Uma transformação afim planar é usada.! Após projecção no plano de vista, todos os pontos são transformados em coordenadas do dispositivo normalizado: [-1,+1] [-1,+1]. glviewport(int x, int y, int width, int height);! glviewport é usado para relacionar os dois sistemas de coordenadas: Transformação janela-visor: revisão! (x,y) = posição do canto inferior esquerdo do visor dentro da janela da interface! width,height = dimensões do visor em pixéis! Normalmente, recria-se a janela após o evento resize da janela da interface para assegurar o mapeamento correcto entre as dimensões do visor e da janela: static void reshape(int width, int height) { glviewport(0, 0, width, height); glmatrixmode(gl_projection); glloadidentity(); gluperspective(85.0, 1.0, 5, 50); } 37
Razão de aspecto: revisão! A razão de aspect (aspect ratio) define a relação entre a largura (width) e a altura (height) da imagem.! A razão de aspecto da janela de projecção é explicitamente fornecida através da função gluperspective/glfrustum.! A razão de aspecto do visor deve ser a mesma para evitar distorção de imagem: aspect ratio = 1.25 aspect ratio = 0.5 // top left: top view glviewport(0, win_height/2, win_width/2, win_height/2); glmatrixmode(gl_projection); glloadidentity(); glortho(-3.0, 3.0, -3.0, 3.0, 1.0, 50.0); glulookat(0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0); glmatrixmode(gl_modelview); glloadidentity(); glcalllist(object); // top right: right view glviewport(win_width/2, win_height/2, win_width/2, win_height/2); glmatrixmode(gl_projection); glloadidentity(); glortho(-3.0, 3.0, -3.0, 3.0, 1.0, 50.0); glulookat(5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glmatrixmode(gl_modelview); glloadidentity(); glcalllist(object); // bottom left: front view glviewport(0, 0, win_width/2, win_height/2); glmatrixmode(gl_projection); glloadidentity(); glortho(-3.0, 3.0, -3.0, 3.0, 1.0, 50.0); glulookat(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glmatrixmode(gl_modelview); glloadidentity(); glcalllist(object); // bottom right: rotating perspective view glviewport(win_width/2, 0, win_width/2, win_height/2); glmatrixmode(gl_projection); glloadidentity(); gluperspective(70.0, 1.0, 1, 50); glulookat(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glmatrixmode(gl_modelview); glloadidentity(); glrotatef(30.0, 1.0, 0.0, 0.0); glrotatef(angle, 0.0, 1.0, 0.0); glcalllist(object); 76 38