Computação Gráfica 2D
Computação Gráfica 2D
Computação Gráfica 2D
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Universidade Federal de Santa Maria<br />
Departamento de Eletrônica e Computação<br />
Prof. Cesar Tadeu Pozzer<br />
Disciplina: Computação Gráfica<br />
pozzer@inf.ufsm.br<br />
9/06/2011<br />
Computação Gráfica <strong>2D</strong><br />
1 Transformações <strong>2D</strong> Afins<br />
Uma transformação afim mantém o paralelismo de retas. São exemplos a translação, escala, rotação,<br />
reflexão e cisalhamento. A projeção em perspectiva não é uma transformação afim. O mesmo vale para<br />
transformações de tapering, twist e bend [4].<br />
Transformações afins envolvendo rotações, translações e reflexões preservam ângulos e comprimentos, da<br />
mesma forma como linhas paralelas. Para estas três transformações, comprimentos e ângulos entre duas<br />
linhas permanecem o mesmo após a transformação [2].<br />
Utiliza-se matrizes para representar transformações. Ver seção de Matrizes.<br />
Translação<br />
Definida pela soma de fatores de translação t x e t y as coordenadas x e y do ponto. É uma soma de matrizes<br />
x’ = x + T x<br />
y’ = y + T y<br />
P’ = P + T<br />
⎡x⎤<br />
⎡x'<br />
⎤ ⎡Tx<br />
⎤ ⎡x⎤<br />
⎡Tx<br />
⎤ ⎡x<br />
+ Tx<br />
⎤<br />
P = ⎢ ⎥ P ' =<br />
⎣ y<br />
⎢ ⎥ T = ⎢ ⎥ P' = =<br />
⎦ ⎣y'<br />
⎦ ⎣T<br />
⎢ ⎥ + ⎢ ⎥ ⎢ ⎥<br />
y ⎦ ⎣y⎦<br />
⎣T<br />
y ⎦ ⎣y<br />
+ Ty<br />
⎦<br />
Escala<br />
Definida pela multiplicação de fatores de escala S x e S y as coordenadas do ponto. É representada por uma<br />
multiplicação de matrizes.<br />
x’ = x * S x<br />
y’ = y * S y<br />
P'<br />
= T ⋅ P<br />
⎡x⎤<br />
⎡x'<br />
⎤ ⎡S<br />
x<br />
0 ⎤<br />
P = ⎢ ⎥ P ' =<br />
⎣ y<br />
⎢ ⎥ T = ⎢ ⎥<br />
⎦ ⎣y'<br />
⎦ ⎣ 0 S<br />
y ⎦<br />
⎡S<br />
x<br />
P'<br />
= ⎢<br />
⎣ 0<br />
0 ⎤⎡x⎤<br />
⎡xS<br />
⎥⎢<br />
⎥ =<br />
S<br />
⎢<br />
y ⎦⎣y⎦<br />
⎣yS<br />
x<br />
y<br />
⎤<br />
⎥<br />
⎦<br />
1
Se S x > 1 aumenta o tamanho do objeto<br />
S x < 1 diminui o tamanho do objeto<br />
S x = 1 mantém o tamanho<br />
S x = S y = n escala uniforme<br />
OBS: a escala pode mudar a posição do objeto. Depende do referencial.<br />
Reflexão<br />
x’ = -x<br />
y’ = y<br />
P'<br />
= T ⋅ P<br />
⎡x⎤<br />
⎡x'<br />
⎤ ⎡−1<br />
0⎤<br />
P = ⎢ ⎥ P ' =<br />
⎣ y<br />
⎢ ⎥ T =<br />
⎦ ⎣y'<br />
⎢ ⎥ ⎦ ⎣ 0 1 ⎦<br />
⎡−1<br />
P'<br />
= ⎢<br />
⎣ 0<br />
0⎤⎡x⎤<br />
⎡− x⎤<br />
⎢ ⎥ =<br />
1<br />
⎥ ⎢ ⎥<br />
⎦⎣y⎦<br />
⎣ y ⎦<br />
Cisalhamento<br />
Transformação que distorce o formato do objeto. Aplica-se um deslocamento aos valores das coordenadas x<br />
ou y do objeto proporcional ao valor das outras coordenadas de cada ponto transformado.<br />
x’ = x + Sy*y<br />
y’ = y<br />
⎡x⎤<br />
⎡x'<br />
⎤ ⎡1 S<br />
y ⎤<br />
P = ⎢ ⎥ P ' =<br />
⎣ y<br />
⎢ ⎥ T =<br />
⎦ ⎣y'<br />
⎢ ⎥ ⎦ ⎣0<br />
1 ⎦<br />
P'<br />
= T ⋅ P<br />
⎡1<br />
S<br />
P'<br />
= ⎢<br />
⎣0<br />
y<br />
1<br />
⎤⎡x⎤<br />
⎡ x + S<br />
⎥⎢<br />
⎥ = ⎢<br />
⎦⎣y⎦<br />
⎣ y<br />
y<br />
y⎤<br />
⎥<br />
⎦<br />
Rotação<br />
Rotacionar um vetor significa mudar sua direção segundo algum eixo de rotação. Para um vetor<br />
bidimensional, ou seja, paralelo ao plano xy, significa reposicioná-lo sobre um caminho circular, como<br />
ocorre com o movimento dos ponteiros de um relógio. O eixo de rotação é um vetor perpendicular ao plano<br />
xy e passa pelo centro de rotação. A rotação é especificada por um ângulo θ (Coordenadas Polares)<br />
Valores positivos de θ geram uma rotação no sentido anti-horário. Neste exemplo, considera-se que o centro<br />
de rotação é a origem do sistema de coordenadas.<br />
2
y<br />
(x’, y’)<br />
r<br />
θ<br />
φ<br />
r<br />
(x, y)<br />
Rotação de um vetor da posição (x,y) para a posição (x’, y’) segundo um ângulo θ relativo à origem do<br />
sistema de coordenadas.<br />
x<br />
Em uma rotação, a norma r do vetor permanece inalterada. Usando identidades trigonométricas, pode-se<br />
expressar as coordenadas transformadas em termo dos ângulos φ e θ.<br />
x'<br />
= r cos( φ + θ ) = r cosφ<br />
cosθ<br />
− r sinφ<br />
sinθ<br />
y'<br />
= r sin( φ + θ ) = r cosφ<br />
sinθ<br />
+ r sinφ<br />
cosθ<br />
As coordenadas iniciais do vetor em coordenadas polares são<br />
Substituindo na expressão anterior temos<br />
Usando-se uma notação matricial, tem-se<br />
Vetor Perpendicular<br />
x = r cosφ<br />
y = r sinφ<br />
x'<br />
= x cosθ<br />
− y sinθ<br />
y'<br />
= xsinθ<br />
+ y cosθ<br />
P ' = RP<br />
⎡cosθ<br />
− sinθ<br />
⎤ ⎡x⎤<br />
P'<br />
= ⎢<br />
⎥ ⎢ ⎥<br />
⎣sinθ<br />
cosθ<br />
⎦ ⎣y⎦<br />
Dado um vetor P, para encontrar um vetor Q, perpendicular a P (que forma um ângulo de 90º em sentido<br />
anti-horário), usa-se a seguinte fórmula:<br />
Q<br />
=<br />
x<br />
〈− P y<br />
P 〉<br />
Esta fórmula pode ser demonstrada utilizando-se a notação matricial genérica para rotações sobre um eixo:<br />
⎡cos(90)<br />
− sin(90) ⎤⎡P<br />
x ⎤<br />
Q = ⎢<br />
⎥⎢<br />
⎥<br />
⎣sin(90)<br />
cos(90) ⎦⎣<br />
Py<br />
⎦<br />
⎡0<br />
−1⎤⎡<br />
Px<br />
⎤<br />
Q = ⎢ ⎥⎢<br />
= [ Px<br />
− Py<br />
Px<br />
+ Py<br />
] = [ − Py<br />
Px<br />
]<br />
P<br />
⎥ 0 1 1 0<br />
⎣1<br />
0 ⎦⎣<br />
y ⎦<br />
Deve-se observar que existem dois vetores perpendiculares em um espaço <strong>2D</strong>. Para um vetor em três<br />
dimensões, a determinação de um vetor perpendicular é mais vaga. Podem existir infinitos vetores<br />
3
perpendiculares (qualquer vetor no plano perpendicular ao vetor P). Em um plano 3D existem 2 vetores<br />
perpendiculares.<br />
Coordenadas Homogêneas<br />
Todas as transformações apresentadas, exceto a translação são representadas como multiplicações de<br />
matrizes. Como será visto na seqüência, é comum fazer a combinações de várias transformações em uma<br />
única matriz. Como a translação está presente em quase todas as transformações, é fundamental que ela<br />
possa ser representada por meio de multiplicação de matrizes. Para isso introduziu-se o conceito de<br />
coordenadas homogêneas.<br />
Consiste em adicionar mais uma dimensão à matriz. Cada ponto <strong>2D</strong> é representado por (x,y,h). Caso o valor<br />
de h não seja 1, deve-se dividir cada componente do vetor por h. Assim, o ponto (2, 3, 6) e (4, 6, 12)<br />
representam a mesma informação<br />
x<br />
⎜<br />
⎝ h<br />
y<br />
h<br />
⎛ ⎞<br />
( x y h) = 1⎟ ⎠<br />
Este processo é chamado de homogenização. Neste caso, x/h e y/h são as coordenadas cartesianas do ponto<br />
homogêneo.<br />
A terceira coordenada do ponto pode ser interpretada geometricamente como um plano h=1 no R 3 , como<br />
mostrado na figura. O ponto P’=(x/h, y/h) é a projeção do ponto P(x, y, h) no plano h=1. Desta forma,<br />
qualquer múltiplo do ponto P homogêneo representa o mesmo ponto.<br />
h<br />
P = (x, y, h)<br />
Plano h=1<br />
y/h<br />
y<br />
x/h<br />
x<br />
Fazendo uso de coordenadas homogêneas, a translação é definida como<br />
P’ = TP<br />
⎡x⎤<br />
P =<br />
⎢ ⎥<br />
⎢<br />
y<br />
⎥<br />
⎢⎣<br />
1⎥⎦<br />
⎡x'<br />
⎤<br />
P ' =<br />
⎢ ⎥<br />
⎢<br />
y'<br />
⎥<br />
⎢⎣<br />
1 ⎥⎦<br />
T<br />
⎡1<br />
=<br />
⎢<br />
⎢<br />
0<br />
⎢⎣<br />
0<br />
0<br />
1<br />
0<br />
Tx<br />
⎤<br />
T<br />
⎥<br />
y<br />
⎥<br />
1 ⎥⎦<br />
⎡1<br />
P ' = TP =<br />
⎢<br />
⎢<br />
0<br />
⎢⎣<br />
0<br />
0<br />
1<br />
0<br />
Tx<br />
⎤⎡x⎤<br />
⎡x<br />
+ T<br />
T<br />
⎥⎢<br />
⎥<br />
=<br />
⎢<br />
y<br />
⎥⎢<br />
y<br />
⎥ ⎢<br />
y + T<br />
1 ⎥⎦<br />
⎢⎣<br />
1⎥⎦<br />
⎢⎣<br />
1<br />
x<br />
y<br />
⎤<br />
⎥<br />
⎥<br />
⎥⎦<br />
Escala:<br />
P'<br />
= S ⋅ P<br />
4
⎡x⎤<br />
P =<br />
⎢ ⎥<br />
⎢<br />
y<br />
⎥<br />
⎢⎣<br />
1⎥⎦<br />
⎡x'<br />
⎤<br />
P ' =<br />
⎢ ⎥<br />
⎢<br />
y'<br />
⎥<br />
⎢⎣<br />
1 ⎥⎦<br />
⎡S<br />
x<br />
S =<br />
⎢<br />
⎢<br />
0<br />
⎢⎣<br />
0<br />
S<br />
0<br />
y<br />
0<br />
0⎤<br />
0<br />
⎥<br />
⎥<br />
1⎥⎦<br />
⎡S<br />
x<br />
P ' = SP =<br />
⎢<br />
⎢<br />
0<br />
⎢⎣<br />
0<br />
S<br />
0<br />
0<br />
y<br />
0⎤⎡x⎤<br />
⎡xS<br />
0<br />
⎥⎢<br />
⎥<br />
=<br />
⎢<br />
⎥⎢<br />
y<br />
⎥ ⎢<br />
yS<br />
1⎥⎦<br />
⎢⎣<br />
1⎥⎦<br />
⎢⎣<br />
1<br />
x<br />
y<br />
⎤<br />
⎥<br />
⎥<br />
⎥⎦<br />
Rotação:<br />
⎡cosθ<br />
P ' =<br />
⎢<br />
⎢<br />
sinθ<br />
⎢⎣<br />
0<br />
− sinθ<br />
cosθ<br />
0<br />
0⎤<br />
⎡x⎤<br />
⎡x<br />
cosθ<br />
− y sinθ<br />
⎤<br />
0<br />
⎥ ⎢ ⎥<br />
=<br />
⎢<br />
⎥<br />
⎥ ⎢<br />
y<br />
⎥ ⎢<br />
xsinθ<br />
+ y cosθ<br />
⎥<br />
1⎥⎦<br />
⎢⎣<br />
1⎥⎦<br />
⎢⎣<br />
1 ⎥⎦<br />
Matrizes em Transformações Geométricas<br />
Matriz Ortogonal<br />
Uma matriz quadrada A é ortogonal se MM T = I. Portanto, se M é ortogonal então<br />
M -1 = M T<br />
Uma outra conseqüência é que se M é ortogonal então det M é igual a 1 ou -1.<br />
Propriedades:<br />
- Se A e B são ortogonais então C = AB também é ortogonal.<br />
- Se A é ortogonal então A -1 também é ortogonal.<br />
Uma matriz é dita é dita ortonormal se o comprimento de cada linha ou coluna, tomados como vetores, tem<br />
comprimento 1 (normalizado). Esses vetores também são mutuamente ortogonais (formam um ângulo de<br />
90 o cada (perpendiculares) – ver definição de produto interno/escalar).<br />
Teorema: Se M é uma matriz ortogonal, então M preserva comprimentos e ângulos. [1]<br />
Uma vez que matrizes ortonormais preservam ângulos e comprimentos, elas preservam a estrutura geral do<br />
sistema de coordenadas. Deste modo, podem apenas representar combinações de rotações e reflexões.<br />
Matrizes de translação não são ortonormais.<br />
⎡cosθ<br />
R =<br />
⎢<br />
⎢<br />
sinθ<br />
⎢⎣<br />
0<br />
− sinθ<br />
cosθ<br />
0<br />
0⎤<br />
0<br />
⎥<br />
⎥<br />
1⎥⎦<br />
V = [ sinθ cosθ ]<br />
V<br />
0<br />
[ cos θ − sinθ<br />
],<br />
= 45<br />
= θ<br />
V =<br />
V =<br />
2<br />
cosθ<br />
+ ( −sinθ<br />
)<br />
2<br />
0.707<br />
+ ( −<br />
2<br />
0.707)<br />
V = 0 .5 + 0.5 = 1 = 1<br />
2<br />
V =<br />
[ cosθ − sinθ ]<br />
5
⎡1<br />
R =<br />
⎢<br />
⎢<br />
0<br />
⎢⎣<br />
0<br />
0<br />
−1<br />
0<br />
0⎤<br />
0<br />
⎥<br />
⎥<br />
1⎥⎦<br />
V = [ 1 0]<br />
V = [ 0 −1]<br />
⎡cosθ<br />
R =<br />
⎢<br />
⎢<br />
sinθ<br />
⎢⎣<br />
0<br />
− sinθ<br />
cosθ<br />
0<br />
0⎤<br />
0<br />
⎥<br />
⎥<br />
1⎥⎦<br />
R<br />
−1<br />
=<br />
T<br />
R<br />
⎡ cosθ<br />
=<br />
⎢<br />
⎢<br />
− sinθ<br />
⎢⎣<br />
0<br />
sinθ<br />
cosθ<br />
0<br />
0⎤<br />
0<br />
⎥<br />
⎥<br />
1⎥⎦<br />
Combinações de Transformações<br />
Quando se deseja aplicar várias transformações a vários pontos, ao invés aplicar várias transformações a<br />
cada ponto, pode-se combinar todas as transformações em uma única matriz e então aplicar esta matriz<br />
resultante aos pontos do objeto, reduzindo-se assim o custo computacional.<br />
Este processo é chamado de concatenação de matrizes, e é executado multiplicando-se as matrizes que<br />
representam cada transformação.<br />
OBS: a multiplicação de matrizes não é comutativa, porém é associativa.<br />
AB≠BA (não comutativa)<br />
A(BC) = (AB)C (associativa)<br />
(FG) T = G T F T<br />
OBS: Deve-se observar a terceira propriedade: (FG) T = G T F T . Ou seja, a forma como a multiplicação é<br />
aplicada indica na ordem que os elementos devem estar dispostos.<br />
A seguinte matriz representa a concatenação de uma translação seguida de uma rotação. A rotação deve<br />
vir antes na multiplicação.<br />
P ' = RTP (Concatenação Correta)<br />
⎡cosθ<br />
− sinθ<br />
0⎤<br />
⎡1<br />
0 Tx<br />
⎤⎡x⎤<br />
P'<br />
=<br />
⎢<br />
⎥ ⎢ ⎥⎢<br />
⎥<br />
⎢<br />
sinθ<br />
cosθ<br />
0<br />
⎥ ⎢<br />
0 1 Ty<br />
⎥⎢<br />
y<br />
⎥<br />
⎢⎣<br />
0 0 1⎥⎦<br />
⎢⎣<br />
0 0 1 ⎥⎦<br />
⎢⎣<br />
1⎥⎦<br />
⎡cosθ<br />
− sinθ<br />
Tx<br />
cosθ<br />
− Ty<br />
sinθ<br />
⎤⎡x⎤<br />
P'<br />
=<br />
⎢<br />
⎥⎢<br />
⎥<br />
⎢<br />
sinθ<br />
cosθ<br />
Tx<br />
sinθ<br />
+ Ty<br />
cosθ<br />
⎥⎢<br />
y<br />
⎥<br />
⎢⎣<br />
0 0<br />
1 ⎥⎦<br />
⎢⎣<br />
1⎥⎦<br />
P ' = TRP (errado)<br />
⎡1<br />
P'<br />
=<br />
⎢<br />
⎢<br />
0<br />
⎢⎣<br />
0<br />
0<br />
1<br />
0<br />
Tx<br />
⎤⎡cosθ<br />
T<br />
⎥⎢<br />
y<br />
⎥⎢<br />
sinθ<br />
1 ⎥⎦<br />
⎢⎣<br />
0<br />
− sinθ<br />
cosθ<br />
0<br />
0⎤⎡x⎤<br />
0<br />
⎥⎢<br />
⎥<br />
⎥⎢<br />
y<br />
⎥<br />
1⎥⎦<br />
⎢⎣<br />
1⎥⎦<br />
6
⎡cosθ<br />
P'<br />
=<br />
⎢<br />
⎢<br />
sinθ<br />
⎢⎣<br />
0<br />
− sinθ<br />
cosθ<br />
0<br />
Tx<br />
⎤⎡x⎤<br />
T<br />
⎥⎢<br />
⎥<br />
y<br />
⎥⎢<br />
y<br />
⎥<br />
1 ⎥⎦<br />
⎢⎣<br />
1⎥⎦<br />
Observa-se que a transformação TRP≠RTP e que (FG) T = G T F T .<br />
Considerando-se P como P T , R como R T e T como T T , temos:<br />
P ' =<br />
P<br />
T<br />
T<br />
T<br />
R<br />
T<br />
P ' =<br />
[ x y 1]<br />
⎡ 1 0<br />
⎢<br />
⎢ 0 1<br />
⎢<br />
⎣T x<br />
T y<br />
0⎤⎡<br />
cosθ<br />
⎥<br />
0<br />
⎢<br />
⎥⎢<br />
− sinθ<br />
1⎥<br />
⎦<br />
⎢⎣<br />
0<br />
sinθ<br />
cosθ<br />
0<br />
0⎤<br />
0<br />
⎥<br />
⎥<br />
1⎥⎦<br />
P ' =<br />
[ x y 1]<br />
⎡<br />
⎢<br />
⎢<br />
⎢<br />
⎣T<br />
x<br />
cosθ<br />
− sinθ<br />
cosθ<br />
− T sinθ<br />
y<br />
sinθ<br />
cosθ<br />
T sinθ<br />
+ T cosθ<br />
x<br />
y<br />
0⎤<br />
⎥<br />
0⎥<br />
1⎥<br />
⎦<br />
No seguinte exemplo deseja-se aplicar uma rotação sobre o eixo do retângulo, ou seja, uma rotação no<br />
sistema de coordenadas local do objeto. Para isso, deve-se fazer uma mudança de sistema, ou seja, levar a<br />
origem (pivô) do sistema de coordenadas do objeto para a origem do sistema de coordenadas do mundo,<br />
aplicar a rotação, e transladar o objeto para seu sistema de coordenadas.<br />
Sistema de<br />
coordenadas<br />
local<br />
Neste tipo de aplicação, é necessário fazer transformações diretas e inversas, ou seja, deve-se aplicar uma<br />
matriz de transformação T e em seguida a sua inversa T -1 . O cálculo de matrizes inversas é complexo, porém<br />
é fácil determinar matrizes inversas de transformações geométricas.<br />
No caso da rotação, por ser uma matriz ortonormal, sua inversa de R(θ) é a transposta (o mesmo vale para<br />
matrizes de reflexão), o que é equivalente a R(-θ).<br />
No caso de uma matriz de translação T = [T x T y 1] T , T -1 é dada por T -1 =[-T x -T y 1] T .<br />
Para uma matriz de escala S = [S x S y 1] T , S -1 = [1/S x 1/S y 1] T<br />
Assim, para o exemplo anterior temos a seguinte matriz M que representa a concatenação de matrizes de<br />
transformação:<br />
M = TRT -1<br />
7
M<br />
⎡1<br />
=<br />
⎢<br />
⎢<br />
0<br />
⎢⎣<br />
0<br />
0<br />
1<br />
0<br />
Tx<br />
⎤⎡cosθ<br />
T<br />
⎥⎢<br />
y<br />
⎥⎢<br />
sinθ<br />
1 ⎥⎦<br />
⎢⎣<br />
0<br />
− sinθ<br />
cosθ<br />
0<br />
0⎤<br />
⎡1<br />
0<br />
⎥ ⎢<br />
⎥ ⎢<br />
0<br />
1⎥⎦<br />
⎢⎣<br />
0<br />
0<br />
1<br />
0<br />
− T<br />
− T<br />
1<br />
x<br />
y<br />
⎤<br />
⎥<br />
⎥<br />
⎥⎦<br />
onde T x e T y representam as coordenadas do sistema de coordenadas do objeto em relação ao sistema de<br />
coordenadas do mundo.<br />
No caso de rotações sucessivas em um mesmo eixo<br />
P’= R(θ 1 )R(θ 2 )P<br />
Por serem aditivas, a composição das duas rotações pode ser dada por<br />
Outros exemplos:<br />
Escala sem alterar a posição do objeto<br />
Rotação em um eixo arbitrário<br />
Rotações consecutivas no mesmo eixo<br />
Rotações consecutivas em diferentes eixos<br />
P’= R(θ 1 +θ 2 )P<br />
Implementação de Transformações<br />
Como ilustrado no exemplo anterior, em muitas situações é necessário aplicar (concatenar) várias<br />
transformações, incluindo rotação, escala e translações. Neste caso, para criar a matriz de rotação final M<br />
deve-se multiplicar várias matrizes.<br />
Antes de partir para uma implementação direta, deve-se observar como a API OpenGL faz para trabalhar<br />
com matrizes de transformação. Ele define uma única matriz “global”, que é atualizada a cada chamada de<br />
comandos glRotate(), glTranslate(), glScale(). A matriz corrente é então multiplicada pela nova matriz<br />
correspondente a transformação chamada. O seguinte código em C++ ilustra como criar uma classe para<br />
gerenciar a matriz de transformação.<br />
Class Matrix<br />
{<br />
float m[3][3]; //em coordenadas homogêneas<br />
public:<br />
Matrix();<br />
void operator *(Matrix m); //multiplica por outra matriz<br />
void loadIdentity(); //carrega matriz identidade<br />
void rotate(float ang); //concatena matriz de rotação<br />
void translate(float dx, float dy); //concatena matriz de translação<br />
void scale(float sx, float sy); //concatena matriz de escala<br />
Vector operator*(Vector v);<br />
//multiplica um ponto v pela matriz<br />
void push(); //empilha matriz (duplica o valor do topo)<br />
void pop(); //desempilha matriz (remove o topo da pilha)<br />
}<br />
Na prática, ao invés de ter uma única matriz, o OpenGL define uma pilha de matrizes de transformação, cuja<br />
posição topo pode ser modificada pelas funções glPushMatrix() e glPopMatrix(). Esse recurso é<br />
extremamente útil quando se tem em uma mesma cena um objeto que sofre movimentação relativa a outro<br />
objeto. Como exemplo, pode-se ter um carro que está em cima de um navio. Quando o navio se move, o<br />
veículo sofre a mesma transformação, porém nada impende que o veículo ande sobre o navio já em<br />
movimento.<br />
8
Outros usos das transformações de Escala e Translação<br />
Muitas vezes é necessário fazer a transformação de dados para um correto processamento ou exibição em<br />
um dispositivo.<br />
Exemplo 1:<br />
Considere por exemplo que seja necessário armazenar vetores de dados sinalizados em vetores não<br />
sinalizados. Considerando um tipo char, em um intervalo sinalizado temos valores entre [-128, 127].<br />
Aplicando-se uma translação nos valores de 128, temos os valores no intervalo [0, 255]. Adicionalmente<br />
pode-se aplicar uma escala nos valores, por exemplo, de 0.5, para transformar os valores no intervalo [0,<br />
128]. O processo inverso pode ser usado para levar os valores ao intervalo original.<br />
Exemplo 2:<br />
Suponha que se deseje desenhar na tela um círculo paramétrico (em coordenadas esféricas). As funções seno<br />
e cosseno geram valores entre [-1. 1]. Na tela, tem-se, por exemplo, valores entre [0, 1024]. Para se desenhar<br />
um círculo em tela cheia, deve-se fazer as seguintes transformações:<br />
- translação em 1 para levar o intervalo entre [0, 2]<br />
- escala em 512 para levar o intervalo entre [0, 1024]<br />
2 Primitivas Gráficas <strong>2D</strong><br />
Formas de Representação de primitivas:<br />
• Analítica (função):<br />
o Gasta menos espaço<br />
o Maior precisão (resolução)<br />
o Facilidade para calculo de pontos intermediários<br />
o Representação de Figuras vetoriais.<br />
o Ex: MS Word.<br />
• Discreta (pontos/pixels - Amostragem)<br />
o Usado para fazer a representação gráfica em dispositivos, como monitores ou impressoras.<br />
o Representações poligonais.<br />
o Ex: Modelos de personagens em jogos 3D, imagens BMP, arquivo de impressão, figuras na<br />
tela do computador<br />
Representação discreta e<br />
analítica de um círculo<br />
Erro de reconstrução<br />
Discretização<br />
amostragem<br />
Analítica<br />
Discreta<br />
Interpolação<br />
Reconstrução<br />
9
Representação analítica:<br />
1. Paramétrica: cada coordenada de um ponto é representado como uma função de um único<br />
parâmetro.<br />
2. Não Paramétrica<br />
a. Explícita y = mx + b<br />
para cada x, obtém-se apenas 1 valor de y. Ex: retas, senoides, etc.<br />
b. Implícita x 2 + y 2 = r 2<br />
para cada x, obtém-se 2 valores para y. Pode ser usado para representar círculos.<br />
Linha<br />
• Usos<br />
• Geralmente disponibilizado em APIs (Java, OpenGL, Directx, etc)<br />
• Representação paramétrica ou por função<br />
Representação por função Explícita<br />
y = mx + b<br />
m = inclinação da reta<br />
b = interseção com o eixo y.<br />
∆y<br />
m = =<br />
Λx<br />
y<br />
x<br />
b = y 1<br />
− mx 1<br />
∆ y = mΛx,<br />
2<br />
2<br />
− y1<br />
− x<br />
1<br />
Λy<br />
Λx<br />
=<br />
m<br />
(x 1 ,y 1)<br />
(x 2 ,y 2)<br />
Algoritmo DDA (Digital Differiential Analyser)<br />
y<br />
x<br />
1<br />
= yk<br />
+ m,<br />
0 < < 1<br />
1<br />
1<br />
= xk<br />
+ , > 1<br />
m<br />
k +<br />
m<br />
k +<br />
m<br />
Algoritmo DDA<br />
dx = x2 - x1<br />
dy = y2 - y1<br />
if (|dx| > |dy|)<br />
steps = |dx|<br />
else<br />
steps = |dy|<br />
incx = dx/steps<br />
incy = dy/steps<br />
pixel(x1, y1)<br />
for(k=0; k< steps; k++)<br />
{<br />
x += incx;<br />
y += incy<br />
pixel(x, y)<br />
}<br />
10
y c<br />
Representação Paramétrica<br />
x = x(t)<br />
y = y(t)<br />
P(t) = (x(t), y(t))<br />
Vetor direção<br />
P ( t)<br />
= P1 + t(<br />
P2<br />
− P1<br />
), 0 ≤ t ≤1<br />
(Uma multiplicação)<br />
P( t)<br />
= P1<br />
+ tP2<br />
− tP1<br />
P ( t)<br />
= (1 − t)<br />
P + tP<br />
(Duas multiplicações)<br />
1<br />
2<br />
ou<br />
P ( t)<br />
= P0 + tV , t ≥ 0 (representação de um raio)<br />
se t=0, P(t) = P 1<br />
se t=1, P(t) = P 2<br />
se t=0.5, P(t) = 0.5P 1 + 0.5P 2<br />
P 1<br />
P 2<br />
Independente da representação, deve-se observar que quando a linha é representada graficamente por um<br />
conjunto de pontos amostrados.<br />
Dependendo da resolução do dispositivo, pode ser visível a formação de bordas dentadas (Alias).<br />
Uma solução para evitar este problema, espacialmente em monitores onde a resolução é menor que<br />
100 DPI, deve-se utilizar algum algoritmo de anti-aliasing.<br />
Na seguinte figura é ilustrado como um algoritmo de anti-aliasing pode ser usado para gerar linhas que se<br />
pareçam mais suaves.<br />
Faz uso de pixels com intensidades diferentes, dependendo de sua área de projeção sobre a linha.<br />
Pixels que são cobertos pela linha tem cor mais escura e pixels que são parcialmente cobertos pela<br />
linha tem cor mais clara.<br />
4<br />
3<br />
2<br />
1<br />
1 2 3 4 5 6 7 8 9 10<br />
Círculo<br />
Função implícita do círculo<br />
2 2 2<br />
x + y = r<br />
y<br />
2<br />
= r<br />
y = ±<br />
2<br />
r<br />
− x<br />
2<br />
2<br />
− x<br />
2<br />
Não centrado na origem<br />
x c -r x c +r<br />
11
2<br />
2 2<br />
( x − xc ) + ( y − yc<br />
) = r , ( xc<br />
− r)<br />
≤ x ≤ ( xc<br />
+<br />
2 2<br />
2<br />
y − y ) = r − ( x − x )<br />
(<br />
c<br />
c<br />
y − y<br />
=<br />
x − x<br />
2<br />
(<br />
c<br />
) (<br />
c<br />
r<br />
−<br />
)<br />
2<br />
r)<br />
y = y<br />
c<br />
±<br />
r<br />
2<br />
−<br />
( x − xc<br />
)<br />
2<br />
Equação paramétrica do círculo<br />
x = x + c<br />
r cosθ (variação constante entre pontos na curva)<br />
y = y + c<br />
r sinθ<br />
Anti-aliasing para círculos: O processo é o mesmo utilizado para retas. As seguintes figuras ilustram<br />
curvas geradas com dois tipos de algoritmos de anti-aliasing (imagens de lentes de câmeras -<br />
http://nikonimaging.com/global/products/lens/af/dx/index.htm). As figuras da direita são ampliações das<br />
figuras da esquerda. Pode-se claramente notar a diferença de qualidade das imagens. Deve-se observar que<br />
se estas imagens fossem geradas sem algoritmos de anti-aliasing, o resultado seria bem pior.<br />
Bom algoritmo de<br />
anti-aliasing<br />
Algoritmo ruim de<br />
anti-aliasing<br />
Assim como primitivas, algoritmos de anti-aliasing também são muito utilizados para geração de<br />
caracteres. A seguinte figura ilustra a geração de caracteres gerados pelo editor Word. Pode-se<br />
observar a adição de pixels coloridos nas bordas dos caracteres.<br />
12
Elipse<br />
x = a cosθ (variação não constante entre pontos na curva) [4] pg. 220<br />
y = bsinθ<br />
θ<br />
Superquádricas<br />
Superelípse<br />
⎛<br />
⎜<br />
⎝<br />
x<br />
r<br />
x<br />
⎞<br />
⎟<br />
⎠<br />
2<br />
s<br />
⎛<br />
+ ⎜<br />
⎝<br />
y<br />
r<br />
y<br />
⎞<br />
⎟<br />
⎠<br />
2<br />
s<br />
= 1<br />
paramétrica<br />
x =<br />
y =<br />
r x<br />
r y<br />
cos<br />
sin<br />
s<br />
s<br />
θ<br />
θ<br />
s=0.5 s=1 s=1.5 s=2 s=3<br />
Poligonal<br />
Vetor ordenado de coordenadas que definem a forma do objeto. Pode ser usado para representar qualquer<br />
figura. Apresenta limitações para desenho de curvas.<br />
Preenchimento de Polígonos<br />
Scan-line<br />
y mínimo<br />
Faz o preenchimento da cena de linha em linha<br />
sentido de deslocamento<br />
da scan-line<br />
scan-line<br />
y máximo<br />
13
Faz uso da inclinação de cada reta para otimizar o processo.<br />
z-buffer<br />
Usado pelo OpenGL para preenchimento de polígonos em 3D. Faz o preenchimento da cena de polígono em<br />
polígono.<br />
Flood/Boundary fill<br />
Contorno boundary fill<br />
Cor de fundo flood fill<br />
4-connected<br />
8-connected<br />
void boundaryFill4(int x, int y, int fill, int boundary)<br />
{<br />
int cur = getPixel(x, y)<br />
if( cur!=boundary && curr!=fill)<br />
{<br />
setPixel(x, y, fill)<br />
boundaryFill4(x+1, y, fill, boundary)<br />
boundaryFill4(x-1, y, fill, boundary)<br />
boundaryFill4(x, y+1, fill, boundary)<br />
boundaryFill4(x, y-1, fill, boundary)<br />
}<br />
}<br />
void floodFill4(int x, int y, int fill, int oldColor)<br />
{<br />
if(getPixel(x, y) == oldColor)<br />
{<br />
setPixel(x, y, fill)<br />
floodFill4(x+1, y, fill, oldColor)<br />
floodFill4(x-1, y, fill, oldColor)<br />
floodFill4(x, y+1, fill, oldColor)<br />
floodFill4(x, y-1, fill, oldColor)<br />
}<br />
}<br />
3 Visualização Bidimensional<br />
Window área selecionada do sistema de coordenadas do mundo para ser exibida no display (área que será<br />
vista). Deve-se observar que nem toda área de um ambiente pode ser exibida em uma única window. Esta<br />
área é determinada pela configuração e posicionamento da câmera sintética.<br />
Viewport área do display (monitor) na qual a window é mapeada. Corresponde a posição na tela onde<br />
mostrar. Ex: janela gráfica de uma aplicação gráfica.<br />
Viewing transformation (ou windowing transformation) mapeamento de uma parte da cena em<br />
coordenadas do mundo para coordenadas do dispositivo.<br />
Deve-se observar que as coordenadas do mundo podem estar no intervalo entre [1, 1] e que as<br />
coordenadas da viewport sempre estão em resolução de tela.<br />
A principal transformação é a escala, que pode não ser uniforme.<br />
Passos:<br />
<br />
Definir a área da window<br />
14
Recortar o que está fora (clipping)<br />
Ajustar posição e escala dentro da viewport (mapeamento)<br />
window<br />
viewport<br />
mundo<br />
dispositivo<br />
Algoritmos de Clipping<br />
<br />
<br />
<br />
<br />
Linhas (Cohen-Sutherland)<br />
Polígonos (Weiler-Atherton)<br />
curvas<br />
strings<br />
Mapeamento na tela<br />
<br />
<br />
Sistema cartesiano define origem no canto inferior esquerdo<br />
Sistema de tela define a origem no canto superior esquerdo<br />
o Ex: OpenGL/Glut, Java, etc.<br />
o<br />
(0,0)<br />
cartesiano<br />
(0,0)<br />
window<br />
viewport<br />
h<br />
(0,0)<br />
x<br />
tela<br />
= x cartesiano<br />
y = h −<br />
tela<br />
y cartesiano<br />
Referências:<br />
[1] Lengyel, E.. Mathematics for 3D Game Programming and Computer Graphics. Charles River<br />
Media, 2002.<br />
[2] Hearn, D., Baker, M. P. Computer Graphics, C Version (2 nd Edition), Prentice Hall, New Jersey, 1997<br />
[3] Foley, J.D., van Dam, A., Feiner, S.K. and Hughes, J.F. Computer Graphics: Principles and Practice<br />
in C (2 nd Edition), Addison-Wesley Pub. Co., Reading, MA, 1995.<br />
[4] Watt, A. 3D Computer Graphics, Addison Wesley; 3 edition,1999.<br />
[5] Rogers, D., Adams, J. Mathematical Elements for Computer Graphics, 2 nd Edition. Mc Graw Hill, 1990.<br />
15