Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Programming

Construyamos un motor gráfico 3D: Transformaciones lineales

by
Read Time:10 minsLanguages:
This post is part of a series called Let’s Build a 3D Graphics Software Engine.
Let's Build a 3D Graphics Engine: Points, Vectors, and Basic Concepts
Let's Build a 3D Graphics Engine: Spaces and Culling

Spanish (Español) translation by Esther (you can also view the original English article)

Bienvenidos a la segunda parte de nuestra serie sobre el motor gráfico 3D. Esta vez vamos a hablar de las transformaciones lineales, que nos permitirán alterar propiedades como la rotación y el escalado de nuestros vectores, y veremos cómo aplicarlas a las clases que ya hemos construido.

Si aún no has leído la primera parte de esta serie, te sugiero que lo hagas ahora. Por si acaso no lo recuerdas, aquí tienes un rápido resumen de lo que creamos la última vez:

Esas dos clases serán la base de todo nuestro motor gráfico, donde la primera representa un punto (una ubicación física dentro de tu espacio) y la segunda representa un vector (el espacio/movimiento entre dos puntos).

Para nuestra discusión sobre las transformaciones lineales, deberías hacer un pequeño cambio en la clase Punto: en lugar de dar salida a los datos en una línea de la consola como antes, utiliza tu API gráfica favorita y haz que la función dibuje el punto actual en la pantalla.


Fundamentos de las transformaciones lineales

Solo una advertencia: Las ecuaciones de transformación lineal parecen mucho peores de lo que son en realidad. Habrá algo de trigonometría involucrada, pero no tienes que saber realmente cómo hacer esa trigonometría: Te explicaré lo que tienes que dar a cada función y lo que obtendrás, y para las cosas intermedias puedes usar cualquier calculadora o biblioteca matemática que tengas.

Consejo: Si quieres conocer mejor el funcionamiento interno de estas ecuaciones, deberías ver este vídeo y leer este PDF.

Todas las transformaciones lineales tienen esta forma:

\[B = F(A)\]

