|
Todos nós estudamos matrizes no segundo grau. Entretanto, a maioria de nós faz isso se perguntando qual é a sua utilidade, e o porquê de tantos cálculos. O que muitos não sabem é que são justamente as matrizes as grandes responsáveis por todos os gráficos 3D dos jogos atuais. Que tal ler esse artigo e descobrir o como?
Coordenadas cartesianas
Você deve estar lembrado que sempre que desenhamos coisas usamos para isso um sistema coordenado, chamado de coordenadas cartesianas. Ele foi inventado por Renatus Cartesius, mais conhecido no Brasil como René Descartes. Nesse sistema, cada ponto é representado em 2D por um par de valores, indicando sua linha e sua coluna:

Você pode imaginar que embaixo desse sistema de coordenadas hipotético, está uma folha de papel, ou mesmo o monitor do seu computador. Tanto faz. O importante é sabermos que, as coordenadas exatas dos pontos são apenas uma referência, uma convenção.
Por exemplo. Digamos que giraremos a folha de papel em 20o no sentido horário, e então iremos colocá-la por cima da folha anterior, e redesenhar o carro, exatamente no mesmo local, por cima de sua “sombra”. Obteríamos a seguinte imagem:

Sem dúvida, não houve qualquer modificação no desenho do carro, ele está exatamente no mesmo local. Entretanto, no novo sistema de coordenadas, ao ajeitarmos a folha, esse carro pareceria ter girado 20o no sentido anti-horário, veja:

O que fizemos no final, ajeitar a folha, é um processo chamado de transformação de coordenadas. Simplesmente pegamos as coordenadas que estavam num sistema (o da folha girada) e as transformamos elas num outro sistema (o da folha normal).
E o que matrizes têm a ver com tudo isso? Tudo.
Representação matemática do sistema de coordenadas
Considere um sistema de coordenadas qualquer, ainda com duas dimensões, e que sobre ele utilizemos vários pontos pra traçar uma figura.

Sabemos que o ponto superior direito dessa figura deve ter uma coordenada positiva de grande valor, como (100,120) ou (10,12) e o seu valor exato não nos importa agora.
A figura por ter sido construída aí, segue uma regra: ela é proporcional a esse sistema. Ou seja, se a figura tem 5cm de largura e 6cm de altura, e a unidade desse sistema for o milímetro, então, o canto superior direito dessa figura será (50,60)mm.
Agora, imaginemos os eixos coordenados dessa figura como dois vetores, chamados vetores de base e, como seu tamanho, atribuiremos o valor um. Novamente, o tamanho os pontos da figura não importam, e sim o fato deles serem equivalentes de 1:1 com esse nosso eixo:

