En ésta entrada comenzaremos a desarrollar la teoría necesaria para el desarrollo de videojuegos. Empezaremos con una de las cosas más básicas: Como transformar los objetos
En geometría, normalmente se trabaja sobre tres tipos de transformaciones: Traslación, escalado, y rotación.
- 2.1: Traslación
Imaginemos que tenemos un polígono formado por 5 vértices, con centro en el punto C(1,1), y queremos mover el polígono de manera que su centro acabe en el punto C'(4,2):
Pues bien, lo único que tenemos que hacer es calcular cuanto se tiene que desplazar el centro, y en que dirección. Es decir, calcular el vector CC'. Una vez que tenemos éste vector, basta sumárselo a todos los vértices para que nos den sus nuevas posiciones.
- 2.2: Escalado
El escalado no es mucho más complicado. Lo que queremos hacer es que nuestro polígono aumente de tamaño de manera uniforme. Pues bien, para cualquier punto, si multiplicamos sus coordenadas por un factor k, conseguimos que el punto esté k veces mas lejos del origen de coordenadas. Así, si queremos hacer nuestro polígono el doble de grande, solo tendremos que multiplicar las coordenadas de sus vértices por dos.
¿Cual es el problema? Que si el centro del polígono no está en el origen de coordenadas, si lo escalamos, también lo trasladamos. Para solucionar ésto, solo tenemos que mover el polígono para que su centro esté en el origen, escalarlo, y devolver el centro a su posición original. De manera que lo que tenemos es:
Transformación= Traslación -> Escalado -> Traslación inversa
- 2.3: Rotación
El método de traslación y escalado es exactamente el mismo para 2d y 3d, pero con la rotación no ocurre lo mismo, ya que el método "tradicional" de rotación produce algunos problemas. Pero para hacer las cosas más sencillas, por ahora solo lo explicaré en 2d.
Por ejemplo, queremos rotar el punto A(1,1) +90º (El sentido positivo es el antihorario) alrededor del origen:
Dados dos ángulos a y b, tenemos que:
sin(a+b) = sin(a) * cos(b) + sin(b) * cos(b)
cos(a+b) = cos(a) * cos(b) - sin(a) * sin(b)
De manera que:
Ax = r * cos(a)
Ay= r * sin(a)
Siendo r el modulo del vector que va desde el origen a A, y a el angulo entre dicho vector y la horizontal (45º)
Si b es el ángulo de rotación (90º) tenemos:
A'x= r * cos(a+b) = r * ( cos(a) * cos(b) - (sin(a) * sin(b) ) = r * cos(a) * cos(b) - r* sin(a) * sin(b)
A'y= r * sin(a+b) = r * ( sin(a) * cos(b) - (cos(a) * sin(b) ) = r * sin(a) * cos(b) - r* cos(a) * sin(b)
Sustituyendo Ax y Ay:
A'x = x * cos(b) - y * sin(b)
A'y = x * sin(b) + y * cos(b)
Efectivamente, si sustituimos los datos de nuestro ejemplo en las dos fórmulas obtenidas, nos sale A'(-1,1)
- 2.4: Concatenación de transformaciones. Matrices
Como se ha visto, los cálculos de los tres tipos de transformaciones son muy diferentes entre sí. Pero para que la aplicación de transformaciones sea eficiente, es necesario un método que permita encadenar diferentes tipos de transformaciones de manera sencilla. Ésto se consigue mediante el producto de matrices.
El método consiste en representar cada tipo de transformación mediante una matriz característica, de manera que para encadenar varias transformaciones únicamente hay que premultiplicar las matrices de las transformaciones.
Además, para poder aplicar la transformación a un punto cualquiera, basta representar las coordenadas del punto mediante una matriz (fila o columna), y premultiplicarla por la matriz de la transformación.
Así, a la traslación definida por el vector V(x,y), le corresponde la matriz:¡
1 0 x
0 1 y
0 0 1
Y a un escalado K le corresponde:
k 0 0
0 k 0
0 0 1
Por último, la rotación de un ángulo a alrededor del origen es:
cos(a) sin(a) 0
-sin(a) cos(a) 0
0 0 1
De ésta manera, la matriz de transformación T que genera un escalado k desde un punto P(x,y), caso que veíamos al final del escalado, será:
T = Traslación(-x,-y) -> Escalado(k) -> Traslación(x,y)
Es decir:
1 0 x k 0 0 1 0 -x k 0 x - kx
T = 0 1 y * 0 k 0 * 0 1 -y = 0 k y - ky
0 0 1 0 0 1 0 0 1 0 0 1
x x'
Si P = y , P' = y' entonces:
1 1
P'= T * P
NOTA: Las matrices que he mostrado se corresponden con la representación de coordenadas en matrices columna.
Conclusión:
Como hemos visto, el álgebra necesaria para la transformación de objetos es muy sencilla. De hecho, la gran calidad gráfica de los videojuegos actuales se debe a que éstos y otros algoritmos son ejecutados por la GPU, la cual cuenta con hardware específicamente diseñado para ello. Una GPU de gama media actual es capaz de procesar escenas con más de un billón de vértices. ¿Como lo consigue? Como el cálculo de transformaciones es muy sencillo, lo que hace es ejecutar dicho cálculo paralelamente, lanzando miles de hilos de ejecución, cada uno con la tarea de ejecutar la transformación a un vértice.
Consideraciones sobre implementación:
A la hora de implementar éstos cálculos, mi recomendación es no implementar un punto como una estructura/clase con un campo de coma flotante por coordenada, ya que tendrás que calcular la matriz columna una y otra vez. Mejor implementarlo con un único campo que se corresponda con la matriz columna, y modificar los elementos apropiados de dicha matriz si se desea modificar las coordenadas directamente.
Y recordad: Al aplicar las transformaciones, siempre se premultiplica. Así si tenemos la cadena de transformaciones Transformación = Transformación1 -> Transformación2 -> ... -> TransformaciónN
la matriz T resultante es: TN * TN-1 * TN-2 *...* T1
No hay comentarios:
Publicar un comentario