Esto establece que si tienes una función de transformación lineal \(F()\N, y tu entrada es el vector \N(A\N), entonces tu salida será el vector \N(B\N).

Cada una de estas piezas, los dos vectores y la función, puede representarse como una matriz: el vector \(B\) como una matriz de 1x3, el vector \(A\) como otra matriz de 1x3, y la transformación lineal \(F\) como una matriz de 3x3 (una matriz de transformación).

Esto significa que, cuando se expande la ecuación, se ve así:

\[ \begin{bmatrix} b_{0} \\ b_{1} \\ b_{2} \end{bmatrix} = \begin{bmatrix} f_{00} & f_{01} & f_{02}\\ f_{10} & f_{11} & f_{12}\\ f_{20} & f_{21} & f_{22} \end{bmatrix} \begin{bmatrix} a_{0}\\ a_{1}\\ a_{2} \end{bmatrix} \]

Si alguna vez has tomado una clase de trigonometría o de álgebra lineal, probablemente estés empezando a recordar la pesadilla que era la matemática matricial. Por suerte, hay una forma más sencilla de escribir esta ecuación para evitar la mayor parte de los problemas. Se parece a esto:

\[ \begin{bmatrix} b_{0}\\ b_{1}\\ b_{2} \end{bmatrix} = \begin{bmatrix} f_{00}a_{0} + f_{01}a_{1} + f_{02}a_{2}\\ f_{10}a_{0} + f_{11}a_{1} + f_{12}a_{2}\\ f_{20}a_{0} + f_{21}a_{1} + f_{22}a_{2}\\ \end{bmatrix} \]

Sin embargo, estas ecuaciones pueden ser alteradas por tener una segunda entrada, como en el caso de las rotaciones, donde un vector y su cantidad de rotación deben ser dados. Veamos cómo funcionan las rotaciones.


Rotaciones

Una rotación es, por definición, un movimiento circular de un objeto alrededor de un punto de rotación. El punto de rotación para nuestro espacio puede ser una de las tres posibilidades: el plano XY, el plano XZ o el plano YZ (donde cada plano está formado por dos de nuestros vectores base que discutimos en la primera parte de la serie).

692px-Rotation_illustration2svg692px-Rotation_illustration2svg692px-Rotation_illustration2svg

Nuestros tres puntos de rotación significan que tenemos tres matrices de rotación distintas, como sigue:

Matriz de rotación XY: \[ \begin{bmatrix} cos \theta & -sin \theta & 0\\ sin \theta & cos \theta & 0\\ 0 & 0 & 1\\ \end{bmatrix} \]

Matriz de rotación XZ:

\[ \begin{bmatrix} cos \theta & 0 & sin \theta\\ 0 & 1 & 0\\ -sin \theta & 0 & cos \theta \end{bmatrix} \]

Matriz de rotación YZ:

\[ \begin{bmatrix} 1 & 0 & 0\\ 0 & cos \theta & -sin \theta\\ 0 & sin \theta & cos \theta \end{bmatrix} \]

Así que para girar un punto \(A\) alrededor del plano XY en 90 grados (\(\pi/2\) radianes, la mayoría de las bibliotecas matemáticas tienen una función para convertir los grados en radianes), tienes que seguir estos pasos:

\[ \begin{aligned} \begin{bmatrix} b_{0}\\ b_{1}\\ b_{2} \end{bmatrix} & = \begin{bmatrix} cos \frac{\pi}{2} & -sin \frac{\pi}{2} & 0\\ sin \frac{\pi}{2} & cos \frac{\pi}{2} & 0\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} a_{0}\\ a_{1}\\ a_{2} \end{bmatrix}\\ & = \begin{bmatrix} cos \frac{\pi}{2}a_{0} + -sin \frac{\pi}{2}a_{1} + 0a_{2}\\ sin \frac{\pi}{2}a_{0} + cos \frac{\pi}{2}a_{1} + 0a_{2}\\ 0a_{0} + 0a_{1} + 1a_{2} \end{bmatrix}\\ & = \begin{bmatrix} 0a_{0} + -1a_{1} + 0a_{2}\\ 1a_{0} + 0a_{1} + 0a_{2}\\ 0a_{0} + 0a_{1} + 1a_{2} \end{bmatrix}\\ & = \begin{bmatrix} -a_{1}\\ a_{0}\\ a_{2} \end{bmatrix} \end{aligned} \]

Así que si tu punto inicial \(A\) era \((3,4,5)\N, entonces tu punto de salida \(B\) sería \((-4,3,5)\N.)

Ejercicio: Funciones de rotación

Como ejercicio, intenta crear tres nuevas funciones para la clase Vector. Una debería rotar el vector alrededor del plano XY, otra alrededor del plano YZ y otra alrededor del plano XZ. Tus funciones deben recibir la cantidad deseada de grados para la rotación como entrada, y devolver un vector como salida.

El flujo básico de tus funciones debería ser el siguiente:

  1. Crear vector de salida.
  2. Convierte la entrada de grados en forma de radianes.
  3. Resuelve cada pieza de la tupla de vectores de salida utilizando las ecuaciones anteriores.
  4. Devuelve el vector de salida.

Escalando

El escalado es una transformación que agranda o disminuye un objeto en función de una escala establecida.

Realizar esta transformación es bastante sencillo (al menos en comparación con las rotaciones). Una transformación de escala requiere dos entradas: un vector de entrada y una 3-tupla de escala, que define cómo debe escalarse el vector de entrada con respecto a cada uno de los ejes base del espacio.

Por ejemplo, en la tupla de escalado \((s_{0},s_{1},s_{2})\), \N(s_{0}\) representa el escalado a lo largo del eje X, \N(s_{1}\) a lo largo del eje Y, y \(s_{2}\) a lo largo del eje Z.

La matriz de transformación de la escala es la siguiente (donde \ (s_{0}\), \ (s_{1}\), y \ (s_{2}\) son los elementos de la 3-tupla de escala):

\[ \begin{bmatrix} s0 & 0 & 0\\ 0 & s1 & 0\\ 0 & 0 & s2 \end{bmatrix} \]

Para hacer que el vector de entrada A \((a_{0}, a_{1}, a_{2})) sea el doble de grande a lo largo del eje X (es decir, utilizando una tripleta de escala \(S = (2, 1, 1) \)), la matemática sería así:

\[ \begin{aligned} \begin{bmatrix} b_{0}\\ b_{1}\\ b_{2} \end{bmatrix} & = \begin{bmatrix} s0 & 0 & 0\\ 0 & s1 & 0\\ 0 & 0 & s2 \end{bmatrix} \begin{bmatrix} a_{0}\\ a_{1}\\ a_{2} \end{bmatrix}\\ & = \begin{bmatrix} 2 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} a_{0}\\ a_{1}\\ a_{2} \end{bmatrix}\\ & = \begin{bmatrix} 2a_{0} + 0a_{1} + 0a_{2}\\ 0a_{0} + 1a_{1} + 0a_{2}\\ 0a_{0} + 0a_{1} + 1a_{2} \end{bmatrix}\\ & = \begin{bmatrix} 2a_{0}\\ a_{1}\\ a_{2} \end{bmatrix} \end{aligned} \]