Vamos escrever cada um desses valores em uma tabelinha?
| Ordenadas (x) | Abscissas (y) | |
| X | 1 | 0 |
| Y | 0 | 1 |
Note como os valores, destacados com cores, foram transportados para as colunas da tabelinha. Se retirarmos os títulos, acabaremos com uma matriz que representa esse nosso sistema de coordenadas.
![]()
Se você lembrar-se das suas aulas do segundo grau, se lembrará que esta é a matriz identidade. Ela tem uma propriedade interessante: qualquer matriz multiplicada pela identidade, não altera seu valor. Ou seja, é como se essa matriz representasse o número um numa multiplicação. Como sabemos, qualquer coisa multiplicada por um não altera seu valor.
Procure se lembrar dessa informação. Ela será importante em breve.
Vetores e matrizes
Você deve se lembrar que vetores podem representar pontos. Não se lembra? Então confira rapidamente nosso artigo sobre vetores.
Por exemplo, o ponto do canto superior direito daquela figura que no exemplo calculamos ser (50,60), poderia ser representado pelo seguinte vetor:
![Vetor [50,60] Vetor [50,60]](http://www.pontov.com.br/site/images/stories/artigos/Matrizes-e-Transformaes--Parte-1_14AA1/clip_image0028.jpg)
O que muitos não sabem, é que esse vetor pode ser representado como uma matriz de uma linha, e duas colunas, como essa aqui: ![]()
Ou mesmo como uma matriz de uma única coluna e duas linhas, como essa:
Como a notação de coluna é difícil ocupa muito espaço escrita, podemos usar a notação de linha, através da matriz transposta: [50 60]T.
Você deve estar se perguntando. E daí? Se você ainda não reparou, uma vez que um vetor é representado por uma matriz, isso também significa que ele pode ser multiplicado por uma matriz. E essa multiplicação permite-nos transformar um vetor que está num sistema de coordenadas qualquer, em um vetor em outro sistema.
Usar linhas ou colunas tem uma implicação importante: Matrizes linhas representam o sistema de coordenadas da mão esquerda. Nele, as funções de rotação funcionam no sentido horário, e as transformações ocorrerão na ordem em que são multiplicadas. Na matriz coluna, as rotações ocorrem em sentido anti-horário, e as transformações ocorrem em ordem inversa da multiplicação. Utilizaremos nessa série de artigos as matrizes colunas, pois são padrão em muitas APIs e livros de computação gráfica, por serem adotadas na OpenGL.
Já as matrizes linha são comumente usadas no DirectX, não é à toa que estão presentes em nossos artigos de XNA e shaders.
Multiplicação de matrizes
Antes de continuarmos, vamos lembrar como se dá a multiplicação de matrizes. Ao multiplicar duas matrizes A e B, calculamos cada elemento Cij (onde i é a linha e j a coluna) usando de um processo simples:
- Na matriz A, pegamos os elementos da linha i, que queremos calcular;
- Na matriz B, pegamos os elementos da coluna j, que queremos calcular;
- Então, multiplicamos esses elementos entre si, e somamos os seus produtos. Note que para que essa multiplicação seja possível, o número de colunas de A, deve ser exatamente igual ao número de linhas de B.
Ainda perdido? Veja abaixo como calculamos o elemento c24:

Se você como eu sempre se perde nesses cálculos. Eis uma forma mais gráfica de representar: desenhe a matriz C, e sobre ela a matriz B e a sua esquerda a matriz A. Os elementos usados para calcular um valor em C estarão na mesma linha em A, e na mesma coluna em B, observe:

Agora que revisamos, vamos voltar ao tema.
Transformações lineares
Escala
Podemos usar matrizes para representar outros eixos coordenados, diferentes do eixo de base. Basta, para isso, imaginarmos como esse eixo seria.
Por exemplo, vamos supor que queiramos ampliar uma imagem em duas vezes. Isso significa que queremos que seu eixo de base seja duas vezes maior que nosso próprio eixo, certo?

Portanto, usando as proporções do segundo eixo como uma matriz, teríamos:
![]()
Com essa matriz, podemos transformar qualquer ponto do sistema de base, num ponto do sistema escalado. Para isso, a matriz de escala e multiplicar pelo vetor que queremos ampliar. Tomemos como exemplo o nosso vetor [50 60], citado anteriormente:
![]()
Não surpreendentemente, os pontos dobraram de valor. Para ampliar uma figura inteira, multiplicaríamos o vetor que representa cada um de seus pontos. Se você está achando que é muito trabalho para pouco resultado, continue lendo o artigo.
Rotação
Alterar o tamanho não é a única coisa que podemos fazer com transformações lineares. O que aconteceria se no lugar da matriz
usássemos a matriz
?
Veja um eixo sobre o outro:

Note que agora não só alteramos o tamanho da imagem, como também alteramos a inclinação dos eixos. Como conseqüência, a transformação final também será inclinada (nesse caso, em 26o).

Se lembrarmos da formula sobre como criar um vetor baseado num ângulo, poderemos facilmente chegar a uma matriz, que faz uma rotação qualquer. Se você não se lembra, criamos um vetor de tamanho t, baseado num ângulo α com a função:
Vector2D Vector2D::bySizeAndAngle(float size, float angle)
{
return Vector2D(
cos(angle) * size,
sin(angle) * size);
}
Ou seja, equivalente à formula:
![]()
Se na hora de montar nosso novo sistema coordenado esse for o vetor de um dos eixos, então, seu vetor perpendicular a ele, será o vetor do outro eixo. Há uma regra simples para achar um vetor perpendicular. Basta inverter a posição dos dois valores, e o sinal do de um deles. Por exemplo, se o vetor em questão é (x,y) seu perpendicular será (-y, x).
Dessa forma, como queremos alterar apenas o ângulo, teremos t = 1, e formamos seguinte sistema em azul, sobre nosso sistema base, em cinza:

E com isso, podemos deduzir a matriz de rotação genérica, que é:
![]()
Repare bem que a primeira linha dessa matriz é exatamente a fórmula do método Vector2D::bySizeAndAngle. E note que a segunda, nada mais é que seu vetor perpendicular.
Assim, se tivermos um vetor (x,y) qualquer, sua rotação será definida por:
![]()
A fórmula acima te causa arrepios? Dê uma olhada no método rotate da classe Vector2D. Reconhece essa fórmula?
Vector2D& Vector2D::rotate(float angle)
{
float s = sin(angle);
float c = cos(angle);
float newX = x * c - y * s;
float newY = x * s + y * c;
x = newX;
y = newY;
return *this;
}
Transformações combinadas
Um detalhe interessante. Você pode ter notado que ambas as matrizes de transformação podem ser multiplicadas umas pelas outras. Porém, essa operação faria sentido? O que ocorreria se multiplicássemos uma matriz por outra?
A resposta é que obteríamos uma terceira matriz que realiza as duas operações ao mesmo tempo.
Se isso não parece muito interessante, vamos calcular um pouco. Suponha que você tenha uma figura formada por 2000 pontos. Se você aplicar individualmente a rotação e a escala, terá feito 4000 operações (2000 rotações e 2000 escalas). Porém, se você primeiro multiplicar as matrizes, fará ao final apenas 2001 operações: a primeira será a multiplicação da matriz de rotação R, pela matriz de escala E, obtendo a matriz composta C. E em seguida, 2000 multiplicações dos vetores dos pontos por C.
Ou seja, você pode ter dezenas de transformações, que elas impactarão muito pouco no tempo total de cálculo.
Um detalhe importante: Lembre-se que a multiplicação de matrizes não é comutativa. Portanto, a ordem que a multiplicação dessas matrizes ocorre afeta o resultado. Veremos exemplos disso no próximo artigo.
Concluindo
Nesse artigo, vimos que matrizes representam um papel importante na computação gráfica. Elas são usadas para transformar coordenadas de um sistema qualquer em outro. No artigo, vimos às transformações lineares, que são capazes de fazer rotação e escala em qualquer eixo.
Vimos também que matrizes graficamente podem representar um sistema de coordenadas, proporcional a outro sistema qualquer, chamado de sistema base. E, principalmente, vimos como entender essas matrizes de maneira gráfica.
No próximo artigo, abordaremos também as transformações afins (AffineTransforms), que acrescentam a operação de afastamento (translação).
-
08/02/2011 11:47:39 | Vinícius Godoy de Mendonça

Sim, a idéia é chegar lá. Usar matrizes para explicar um grafo de cena e, depois, partir talvez para orientação no espaço (ângulos de Euler, vetor e ângulo, etc...)
Talvez até dê para entrar em geometria 3D, mas é um campo um pouco mais árido. Vou pensar certinho em como abordar esse assunto de maneira mais prática.
-
10/02/2011 14:54:17 |200.170.114.xxx| Marcos Vasconcelos

Muito bom artigo, é interessante saber como isso funciona para criar jogos de qualidade.
E ai está um bom exemplo que mostra que vetores não servem apenas para movimento.
-
23/02/2011 21:30:56 |201.68.146.xxx| droidevr

Mais um belo artigo do pontov!
Estou passando por todos os artigos. O material do site de vocês é muito bom.
Ainda não apliquei o conteudo na prática, pois estou fazendo um jogo 2D e por enquanto consigo seguir, mas futuramente estarei aprofundando no seu artigo.
O mercado de games, ainda mais com mobiles está crescendo no Brasil, vocês vão ser a referência para gamedev.
Continuem assim.
-
23/02/2011 21:39:35 | Vinícius Godoy de Mendonça

Valeu Droide. O interessante é que essas transformações que citei nesse artigo e citarei no próximo podem ser aplicadas em jogos 2D.
O Java2D, por exemplo, tem a classe AffineTransform, que nada mais é que uma representação das matrizes de transformação.
E creio que nem precisa dizer que as matrizes dessa forma são a base para jogos 3D, não é mesmo?
-
13/04/2011 12:01:25 |2.82.93.xxx| Anônimo

Podias colocar uma representação matemática das coordenadas cartesianas de uma matriz 3*3?
-
13/04/2011 13:25:15 | Vinícius Godoy de Mendonça

Não entendi. No artigo há diversos exemplos. O que exatamente vc não entendeu?
No 3x3, a única diferença é que teremos um terceiro eixo.
-
22/04/2011 13:18:49 |201.68.17.xxx| Fernando

Muito bom o artigo! Parabéns!!
Estou fazendo pesquisas para fazer meu TCC de Especialização em matemática!!
Com esse artigo pude tirar algumas dúvidas, e conhecer um pouco mais!
Parabéns!
-
22/04/2011 17:47:39 | Vinícius Godoy de Mendonça

Obrigado. Semana que vem sai a segunda parte do artigo.
-
31/08/2011 15:08:58 |200.179.192.xxx| andressa - parabens

nao sou boa em matematica e vc conseguiu me deixar mais maluca a inda
-
31/08/2011 15:13:35 | Vinícius Godoy de Mendonça

E o pior é que essa matéria é a base de toda a computação gráfica moderna. É isso que deu origem aos jogos 3D e efeitos especiais de filmes. Certamente é mais interessante saber que matrizes tem alguma utilidade prática, do que a forma que as estudamos no segundo grau: sem ter a menor noção da sua utilidade.

-
05/11/2011 15:33:12 |189.35.66.xxx| Renato Reis

Excelente! Ótimo artigo. Quanto mais leio sobre matemática na computação, mais me apaixono pelas duas coisas.
Matemática é linda, pura poesia.
-
21/12/2011 18:08:43 |200.129.242.xxx| Bernardo Biesseck - Co

Olá Vinícius, ótimo texto!
Só uma correção: no tópico Representação matemática do sistema de coordenadas, no qual você colocou a figura da vaquinha, você fala do canto superior esquerdo, mas apresenta as coordenadas do ponto no canto superior direito. Acredito que a correção ajudaria a evitar confusões.
Abraço!
-
22/12/2011 09:17:13 | Vinícius Godoy de Mendonça

Ooops. Tem razão. Já está corrigido. Obrigado pelo aviso!












Cara muito bom o artigo.
Eu pessoalmente gosto muito de ler artigos matemáticos sobre a área, pois esses conceitos se mantém independente da engine e ou api utilizada.
Fica como sugestão e pedido meu para próximos artigos, algo sobre Quaternions e geometria 3D, é muito dificil achar algo em portugues sobre (pelo menos eu não achei muitos).