09.28.08
Porque lo llaman “convenciones” cuando quieren decir “libre albedrío”…
Estos días en casa estoy empezando a hacer desde cero lo que probablemente sea mi última iteración como programador de gráficos/juegos/whatever, y como siempre me surgen las eternas pequeñas dudas que una y otra vez acabo consultando en diferentes webs. El problema de esto es que muchas veces te encuentras cosas contradictorias, ya sea porque o tú mismo no lo has leido bien, o el tio que ha escrito sobre el tema no sabe de que coño habla, o al igual que tu se ha basado en otras webs y las ha tomado como los 10 mandamientos.
Un claro ejemplo de lio a la hora de buscar referencias es el tema de las matrices y las transformaciones, sobretodo en gráficos. ¿Quien no se ha metido alguna vez en una conversacion de “left handed / right handed” y ha salido de ella con dolor de cabeza? Parece que cada uno entendemos las cosas de distintas formas y nos acabamos haciendo la picha un lio.
Estos días que estoy con mi revictoring de la muerte he tenido que remirarme esta mierda una vez mas, pero esta vez he pensado que seria bueno dejar aqui escrito una pequeña explicación sobre el tema. Quien sabe, quizá algún día cuando yo ya no esté por estos lares programantiles las futuras generaciones lo lean y digan “coño, menos mal que estaba aqui el articulillo este, porque ya me estaba rajando las venas con el tema…”
En el tema de las transformaciones con matrices y su uso para gráficos hay dos cosas que hay que tener claras desde el principio: la manera en que definimos las matrices (layout) y el sitema de coordenadas que estamos usando (left handed o right handed). El origen de todo mal está en que mezclamos los dos conceptos y tendemos a convertirlo en uno solo, y lo llamamos como nos parece. Muchas veces leemos los articulos en vertical y buscamos “left” o “right” para saber en que formato estan las cosas…. y la cagamos.
A la hora de transformar un vector usando una matriz podemos hacerlo de dos maneras: Multiplicando el vector por la matriz o multiplicando la matriz por el vector. Esta elección es la que define el formato (layout) de todas las matrices y vectores que vayamos a usar, ya que la operación de multiplicacion de matrices es: M[i,j] * M[j,k] =M[i,k]
De este modo si queremos multiplicar un vector 3D por una matriz de 3×3 está claro que el vector viene a ser una matriz de 1 fila y 3 columnas y el vector resultante de la operación será otro vector de 1 fila y 3 columnas. A este tipo de vectores los llamamos vectores fila, y a la operacion de transformacion la llamamos pre-multiplicar, porque el vector (o la matriz fila, como lo quieras llamar) que queremos transformar va antes que la matriz que se usa para la transformacion.
La otra manera de hacerlo es multiplicando la matriz por el vector que queremos transformar. Es decir multiplicar la matriz de 3×3 por una matriz de 3×1 y nos saca otra matriz de 3×1. A este vector lo llamamos del tipo vector columna.
Para que ambas convenciones del el mismo resultado (pq sinó ya me dirás tu que hacemos) está claro que hay que hacer algo con las matrices que se usan en la transformacion. Puesto que hay 2 maneras de representar el vector a transformar tambien hay 2 maneras de representar la matriz a transformar. Es lo que se llaman las matrices fila y matrices columna. Las primeras se usan para operar con vectores fila y las segundas con vectores columna. Para entender la diferencia entre ellas podemos pensar en la manera en la que se guardarian en memoria estas matrices. En el caso de las matrices fila se guardaria en memoria primero la primera fila seguido de la segunda y asi consecutivamente. En el caso de las matrices columna se guardaria primero el primer elemento de cada fila, despues el segundo elemento de cada fila, y asi consecutivamente. En la practica obviamente no vamos a tener 2 tipos de matrices en nuestro codigo que almacenen los datos de distinta manera. Lo que se suele hacer es hacer la traspuesta de la matriz en cuestion para pasarla de un tipo a otro.
La mayoria de literatura que se encuentra por ahí está escrita por matemáticos, y en su mundo perfecto lleno de números lo que se usa son los vectores columna. Los matemáticos son gente de ideas fijas, por lo que no os recomiendo intentar llevarles la contraria cuando encotreis referencias por ahi :P. Yo soy mas de la filosofia “be water” de mi amigo Bruce Lee (tb soy un gran fan de su hermano Simón :P), por lo que os recomiendo que os adapteis y en vuestro código useis la convención de los vectores columna y las matrices columna. Si lo haceis la teoria deberia ser únicamente copy pastear las transformaciones modernas que os encontreis en vuestro libro preferido de algebra y 3D.
Una forma facil de identificar una matriz es ver donde tiene puesta su operacion de traslacion, si está en la ultima fila es una matriz fila y si está en su última columna es una matriz columna… fácil
Ahora viene la otra mitad del invento. Existe otra convención a tener en cuenta a la hora de hacer operaciones con matrices, y es en el sistema de coordenadas que se está usando. La coña de left y right handed: Si colocamos el dedos pulgar, indice y anular de forma que formen un eje de coordenadas el pulgar es el eje X, el indice el Y y el anular el Z. Ahora bien, si lo hacemos con la mano derecha y luego con la izquierda vemos que el eje Z va en la misma direccion pero en sentido contrario. Esta es la diferencia entre ambos sistemas, y es algo con lo que tener cuidado cuando creamos (o sea copiamos cual piratones) nuestras matrices. A ver, las transformaciones son siempre las mismas, no cambian por ser right o left handed, las matemáticas son siempre las mismas, lo importante es que tengais en cuenta que en un sistema el eje z va hacia adelante y en otro hacia atras, con lo cual podeis encontraros que una rotacion vaya en el sentido contrario al que esperabais y cosas por el estilo…
Por último un apunte sobre quien usa cada cosa. OpenGL usa right handed, o sea la X a la derecha, la Y hacia arriba y la Z positiva hacia fuera de la pantalla. Las matrices son por columnas. DirectX es al revés, le gustan las matrices por fila, y el sistema de coordenadas es left handed. Para cambiar de uno a otro lo mas normal viene siendo multiplicar por una matriz identidad con el componente de la Z puesto a -1, y en el caso de las matrices pos andar con ojo de si multiplicas A·B o B·A segun el caso, o hacer traspuestas…
Seguro que todos vosotros habeis hecho alguna vez el probar dististas combinaciones a saco hasta que saliera la cosa como esperabais… espero que con esto tengais un poco mas claro como va el invento y no sigais dedicandoos a hacer guarradas ![]()
buy_vigrxplus said,
July 18, 2009 at 2:29 am
The best information i have found exactly here. Keep going Thank you
LnddMiles said,
July 25, 2009 at 9:11 am
Pretty cool post. I just stumbled upon your blog and wanted to say
that I have really liked reading your blog posts. Anyway
I’ll be subscribing to your blog and I hope you post again soon!