Así que si dado el vector de entrada \(A = (3,4,0)), entonces tu vector de salida \(B\) sería \((6,4,0)).

scalingscalingscaling

Ejercicio: Funciones de escala

Como otro ejercicio, añade una nueva función a tu clase vectorial para escalar. Esta nueva función debería tomar una tripleta de escala y devolver un vector de salida.

El flujo básico de tus funciones debería ser el siguiente:

  1. Crear vector de salida.
  2. Resuelve cada pieza de la tupla de vectores de salida utilizando la ecuación anterior (que puede simplificarse a y0 = x0 * s0; y1 = x1*s1; y2 = x2*s2).
  3. Devuelve el vector de salida.

¡Vamos a construir algo!

Ahora que ya tienes las transformaciones lineales en tu haber, vamos a construir un pequeño programa rápido para mostrar tus nuevas habilidades. Vamos a hacer un programa que dibuje un grupo de puntos en la pantalla, y luego nos permita modificarlos en su conjunto realizando transformaciones lineales sobre ellos.

Antes de empezar, también querremos añadir otra función a nuestra clase Point. Se llamará setPointToPoint(), y simplemente establecerá la posición del punto actual a la del punto que se le pase. Recibirá un punto como entrada, y no devolverá nada.

He aquí algunas especificaciones rápidas de nuestro programa:

  • El programa mantendrá 100 puntos en un array.
  • Al pulsar la tecla D, el programa borrará la pantalla actual y volverá a dibujar los puntos.
  • Al pulsar la tecla A, el programa escalará todas las ubicaciones de los puntos en 0,5.
  • Al pulsar la tecla S, el programa escalará todas las ubicaciones de los puntos en 2,0.
  • Al pulsar la tecla R, el programa girará la ubicación de todos los puntos 15 grados en el plano XY.
  • Al pulsar la tecla Escape, el programa saldrá (a menos que lo hagas con JavaScript u otro lenguaje orientado a la web).

Nuestras clases actuales:

Con estas especificaciones, veamos cuál podría ser nuestro código:

Ahora deberías tener un pequeño y genial programa para mostrar todas tus nuevas técnicas. Puedes ver mi sencilla demostración aquí.


Conclusión

Aunque ciertamente no cubrimos todas las posibles transformaciones lineales disponibles, nuestro micromotor está empezando a tomar forma.

Como siempre, hay algunas cosas que se han dejado fuera de nuestro motor por simplicidad (concretamente la cizalla y las reflexiones en esta parte). Si quieres saber más sobre esos dos tipos de transformaciones lineales, puedes encontrar más información sobre ellas en Wikipedia y sus enlaces relacionados.

En la siguiente parte de esta serie, cubriremos los diferentes espacios de vista y cómo eliminar objetos que están fuera de nuestra vista.

Si necesitas ayuda adicional, dirígete a Envato Studio, donde puedes encontrar un montón de fantásticos servicios de diseño y modelado en 3D. Estos proveedores experimentados pueden ayudarte con una amplia gama de proyectos diferentes, así que solo tienes que examinar los proveedores, leer las reseñas y las calificaciones, y elegir a la persona adecuada para ayudarte.

3D Design Modeling services3D Design Modeling services3D Design Modeling services
Servicios de diseño y modelado 3D en Envato Studio
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.