Projeção e Anaglifos Renato Paes Leme Nosso problema básico é o seguinte: temos uma coleção de pontos (x i, y i, z i ) em um conjunto de vértices, e um conjunto de polígonos. Queremos representar esses pontos em uma tela, dando ao observador a noção de perspectiva. Usaremos então a perspectiva cônica, que consiste basicamente em considerar um observador pontual Q e um plano de projeção π. A imagem de um ponto Q R 3 é dada pelo ponto de interseção da reta P Q com o plano π [Fig 1] Para simplicar os cálculos, vamos supor que o observador está na origem, ou seja, que Q = (0, 0, 0) e que o plano π é o plano Z = f onde f é um número positivo [Fig ]. A menos de uma mudança de coordenadas, podemos passar para essa situação. Mais especicamente, podemos passar para essa situação somente usando uma translação e uma rotação - basta tomar a translação que leva Q à origem e uma rotação que leva o vetor normal unitário do plano π em (0, 0, 1) (f ca sendo a distância de Q ao plano π). ( forma, se P = (x, y, z), a sua projeção no plano Z = f é dada por: f xdessa, f y, f). Assim, basicamente, o nosso trabalho será ler todos os pontos z z de um arquivo PLY (que contém coordenadas dos pontos e as arestas) e projetá-los no plano Z = f. O primeiro exemplo é a projeção de teapot.ply. É interessante aplicar uma transformação incialmente nos pontos para que eles quem bem enquadrados pela câmera. Se os pontos cam muito próximos da câmera (a origem) podemos cair em uma situação em que só conseguimos enxergar um pedaço do objeto, perdendo a visão do todo. Vamos projetar somente em uma região limitada do plano Z = f que é o ( quadrado: [ 1, 1] [ 1, 1]. Então, estamos interessados que todos os pontos f x, f ) y estejam nesse quadrado. Duas idéias para se obter isso: z z Se Ω é o conjunto de n pontos. Inicialmente denimos um centro para a gura. Uma idéia para denir o centro e tomar uma média coordenada a coordenada dos pontos, ou seja: G = 1 P n 1 P Ω
Ou tome: x m = min{x; (x, y, z) Ω} e x M = max{x; (x, y, z) Ω}. 1 Assim, tomamos a coordenada x de G como: (x m + m M ). Fazemos o mesmo para as demais coordenadas. Assim, temos um centro para a gura. Em seguida, denimos um raio, dado por: r = max{ P G ; P Ω} Aplicando a translação P P G + (0, 0, d) faz com que a gura passe a ter centro no ponto (0, 0, d). Em [Fig 3] buscamos, dado r e f determinar d para que a projeção ocupe o quadrado [ 1, 1]. Usando uma semelhança de triângulos, temos: r d = 1 = d = r 1 + f 1 + f A primeira abordagem foi usada em perspectiva1.cpp, que produziu o script teapot1.txt para o Plot. Para vizualizar esse arquivo, basta digitar./plot teapot1.txt. Em perspectiva.cpp, que produz o script teapot.txt para o Plot, adotamos a segunda abordagem. Note que os resultados são muito semelhantes. Outra abordagem interessante é, ao invés de pensarmos em uma esfera de centro G e raio r, pensarmos em um paralelepípedo. Essa abordageme está exemplicada em [Fig 4]. Calculando os valores máximo e mínimo que cada coordenada assume, podemos colocar o objeto dentro de um paralelepípedo da forma: [x m, x M ] [y m, y M ] [z m, z M ]. Tomemos o ponto G como o centro da base do paralelepípedo, ou seja: ( xm + x M G =, y m + y M, z m ) A base do paralelogramo é um retângulo de lados x = x M x m e y = y M y m. Pela gura, claramente, a imagem do paralelogramo no plano Z = f é um retângulo de lados f x e f y. Assim a imagem do objeto que d d está no paralelogramo está nesse retângulo. Se queremos que esse retângulo esteja em [ 1, 1], basta fazer uma transformação P P G + (0, 0, d) com d f max{ x, y}. Esta abordagem produziu o script teapot3.txt. Outro script produzido por essa abordagem é o bunny1.txt. Tendo resolvido esse problema, partiremos para o problema de projetar em um plano qualquer. Representaremos um plano pelo seu vetor normal unitário apontando para o sentido oposto da origem. Assim, como em [Fig5], considere uma base ortonormal para o R 3 dada por {u 1, u, u 3 } onde u 3 é o vetor normal ao plano. Essa base dene um sistema de coordenadas. A matriz:
U = [u 1 u u ] cujos vetores coluna são u 1, u e u 3, faz a passagem da base {u 1, u, u 3 } para a base canônica. Assim, a matriz inversa U 1 = U t (pois U é ortogonal) faz a passagem da base canônica para a base {u 1, u, u 3 }. Portanto, dado um vetor (x, y, z), se U t (x, y, z) = (α, β, γ) então: (x, y, z) = αu 1 + βu + γu 3 Assim, podemos projetar como zemos anteriormente, associar (x, y, z) a um ponto ( ) fα, fβ γ γ. Assim, basta tomar a composição das funções: U t : R 3 R 3 e proj : R 3 R Usando ver.cpp podemos criar projeções de um arquivo PLY em qualquer plano. Para escolher o plano, basta ajustar o valor de f e os coecientes da matriz U. A biblioteca geometria.h permite a multiplicação e matrizes e já vem com as matrizes que representam os ângulos de Euler prontas. O programa animacao.cpp produz animacoes a partir de guras. O último problema a se atacar é o problema dos anaglifos. Agora, ao invés de fazermos uma imagem em preto e branco como vínhamos fazendo, faremos duas imagens: uma azul e uma vermelha. Os anaglifos serão vistos com um óculos vermelho e azul, de forma que o olho direito, com a lente azul, só enxergará o desenho em vermelho e o olho esquerdo, com a lente vermelha, só enxergará o desenho em azul. Seja n a distância entre os olhos. No nosso modelo em que o centro de projeção se encontra na origem e o plano de projeção é o plano Z = f, consideremos que os olhos estão nas posições n e n. Dessa forma, como é possível concluir pela [Fig 6]: n z = n z f = n = n z f z Assim, se anteriormente para cada ponto P = (x, y, z) marcávamos um ponto proj P (f) = ( f x, f ) y z z R, agora marcamos dois pontos, dados pela fórmula: proj P (f)±n z f, sendo que o sinal + representa o ponto azul e o sinal z representa um ponto vermelho. Isso está implementado em anaglifo.cpp. Dois exemplos de anaglifos são: anaglifo1.txt e anaglifo.txt 3