Programación Gráfica: Fundamentos de Recorte
–Como Cortar Objetos 3D–
Como ya dije hace mucho, una de las técnicas que uso para ver que un libro sobre gráficas por computadora realmente toma el tema de la programación gráfica en serio es ver como manejan los algoritmos de recorte. El recorte en gráficas vectoriales es algo que se utiliza casi tanto como las ecuaciones de proyección pero que en la mayoría de los casos se hace de manera transparente al usuario. Lo interesante es que los algoritmos de recorte no solo se usan para rebanar figuras en el espacio sino que también se utilizan para validar contactos, física, simulación de linea de vista como cuando queremos saber si el jugador puede ser visto por una unidad enemiga o para algo tan elemental como separar lo que queda dentro de nuestro campo visual en un mundo 3D de lo que queda afuera, aunque esto último solo lo saben los que han intentado hacer su propio engine gráfico pues como dije al principio, los motores actuales hacen esto de manera completamente transparente al desarrollador. Pero antes de explicar como funciona el recorte veamos una pequeña historia que viví de propia mano hace no mucho tiempo.

Como ya dije, el recorte de lineas, polígonos y sólidos basados en vectores en el espacio es algo tan elemental en la programación gráfica como las ecuaciones de proyección en perspectiva o la transformación de coordenadas. Pues bueno, una vez estaba muy feliz en la comunidad de internet de desarrollo de videojuegos que todos los creadores de videojuegos de latinoamérica conocen y alguien llegó con la noticia de que los programadores (esos si son programadores) de Konami habían implementado un sistema de recorte arbitrario en tiempo real en su nuevo motor gráfico llamado entonces el Fox Engine. Si bien tiene un gran mérito implementar un sistema de recorte arbitrario y en tiempo real por la complejidad de las estructuras de datos que están involucradas hacer un recorte en el espacio no es algo tan sorprendente como suena. De hecho, si los programadores de ese sistema gráfico no hubieran sabido desde antes como hacer un recorte no habría sido ni siquiera capaces de programar el engine gráfico en primer lugar. Como es de esperarse tales declaraciones tuvieron revuelo y creo que por ahí hasta salieron rodando algunas sandias virtuales. En ese entonces no quise hacerla de pleito porque de todos modos la mayoría de la gente ahí presente no me iba a entender pero aquí que estoy entre programadores si que puedo explicar con toda tranquilidad en que consiste el recorte en 3D y toda la ciencia que hay detras de este.
Recorte de lineas rectas en el espacio
Lo primero que tenemos que saber sobre el recorte en 3D es que este se da exclusivamente entre rectas y planos en el espacio. En los casos que estemos trabajando con un espacio vectorial en dos dimensiones se considera que los planos de recorte son perpendiculares al plano donde se lleva a cabo la acción cual si se tratase de muros. Lo segundo es que siempre es el plano el que recorta a la linea recta, nunca se recortan dos lineas rectas porque hacer que dos rectas en el espacio 3D se crucen es casi imposible ni tampoco se cortan dos planos porque el resultado es una recta con un sinfin de ecuaciones posibles. En cambio, cuando un plano corta a una recta (o visto de otro modo cuando una recta perfora un plano) el resultado es un sencillo número que dependiendo de nuestras necesidades puede convertirse en las coordenadas de un punto en el espacio, un valor escalar o una simple bandera de decisión para la lógica del juego. En el caso del recorte se trata de lo primero, de obtener la coordenada del espacio donde el segmento de recta y el plano se intersectan. La última cosa que deben de saber del recorte es que no basta con ser capaces de calcular el punto donde la linea y el plano se encuentran sino que es necesario redefinir por completo el modelo 3D a nivel de sus estructuras de datos. Y cuando digo completamente me refiero desde la definición de sus vértices, aristas y caras hasta el detalle de superficie y la forma como lo afectan otros modelos cercanos. Incluso en algunos casos puede ocurrir que al cortar un objeto este se multiplique (se hagan dos o mas) aunque si se siguen ciertas reglas estos casos pueden presentarse muy pocas veces.
En la primera imagen tenemos la situación en la que un segmento de recta definido por sus dos extremos inicial y final son cortados por un plano en el espacio. Y en la segunda imagen tenemos dos representaciones de un plano y un segmento de recta. Repasemos como se definan matemáticamente estas dos entidades. Como recordarán, un segmento de recta o arista tiene un punto inicial p0 y un punto final p1 y si la definimos en forma paramétrica existe un parámetro t que va de cero a uno entre estos dos puntos. Por su parte un plano se define por un punto en el espacio y un vector perpendicular que lo traspasa del mismo modo que un clavo a un trozo de madera. Aunque como ya saben es posible obtener estos dos datos a partir de 3 puntos en el espacio que no estén alineados que es como suelen definirse las superficies planas en los juegos 3D. El recorte de lineas toma como entradas los 2 puntos extremos del segmento de la linea que queremos cortar y el punto y el vector que definen el plano de recorte. El algoritmo de recorte regresa como resultado el valor del parámetro t en el que el plano recorta a la linea. Existen muchos algoritmos usados para hacer el recorte pero los dos mas usados y del que todos estos descienden son los algoritmos de recorte de Cohen-Sutherland y el de Liang-Barsky. El algoritmo de Cohen-Sutherland es bueno para computadoras muy sencillas que solo puedan manejar valores enteros y obtiene el punto de intersección por medio de la búsqueda de raices conocida como Método Bolzano mientras que el de Liang-Barsky aplica una fórmula directa y sencilla pero que requiere que el equipo tenga capacidad de procesamiento de punto flotante. En las siguientes entradas vamos a examinar ambos algoritmos y tomaremos lo mejor de cada uno. De momento solo necesitamos saber que los algoritmos de recorte toman como entrada una recta definida por dos puntos y un plano de recorte que ha de funcionar como una navaja. La función retorna el parámetro t en el que el segmento de recta y el plano de recorte se intersectan. Función que veremos con detalle en la siguiente entrada.

Con el parámetro t devuelto podemos hacer muchas cosas. La mas obvia es obtener la coordenada espacial en la que se da el corte. Para hacer esto basta sustituir el valor de t en las ecuaciones paramétricas de la recta. Aunque puede darse también el caso en el que la recta y el plano sean paralelos entre si y nunca se corten o incluso que la linea sea coplanar al plano de corte que al final es como si no se cortara. Otra cosa que puede pasar y de hecho pasa la mayoría de las veces si no se hace una buena validación es que el parámetro t devuelto por la función de recorte de un valor fuera del rango de 0 a 1. Cuando esto sucede la linea si es cortada por el plano, pero en un punto que está mas allá de sus extremos finales. Recuerden que matemáticamente las lineas rectas en el espacio tienen longitud y delgadez infinitas. Y para colmo de males, encontrar el punto en el espacio en los que un plano y una linea se intersectan es apenas una muy pequeña parte de lo que es el recorte.
Antes y despues de recortar
Resulta que hay que hacer una larga cantidad de validaciones y cálculos previos antes de hacer un recorte y una vez obtenidos los puntos en los que las lineas son cortadas es necesario reconstruir todo el modelo para poder representarlo en pantalla. Como ambos temas son demasiado extensos y esta entrada ya me quedó muy larga solo voy a mencionar las técnicas que hacen esto y en otra ocasión las describiré en detalle. La primera de las validaciones es conocida como la prueba dentro-fuera en donde nos aseguramos que la linea tenga sus extremos en lados opuestos del plano de recorte. Esto se hace evaluando las coordenadas de los vértices en la ecuación del plano y comparando el signo. Proceso que en los procesadores Intel actuales se resume a una sola instrucción de ensamblador. Si los signos son opuestos la linea puede ser cortada. Esta prueba dentro-fuera se extiende a algo llamado Prueba de Eliminación de Cohen-Sutherland que se usa para generar vistas de mundos complejos y determinar contactos en el espacio de varios miles o millones de vectores. Otra validación, que en realidad es una potente optimización consiste en aprovecharse de que hacer recortes usando planos perpendiculares a los ejes coordenados toma la tercera parte de las operaciones matemáticas que requiere hacerlo respecto a un plano cualquiera, así que es posible escalar y sesgar todos los objetos de nuestro mundo 3D y minimizar las operaciones de recorte. Esto puede parecer un esfuerzo inutil pero reescalar el mundo usando matrices es mucho mas eficiente que hacer recortes arbitrarios e incluso puede agregarse este escalamiento a la matriz de transformación de vista de modo que cambiaríamos lo que podrían ser varios millones de validaciones y dos tercios de otros millones de cálculos de punto flotante por una humilde multiplicación de matrices de 4 por 4 que podemos hacer en menos de una docena de ciclos de reloj.
De acuerdo, lo anterior fue apenas la preparación para cortar los modelos 3D. Ahora veamos que ocurre luego de que hemos dado el hachazo. En realidad hacer un recorte en 3D es mas parecido a una amputación quirúrgica de una extremidad que a un simple corte de un material sin vida, pues no solo debemos de ser cuidadosos para no cortar si no hay necesidad sino que después de haberlo hecho necesitamos hacer toda una reconstrucción. Lo primero que obtenemos luego de hacer un recorte es una lista de coordenadas xyz en la que cada una de las aristas se cruza con el plano de recorte. Si solo queremos obtener el punto donde se cruzan no necesitamos hacer nada mas pero lo mas probable es que queramos quedarnos con las piezas separadas. Y ahí es donde comienzan los problemas porque ahora cada una de las aristas se habrá duplicado. Digamos que tenemos una arista cuyos puntos extremos son p0 y p1 y que el recorte se da en un punto intermedio que llamaremos pR que obtuvimos sustituyendo el parámetro t dado por la ecuación paramétrica pR = p0 + (p1-p0)*t. Ahora tendremos 2 aristas separadas. La primera va del punto p0 a pR y la segunda va de pR a p1. Si mas adelante queremos reposicionar estas nuevas aristas obtenidas basta con cambiar sus nuevos valores iniciales y finales. Pero el problema de la reconstrucción no termina aquí.

Recortar un modelo 3D de estructura de alambre es el caso mas sencillo de reconstrucción de un modelo post-corte. El caso mas común y verdaderamente complicado es cuando queremos recortar un modelo construido a partir de polígonos con detalle de superficie. Pues a la hora de reconstruir el polígono no solo se corre el riesgo de que estos se dividan en muchos mas pequeños sino que deben de reconstruirse. Esta es una de las muchas razones por la que usamos caras triangulares para construir objetos complejos. Los triángulos al ser recortados respecto a planos de recorte rara vez se dividen en mas de dos partes, sus coordenadas de textura y normales son mucho mas sencillas de ajustar luego de ser cortados y en el caso del recorte de volumen de vista que es la aplicación mas importante del recorte ya existen muchos algoritmos para cortar estos triángulos de manera eficiente e incluso eliminarlos por completo sin necesidad de cortarlos. En el caso del recorte de vista no importa mucho si recortamos un polígono y lo dejamos abierto. El problema es cuando queremos recortar un sólido en un editor 3D o peor aun hacerlo en tiempo real como en el Fox Engine de Konami. Pues no solo hay que redefinir por completo vértices, aristas y polígonos sino que incluso es necesario definir polígnos y aun sólidos que antes no existían. Piensen un momento en el caso de una sandia. En su versión original se usa una textura verde con blanco para simular la cáscara de la fruta. Pero a la hora de cortarla necesitamos una textua roja que muestre el interior de la fruta. A menos que de inicio hubiéramos definido un conjunto de propiedades internas de la sandia esta ni sus polígonos van a existir cuando hagamos el recorte. Otro buen ejemplo del recorte es la madera. Podemos usar una textura para la parte externa pero si usamos la misma imagen va a parecer como si la pieza de madera estuviera forrada con papel adhesivo color madera. Ahora veamos como se hace para cerrar una figura que ha sido cortada de esta manera.
Recorte y Reconstrucción de Sólidos 3D

Cuando recién cortamos una figura hecha por polígonos con detalle de superficie y solo tenemos la lista de puntos donde cada arista es cortada por los planos tenemos que reconstruir cada polígono de manera individual. Afortunadamente existe un algoritmo que hace esto al momento de recortar que se llama Algoritmo de Sutherland-Hodgman que para explicarlo en pocas palabras funciona igual que uno de esos plásticos adhesivos que se usan para sellar los recipientes de comida. Ese algoritmo recorre los vértices del polígono en forma circular y agrega o elimina vértices dependiendo de los puntos obtenidos luego de recortar. Para los casos en los que quedan huecos en el modelo 3D se aplica una variante del algoritmo de Sutherland-Hodgman basado en el conocido (aunque no por todos los titulados) Algoritmo del Cerco Envolvente en el que se van creando nuevas caras conforme un plano ‘envolvente cubre las partes abiertas del modelo 3D. Una vez obtenidos los datos sobre vértices, aristas y caras de estos nuevos polígonos que antes no existian ya tenemos un modelo 3D usable, aunque por regla general los recortes nunca se hacen uno solo a la vez y en muchos casos es necesario repetir el proceso una y otra vez como en el caso del viejo recorte de vista.
Ya para terminar porque esta entrada quedó demasiado larga y no encuentro por donde recortarla quiero dejar claro el porqué los algoritmos de recorte son tan necesarios en Programación Gráfica y a la vez tan poco conocidos por quienes reciben dinero por dedicarse a estas cosas. Resulta que la aplicación mas elemental del recorte 3D es la creación del volumen de vista. Tema que veremos en un futuro espero no muy lejano. Las tecnologías actuales usadas por los aficionados hacen este recorte de manera automática y los que usan software de modelado 3D ni siquiera son conscientes de que hay que recortar aquello que queda fuera de nuestro campo visual. Es por eso que esto del recorte no es entendido por cualquiera. Sobre todo por la parte de la redefinición de datos involucrada en un buen corte. Recuerdo en tiempos de los primeros editores 3D que el ponerle nombre a cada sólido luego de cortarlo era un proceso tedioso y desconcertante. Manejar esta redefinición de datos requiere mucho conocimiento de programación gráfica y no solo de como hacer llamadas a una API. Es decir, de cosas que no cualquiera que diga dedicarse a esto de los juegos 3D domina realmente. Es por eso que mi último consejo es que si quien está leyendo esto tiene bajo su mando a un equipo de desarrollo de videojuegos y quiere reducir costos mandando a algunos empleados de vacaciones forzadas páselos de uno en uno a su oficina donde tiene su computadora con monitor dual y dígale que le explique como funcionan los algoritmos de recorte. Verá como estos algoritmos no solo sirven para recortar lineas y polígonos. ¡También sirven para hacer recorte de personal!
La Saga de la Programación Gráfica 3D
–Un programador de videojuegos no le teme a las matemáticas–

Programación Gráfica es la rama de la programación que hace posibles los videojuegos 3D, efectos especiales y demas gráficas interactivas en tiempo real. Esta es la saga de la Programación Gráfica 3D en la que se reunen todas las entradas relacionadas con las gráficas por computadora que pueden encontrarse en este blog de ensamblador que fueron pensadas para que cualquier programador aficionado al ASM y al desarrollo de videojuegos 3D pueda entenderlas y apreciarlas. Y lo mejor de todo es que solo hace falta lapiz, papel y calculadora.
Directorio de Programación Gráfica y 3D:
Programación Gráfica para Principiantes
Esta es la primera entrada, explica en que consiste la programación gráfica y deja claro que para aprender a hacer juegos 3D solo hace falta una libreta de cuadrícula, lápices y una calculadora. Al menos eso es lo que hace falta al principio.
El Espacio 3D
Se le conoce como 3D porque es un espacio tridimensional, se explica lo que es son los vectores y como estos se utilizan para construir todas las cosas relacionadas con las gráficas por computadora.
La Rotación de Objetos
Aquí se ve la teoría matemática básica para aprender como funcionan las rotaciones de objetos vectoriales. Este es el punto de no retorno en el que se ve si a uno realmente quiere hacer Programación Gráfica o si por miedo a los números prefiere dedicarse a otra cosa.
Modelado y Traslación
Conoce la información que una computadora necesita para generar un modelo 3D y como se hace para poder posicionar estos sólidos en cualquier lugar del espacio
Escalamiento y Distancias en el Espacio 3D
Las gráficas vectoriales pueden cambiar su tamaño sin pérdida de calidad. Así como la manera de medir distancias y longitudes en el espacio.
La Rotación Puesta en Práctica
Un ejemplo de rotación de un objeto vectorial y una explicación del porqué es importante saber siempre donde queda el eje de rotación.
Matrices y la Mecanización de los Cálculos
Las matrices son entidades matemáticas capaces de concentrar y almacenar grandes cantidades de operaciones matemáticas para luego aplicarlos a un vector cual si fueran una sola. Lo mas importante es que estas cosas son muy utilizadas por el hardware de aceleración gráfica.
Matrices de Transformación y Coordenadas Homogeneas
Es posible almacenar largas secuencias de transformaciones geométricas como rotaciónes, traslaciones, escalamientos y otras tantas mas extrañas en matrices y luego concentrarlas en una sola. Aunque para ello tenemos que trabajar con mas de 3 dimensiones.
Producto Escalar
El producto punto o producto escalar es una operación matemática entre dos vectores que es muy importante. Tiene aplicaciones en iluminación, cambios de cámara, manejo de fuerzas y lo mas importante poner un vector en términos de otros vectores.
El Producto Vectorial
Es una operación que permite crear un tercer vector a partir de otros 2 vectores. Se aplica en detalle de superficies, construcción de vistas en juegos multijugador y es muy util para entender como funcionan las superficies en los ambientes virtuales.
Polígonos y planos en el espacio 3D
Aunque no lo parezca todos los modelos 3D son construidos por pequeñas caras planas triangulares a las que se les ha dado un tratamiento de detalle de superficie e iluminación para aparentar relieves curvos. Aquí se explica como se definen estas caras planas y todo lo que podemos hacer con ellas.
Lineas Rectas en el Espacio 3D
Un segmento de linea recta en el espacio se define por sus dos puntos inicial y final, tienen delgadez infinita y al igual que los polígonos se usan para construir modelos de estructura de alambre y para animaciones. En esta entrada se explica como funcionan las lineas en el 3D y las operaciones que podemos hacer con ellas.
Cambio de Sistemas de Coordenadas
Puede que se trate de la operación mas importante en las gráficas por computadora. El cambio de sistema de coordenadas permite expresar un punto (o un modelo 3D completo) en función de diferentes sistemas de coordenadas. Esto es util tanto para posicionar objetos en un lugar y con orientación arbitraria como el tomar los datos de un objeto en cualquier lugar del espacio. Y es fundamental para simular vistas de cámaras y detalles de superficies.
Como Posicionar Objetos 3D
Se explica como posicionar un modelo 3D en cualquier lugar y orientación del espacio. Esta operación es la que permite construir grandes mundos virtuales a partir de unos pocos modelos que cambian de lugar.
Introducción a la Vista 3D
Lo minimo a saber para entender como funciona la vista 3D. Aquí se explica lo que es un plano de proyección y los rayos proyectores. Así como las proyecciones de vista mas importantes como la Paralela y la Perspectiva.
Proyeccion en Perspectiva
Aquí se describe como funciona la vista 3D en primera persona y se muestran las ecuaciones necesarias para convertir puntos del espacio a puntos en el plano de proyeccion. Puede que les sorprenda ver que estas ecuaciones no son tan complicadas como seguro creian que lo eran antes de leer esta entrada.
Práctica de Proyección en Perspectiva
Aquí se muestra un ejemplo de como generar una vista en primera persona de un objeto 3D. En este caso se trata de un cubo visto desde un punto lejano. Con un poco de imaginación pueden imaginarse que es lo que vería un francotirador colocado pecho tierra quien espera que su blanco salga de un edificio.
Coordenadas de Referencia Visual
En un mundo virtual es posible hacer aparecer una cámara en cualquier lugar del espacio y hacer que tome una foto de nuestra escena 3D. Aquí se explica como construir un sistema de coordenadas de referencia visual (o simplemente una cámara) con solo 2 puntos y un vector.
La última actualización de este directorio fue el 25 de diciembre del 2011. Revisa esta página de vez en cuando para encontrar nuevas actualizaciones.
Programación Gráfica: Coordenadas de Referencia Visual
–Como Implementar una Cámara en 3D–
Una de las primeras cosas que se pregunta un programador de videojuegos al dia siguiente de haber logrado implementar la proyección en perspectiva es como se hace para moverse por su mundo virtual, o como implementar eso que los grafistas llaman “la cámara”. Cuando escuchamos el término cámara lo primero que nos imaginamos es un cubo pesado con una trompa que apunta en dirección a lo que queremos fotografiar, y algunos mas veteranos puede que incluso se imaginen que tal cubo cuente con dos rodillos superiores cual orejas de ratón y una manivela rotatoria en un costado. Definitivamente nadie se imaginaría que la figura extraña que se muestra en la primera imagen tenga algo que ver con el refinado mundo de la fotografía. En esta entrada vamos a ver como podemos hacer fotografías de nuestros modelos 3D desde cualquier ángulo dentro de nuestro mundo virtual.

Primero dejemos en claro que es eso de Coordenadas de Referencia Visual. Conocidas también simplemente como Coordenadas de Vista, se trata de un sistema que convierte la información de los objetos en Coordenadas Mundiales en datos de posición relativos a un jugador que se mueve por ese mundo. Cuando decimos que algo se encuentra al frente, arriba o tras nosotros estamos usando coordenadas de referencia visual en la vida cotidiana. Pues bien, para poder movernos por nuestros mundos virtuales necesitamos mover una cámara y tomar una sucesión de fotos lo bastante rápida para generar una animación. Y para eso es que necesitamos una cámara, pero como nosotros somos programadores lo que vamos a implementar es un sistema de Coordenadas de Referencia Visual.
Ahora si vamos a describir que demonios es esa cosa que recuerda a un viejo satélite, aunque intentaré explicarlo como una cámara hasta donde me sea posible. El cuadro de papel es el Plano de Visión donde se va a desplegar la imagen, ese es nuestra porción de rollo de película.Los signos de mas y de menos que pueden verse en las esquinas de ese cuadro son los límites de la Ventana de Proyección. y los necesitamos para definir el ancho y la altura de la imagen que vamos a proyectar. El punto rojo donde todos los bastones de madera se unen es el Punto de Referencia Visual y es el objetivo de la cámara o la mira que nos indica hacia donde queremos tomar la foto. La enorme flecha que sale del plano de proyección se llama Normal del Plano de Visión o VPN y define la linea infinita que pasa por el centro del objeto a fotografiar y el ojo del observador. La bola de color verde que traspasa la flecha mas grande cual aceituna es el Punto de Referencia de Proyección o simplemente OJO
y es justo donde quedarían los ojos de un observador que mira por la cámara. Las flechas marcadas como U, V y N son los vectores que definen el Sistema de Coordenadas de Referencia Visual. Como puede verse, el vector N es paralelo a la Normal del Plano de Visión, pero a diferencia de este, N solo mide una unidad, pues U, V y N forman una base ortonormal del mismo modo que lo hacen los vectores mundiales X, Y, Z.
El sistema de coordenadas de referencia visual que acabo de describirles en realidad está simplificado para ser mas sencillo de entender a los principiantes. Pues como se explicará mas adelante en esta misma entrada, este sistema puede modificarse para obtener no solo las proyecciones paralela y perspectiva. Sino incluso las tomas que se usan en dibujo de ingeniería y planos industriales, que si bien no sirven para hacer videojuegos son perfectas si lo que quieren es hacer su propio editor de modelado 3D. Eso se explicará al final, por ahora veamos como se convierten las Coordenadas Mundiales a Coordenadas de Referencia Visual y recuerden que este ejemplo está simplificado para los principiantes.
Como definir un sistema de Coordenadas de Referencia Visual
Lo primero que necesitamos hacer es construir el sistema de coordenadas de referencia visual. Tenemos 2 opciones y ninguna es buena. La primera consiste en fabricarla de la nada y otra definirla como un objeto mas del mundo. En mi experiencia personal lo mejor es definir una cámara como un objeto mas en el mundo virtual y aplicarle las mismas reglas físicas que al resto de los objetos del juego y orientarlo de la misma manera como se posicionan y orientan todos los modelos en el sistema de coordenadas mundiales. Crearla de la nada a veces lleva a formas indeterminadas que crean vistas poco realistas o incluso puede aparecer una cámara dentro de otro objeto y mostrarlo incompleto. Este problema era muy común en tiempos del Nintendo 64. Sea como sea necesitamos 3 puntos, o mas bien 2 puntos y un vector. Veamos primero como se crea una cámara de la nada.

Definimos la Posición de la Cámara.-El punto en el espacio donde queremos posicionar la cámara será el Punto de Referencia de Proyección o simplemente el OJO.
Definimos el vector de vista hacia arriba VUP El Vector de vista hacia arriba VUP es una de las cosas mas difíciles de explicar a la hora de definir una cámara. En la imagen se muestra el vector VUP de manera separada al sistema de coordenadas de referencia visual. Si lo ven de cerca verán que el vector VUP se apoya en un cuadro plano en el piso de nuestro mundo. Este vector indica la verticalidad de la cámara. Si movemos este vector podemos hacer que la cámara se ladee o quede de cabeza. Pero lo mas peligroso es cuando VUP y y la normal al plano VPN son paralelos. Cuando esto sucede se crea una indefinición y no podremos crear el sistema de coordenadas mundiales.
Determinamos la dirección de la Cámara.-El segundo punto es hacia donde la cámara está mirando. Es decir el Punto de Referecia Visual. No es necesario ni aconsejable fijar el punto de referencia visual directamente en el objeto a “fotografiar” a menos que queramos que el plano de proyección y el objeto compartan el mismo espacio. Basta con que quede entre el punto de referencia de proyección y el objetivo. Puede usarse la ecuación paramétrica de la linea para obtener una distancia intermedia arbitraria.
Calculamos la Normal al Plano de Visión.-Se trata de la flecha mas grande y es perpendicular al plano de visión. Para calcularla basta tomar las coordenadas del Punto de Referencia de Proyección y restarle las respectivas del Punto de Referencia Visual. El resultado serán las componentes del vector normal al plano de proyección. Y como sabemos que para definir matemáticamente un plano solo necesitamos un punto y su normal, ya tenemos definido nuestro plano de proyección.
Obtenemos la Base Ortonormal UVN.-Primero dividimos la normal al plano de visión por su propia longitud y guardamos el resultado como el Vector N. Luego tomamos el vector de vista hacia arriba VUP (definido en coordenadas mundiales) y hacemos un producto cruz VUP X N para obtener un vector que luego dividiremos entre su propia longitud para obtener el vector U. Finalmente hacemos un producto cruz final N x U y obtenemos directamente el vector V. Si este proceso se les hace conocido, es porque es el mismo que usamos para posicionar y orientar objetos en el espacio de manera arbitraria. Proceso que ya se discutió en una entrada anterior.

En caso de que queramos predefinir una cámara como un objeto mas solo basta con predefinir estos datos y acomodarlos en el espacio como cualquier otro objeto. Otro método para obtener lo mejor de ambas técnicas y que es especialmente util en los First Person Shooters es definir 3 puntos en el propio modelo 3D. De modo que si tenemos por ejemplo el típico Space Marine el punto de referencia de proyección quede en los ojos, el punto de referencia visual un poco frente a los ojos como si se tratara de uno de esos displays montados en los cascos (o en la mira del rifle si se trata de un francotirador) y definir el vector de vista hacia arriba como una antena que sobresalga del casco directamente hacia arriba. De este modo no nos arriesgaremos nunca a que VUP y Y creen una indeterminación sin importar en que posición quede nuestro personaje, y no tendremos las pérdidas de precisión que implica mover por el espacio cámaras completas.
Como Transformar a Coordenadas de Vista
Pues bien, ya entendimos como se define un sistema de coordenadas de referencia visual y como este funciona como lo haría una cámara fotográfica. Ahora veamos como tomar la foto. Y aunque lo detallaré en la nota que sigue por falta de espacio les recuerdo que estas operaciones se hacen con matrices. Por lo que es posible concentrar todas las transformaciones de vista, proyección (y mas adelante recorte) en una sola matriz. Ahora veamos los pasos para tomar la foto.

Trasladamos el Punto de Referencia Visual al origen. Esto es solo una sencilla traslación que posiciona el sistema tal que el Punto de referencia visual (la mira) quede en el centro del sistema de coordenada mundiales.
Se hacen coincidir los vectores UVN con XYZ.-Tanto UVN como XYZ son vectores ortonormales. Para hacer esto solo hay que escribir los vectores UVN como las columnas de una matriz. Recuerden que para los sistemas ortonormales la inversa es también la traspuesta.
Se traslada el Punto de referencia de Proyección al origen.-Esta traslación hace que el observador quede en el centro del sistema.
Se escala al volumen de vista canónico.En este ejemplo no se detalla por tratarse de una explicación para principiantes, pero este paso convierte la pirámide de visión en un volumen particularmente sencillo de procesar mas adelante. Aquí es donde entran en juego los límites mínimos y máximos de la ventana o puerto de vista que queremos capturar. Como nota al margen, así es como se logran efectos realistas de ZOOM en los juegos 3D. Solo es cuestión de estrechar el volumen de vista y asunto arreglado.De momento el cálculo de transformacion a coordenadas de vista termina aquí. Ahora solo falta la proyección.
Aplicar la Proyección en Perspectiva. Esto es tan simple como aplicar las ecuaciones de la entrada anterior. Para convertir coordenadas de vista a coordenadas proyectadas solo hay que dividir entre Z y multiplicar por la distancia del observador al plano de proyección. En este caso esa distancia es el negativo de la coordenada Z del Punto de referencia Visual.
Hasta aquí ya se vio el caso específico cuando se maneja proyección en perspectiva. En las siguiente entrada veremos como las Coordenadas de Referencia Visual pueden generalizarse para manejar también la proyección en paralelo de manera que pueda hacerse una sola rutina que maneje cualquier tipo de proyección con tan solo pasarle los parámetros adecuados. Y otro poco mas adelante veremos el concepto de volumen de vista. Que como se discutió en la entrada anterior es una pirámide que recorta el mundo que podemos ver y lo transforma de modo que resulta mucho mas eficiente de procesar. El tema de las proyecciones de vista es complejo. No esperen dominarlo en pocos dias. Si tienen dudas repasen las entradas anteriores sobre programación gráfica. Y siempre que se sientan vencidos recuerden la primera ley del programador de videojuegos: Un Programador de Videojuegos no le Teme a las Matemáticas.
Programación Gráfica: Práctica de Proyección en Perspectiva
–Los Engines 3D no fueron hechos por los Extraterrestres–
Mientras mas gente relacionada con el desarrollo de videojuegos conozco. Mas me convenzo de que la mayoría de ellos creen que la tecnología que hace posible los juegos 3D fue inventada por los extraterrestres. O por lo menos una inteligencia superior a la de la raza humana. Solo así se explicarían muchas actitudes raras que involucran a gobiernos, universidades, empresas privadas y controvertidos grupos en internet dedicados a la desinformación. Hay mucho secretismo alrededor del tema. Por mi parte, considero que puedo ayudar mucho mas al desarrollo de estas tecnologías explicando como funcionan del modo mas amistoso y entendible que he podido hasta ahora en lugar de pasarme el tiempo diciéndole a todos lo genial que soy como la gente de cierta comunidad de desarrollo de videojuegos que por cierto ya muestra signos de rigidez cadavérica. En esta entrada les voy a mostrar un ejemplo muy simplificado pero funcional de como se genera una vista en primera persona de un objeto 3D.

En la entrada anterior vimos como el campo visual de una persona tiene forma de pirámide y como los objetos que quedan dentro de este volumen se proyectan sobre un plano imaginario que se encuentra frente al ojo del observador. En esta entrada vamos a dividir la tarea en dos partes. En la primera vamos a crear un objeto 3D sencillo en coordenadas de modelado y lo posicionaremos en el sistema de coordenadas mundiales. En la segunda parte vamos a colocar a un observador y generaremos una vista 3D del objeto. Recuerden que lo único que estamos usando ahora son lapiz, papel cuadriculado y una calculadora de bolsillo. Aunque si no tienen la suficiente paciencia pueden hacer uso de una hoja de cálculo por si quieren experimentar.
La figura mas elemental y conocida por el gran público que se me ocurre es un cubo que mide una sola unidad por lado. El cubo de la primera imagen tiene 8 vértices y 12 aristas. De momento no quise definir las caras porque no las vamos a necesitar. Pero si ustedes quieren hacerlo no olviden subdividir cada una de las caras cuadradas por al menos 2 caras triangulares para asegurar que cada una quede siempre definida como un plano en el espacio. Otra razón por la que quise usar un cubo unidad es que es mucho mas sencillo cambiar sus proporciones y posición de manera manual usando las matrices de rotación, traslación y escala que ya conocemos. En este ejemplo como lo queremos dejar lo mas sencillo posible vamos a usar una matriz identidad que como ya saben deja todos los vértices sin cambios. En este caso particular el cubo tiene una de sus esquinas justo en el origen y la esquina opuesta queda en la coordenada (1, 1, 1).
Ahora coloquemos al observador. Para agilizar los cálculos vamos a colocar la cámara en la coordenada (0,0,4) y el plano de proyección exactamente dos unidades por delante de modo que la linea de vista que es también la normal al plano de proyección coincida con el eje Z. La escena final se muestra en la segunda imagen junto con todos los parámetros básicos de vista.

Antes de generar la vista final repasemos las ecuaciones de proyección en perspectiva. Como ya saben de la entrada anterior la fórmula de proyección en perspectiva toma como entrada las coordenadas mundiales de un vértice y los datos de la cámara y da como salida las coordenadas bidimensionales en el plano de proyección. Este ejemplo ha sido reducido a tal nivel que los únicos parámetros que necesitamos son las coordenadas mundiales XYZ del vértice que queremos proyectar y la distancia del ojo al plano de proyección. La distancia del ojo al plano de proyección la llamaremos D_Plano y en este caso siempre va a ser 2. Para calcular la distancia total del ojo del observador al vértice vamos a tener que tomar la coordenada Z del punto de observación y restarle la coordenada Z del vértice que queremos poyectar. Hay una razón por la cual tomamos Z como negativa, y es que la distancia de vista se incrementa en dirección a la Z negativa. Si la coordenada Z del punto que queremos proyectar y la coordenada de vista fueran iguales (en este caso igual a 4), el denominador de la ecuación de proyección en perspectiva se anularía y tendríamos la temible división entre cero. En fin, luego de sustituir la distancia al plano por 2 y la coordenada Z de la cámara por 4, la vieja ecuación de proyección en perspectiva para esta vista nos queda así:
X_proyectada = (2 * X)/(4 – Z)
Y_proyectada = (2 * Y)/(4 – Z)
Lo siguiente es tomar los 8 vértices que componen nuestro cubo ya trasladado a coordenadas mundiales y aplicarle a cada uno las ecuaciones de proyección en perspectiva. En total se necesitan una multiplicación, una división y una resta para cada componente de la coordenada. Aunque mas adelante verán que todo esto puede reducirse a un solo producto de matriz por vector cuando se mecanizan los c\alculos con matrices. Al final de esta serie de operaciones tendremos las coordenadas proyectadas de todos los vértices del cubo. Ahora lo único que tenemos que hacer es dibujar los puntos en una hoja cuadriculada y unirlos siguiendo el orden de nuestra lista de aristas. Esto no es tan sencillo como parece y veremos el porqué a continuación.
Generación de la Vista en Primera Persona
Los parámetros que usamos para generar esta vista fueron simplificados en extremo para poder hacer estos cálculos a mano. Si tan solo dibujamos las coordenadas anteriores la imagen que vamos a obtener va a ser demasiado pequeña. Pues con los parámetros dados el plano de proyección que queda dentro del volumen de vista apenas mide 4 por 4 unidades. Así que para que puede dibujarse en una hoja de libreta a escala razonable vamos a escalar por un factor de 4 para poder dibujar la escena en una cuadrícula de 16 por 16. Para hacer este escalamiento basta con multiplicar las coordenadas ya proyectadas por 4. Una vez hecho esto dibujamos los vértices ya proyectados recordando que las coordenadas del plano de proyección (0,0) se encuentran al centro de ese cuadro, para recordar esto he dibujado una mira en ese punto no solo para que se parezca mas a un First Person Shooter sino para recordarles hacia donde está mirando el jugador. Es importante recordar que cuando queremos representar una imagen solo por sus aristas (lo que también se llama estructura de alambre primero dibujamos los vértices proyectados y luego los unimos por lineas rectas como lo indica la lista de aristas. En este caso vamos a dibujar 12 lineas rectas que unen los puntos en la secuencia que indica la lista de aristas que define el cubo. No importa donde queden los vértices después de las transformaciones, las aristas siempre los van a unir. Es importante tener bien identificado cual vértice es cual para evitar no confundirnos. Si hicimos todo correctamente al final obtenemos la vista en primera persona de la siguiente imagen (click para ampliar):
La verdad es que la imagen no me salió tan detallada como me hubiera gustado por hacerla tan simple. La escena está tomada de una toma al mismo nivel del piso en el que se encuentra posado el cubo. Piensen en una escena de un juego de guerra en la que el jugador se encuentra pecho tierra apuntando hacia la esquina izquierda de un edificio alejado. Para disminuir la ilusión óptica conocida como el Cubo de Necker repinté las aristas que quedan de frente al jugador y dejé con lineas de grosor normal las que quedarían ocultas si el cubo fuera opaco. Como la linea de vista está alineada con la esquina del cubo, lo que puede verse es la pared opuesta, el techo y la pared orientada en dirección al eje X. Espero en notas posteriores cuando veamos como eliminar partes ocultas y añadir detalle de superficie no necesitar de tanta imaginación para entender este tipo de tomas.
Pues bien, como pueden ver acabamos de crear una escena en 3D y la hemos proyectado. Y lo mas impresionante de todos es que no nos hizo falta mas equipo que papel, lapiz, calculadora y puede que una regla para dibujar rectas las aristas. Lo mas interesante de todo este proceso es que podemos aplicar cualquier transformación geométrica al cubo original y vamos a obtener una vista completamente diferente dependiendo de los datos que le demos. Si movemos el punto del observador hacia atras o adelante veremos como los cubos se alejan o se acercan. Todo estará bien por ahora mientras los vértices no salgan de la pirámide de visión ni entren en contacto con el punto que representa el ojo del observador. Inclusive podemos colocar el cubo entre el observador y el plano de proyección. Lo que bien hecho puede dar la impresión de que se encuentre por delante del monitor de la computadora.
Antes de terminar esta entrada quiero comentar un poco mas sobre el modelado wireframe o de estructura de alambre. En este ejemplo solo proyectamos los vértices y los unimos con aristas. Lo que da la impresión de que los objetos son transparentes o que están formados por alambres finos. Existen algoritmos para determinar si una arista es visible o no desde el punto de vista en que la vemos e incluso hay avanzados (aunque no por ello imposibles) algoritmos de iluminación y detalle de superficies. Cuando trabajamos con superficies opacas determinamos primero si un polígono es visible y si así es lo dibujamos. Para los casos en los que solo una parte es visible es posible recortar las aristas y redefinir la estructura de datos del sólido para desplegarla correctamente. Por ahora, con lo visto, podemos dibujar los cubos que queramos a partir del mismo cubo que definimos en coordenadas de modelado.
Ya para irme quiero advertirles algo sobre lo que acabamos de hacer aquí. Esta vista está exageradamente simplificada para ser facil de entender y generar a mano en tiempo razonable. La verdad es que es posible implementar una enorme cantidad de mejoras a la vista en primera persona para convertirla en una auténtica cámara. Por ejemplo, es posible obtener una vista de cualquier parte del espacio de coordenadas mundiales y no solo desde un punto constante dentro del eje Z. El plano de vista puede ampliarse para obtener visiones panorámicas o estrecharse para simular una mira telescópica. Puede rotarse sobre la linea de vista para hacer una vista ladeada. Maniobra conocida como Bank o Roll. También es posible definir una cámara con tan solo 3 puntos en el espacio o crear secuencias de animación donde la cámara tenga siempre enfocado un objetivo. En pocas palabras, existen algoritmos de vista capaces de implementar una auténtica cámara con la cual poder capturar cualquier escena de nuestro mundo 3D. Y eso lo vamos a estudiar en las siguientes entradas.
Programación Gráfica: Proyección en Perspectiva
–Como Funciona la Vista en Primera Persona–
Uno de los mejores recuerdos que tengo de cuando comenzaba a programar fue el haber implementado las ecuaciones de proyección en perspectiva en un modesto programa de 16 bits de MS-DOS. Cálculos que aunque humildes eran capaces de desplegar imágenes tridimensionales de estructura de alambre que a principios de los noventa sorprendian a mas de uno. Se trataba tan solo de lineas claras sobre fondo negro pero al menos a mi me dieron la suficiente inspiración para dedicarme a programar estas cosas. De eso han pasado casi veinte años y aunque las gráficas por computadora son algo cotidiano siguen provocando el mismo complejo de inferioridad de aquellos dias de los monitores CRT. Sigo escuchando como programadores jóvenes que han jugado juegos 3D toda su vida les da miedo este tipo de programación. De momento no me voy a poner a insultar y voy mejor a intentar compartir con los programadores mas principiantes esa misma emoción que experimenté aquellos dias.

La proyección en perspectiva es como el ojo humano percibe su entorno tridimensional. Cualquiera puede salir a la calle y ver como las cosas parecen hacerse mas pequeñas cuanto mas lejos están, o como las orillas de la carretera parecen juntarse en la distancia a pesar de tratarse de lineas paralelas. Los movimientos de los objetos cercanos parecen ser mas rápidos que los que están lejos de nosotros e incluso podemos cubrir la circunferencia completa de la luna llena con tan solo uno de nuestros dedos. En el primero de los dibujos se muestra el porqué de esto. El campo visual de una persona tiene forma de una pirámide cuya punta termina en el ojo y se abre hasta el infinito. Todo lo que podemos ver se encuentra en los límites de esa figura. Sin embargo, como no estamos trabajando con proyecciones intraoculares sino con pantallas de computadora existe un concepto llamado Plano de Proyección.
El plano de proyección es como una ventana de vidrio por la que vemos nuestro mundo en 3D. La parte de ese plano que queda dentro del volumen de visión piramidal representa la pantalla de la computadora. Existe una distancia entre el ojo del observador y esa ventana que representa el plano de proyección. Si leyeron la entrada anterior ya saben que hay lineas llamadas proyectores que van desde el ojo del observador hasta cada uno de los vértices de las figuras tridimensionales. Las ecuaciones de perspectiva nos indican como se proyectan los vértices en el espacio en ese plano dados únicamente sus coordenadas x,y,z y la distancia entre el observador y el plano de proyección.
De manera muy esquematizada, lo que se muestra en el dibujo es la vista lateral de una proyección en perspectiva. Aunque los mísmos cálculos se pueden aplicar para una vista superior. Representa a un observador que dispara contra una pared (el rectángulo) frente a él. La linea vertical entre ambos es el plano de proyección y la linea punteada horizontal indica la linea de vista que es la dirección en la que el jugador está apuntando. Las diagonales que van del ojo del observador a las esquinas de la pared son los proyectores y las equis donde estos se cruzan son los puntos que vamos a desplegar en pantalla. Tenemos que obtener las coordenadas BIDIMENSIONALES que corresponden a esas equis en nuestro plano de proyección.
Recuerden por un momento como representábamos un plano cartesiano en dos dimensiones. Era esa cosa con dos lineas cruzadas que recordaba a las miras de los francotiradores (snipers) de los juegos First Person Shooters. Pues al igual que estas miras, la linea punteada que indica la dirección en la que el jugador está viendo pasa por el centro de esa mira como lo haría una bala disparada por el rifle. Si un vértice quedara en esa linea de fuego se proyectaría justo en el centro de nuestro plano de proyección. Y conforme cambiara de lugar se alejaría cada vez mas del centro. Ahora veamos de forma matemática como obtener las coordenadas x,y de este plano de proyección a partir de las cordenadas x,y,z que son mundiales.
En el segundo dibujo se muestra una parte de la primera imagen. La linea horizontal representa la linea de vista (la punteada) que coincide con el centro del plano de proyección y es igual a la distancia entre el observador y el objetivo. El eje vertical puede representar tanto X como Y suponiendo que la linea de vista coincida con el eje Z. La linea vertical mas grande, o en este caso el lado vertical del triángulo que se forma es la distancia del centro de la linea de vista al punto en el espacio que queremos proyectar, la linea vertical que parte el triángulo representa nuestro plano de proyección.
Matemáticas de la Proyección en Perspectiva

Antes de continuar revisemos que tenemos 4 parámetros:
Distancia Total: La distancia horizontal del observador a la coordenada mundial. Se acostumbra que coincida con el eje Z.
Coordenada Mundial:Puede ser X o Y suponiendo que la distancia total coincida con el eje Z.
Distancia al Plano:La distancia del observador al plano de proyección.
Coordenada Proyectada: Se trata de la proyección de la coordenada mundial en el plano de proyección y es el valor que queremos obtener
Lo que debemos hacer es calcluar la longitud del segmento de linea pintado de rojo (la coordenada proyectada) y ese será el valor proyectado de la coordenada mundial en nuestro plano de proyección. Lo primero que vemos es que la Distancia Total se divide en dos partes. La parte entre el punto de observación y el plano de vista es la distancia al plano de visión. Y la distancia del observador al objetivo es la Distancia Total. Lo segundo es que existe una proporción entre estos 4 números: Si dividimos la Coordenada Mundial entre la Distancia Total obtenemos el mismo número que si dividimos la Coordenada Proyectada entre la Distancia de Proyección. No importa que no conozcamos el valor de la Coordenada Proyectada porque se trata de triángulos similares. Entonces con un poco de álgebra podemos despejar el valor de la Coordenada Proyectada como sigue:
(Coordenada_Mundial)/(Distancia_Total) = (Coordenada_Proyectada)/(Distancia_al_Plano)
(Coordenada_Proyectada) = (Distancia_al_Plano)*(Coordenada_Mundial)/(Distancia_Total)
En resumen, para proyectar una coordenada mundial en un plano de proyección basta con multiplicarla por la Distancia al plano de proyección y luego dividirla por la distancia horizontal. Ahora juguemos con estos valores. La distancia al plano de proyección debe de elegirse cuidadosamente, si es demasiado pequeña el volumen de vista será demasiado amplio y las figuras parecerán mas pequeñas de lo que son. Si es demasiado grande no podremos ver mas que una parte muy pequeña del mundo, es mas, conforme este valor se acerca al infinito los proyectores comienzan a volverse paralelos y obtenemos una proyección paralela. Dato que veremos en alguna nota posterior de manera mas matemática. Nota aparte, en la época en la que se hacía 3D sin valores de punto flotante se acostumbraba usar una potencia de dos como 128 o 256 para optimizar los cálculos y cambiar una multiplicación por un simple desplazamiento binario.

La distancia horizontal entre el observador y el objetivo a proyectar controla no solo el tamaño de la proyección. Sino que cuando se convierte en un valor negativo. Es decir que el objeto queda por detras del observador la imagen proyectada se invierte y parece estar por delante del jugador. Es importante mantener los valores siempre dentro de la pirámide de volumen de vista o recortarla si es posible. Si la distancia es muy larga el objeto comenzará a parecer un simple punto cerca del centro de la pantalla.
Cuando la coordenada mundial que queremos proyectar tiene un valor cercano a cero va a aparecer en el centro del plano de proyección y conforme crece en valor absoluto se va alejando del centro hasta que queda fuera de los límites de lo que podemos mostrar en pantalla.
El algoritmo de proyección funciona como una cámara fotográfica. Ponemos la cámara en un lugar del espacio y tomamos la foto. Mas adelante veremos como poner la cámara en cualquier parte del mundo definido por el sistema de Coordenadas Mundiales. De momento vamos a suponer que la cámara está alineada con el eje Z y que mira en dirección al origen. De modo que el plano de proyección sea perpendicular al eje Z del sistema de coordenadas mundiales y que el observador se encuentre frente a este. En la siguiente entrada veremos todo esto de una manera mucho mas programable. De momento solo tienen que estar enterados de que se usan matrices de transformación geométrica para simplificar los cálculos de las vistas de cámara.
Ya para despedirme, espero que estas notas les abran los ojos y vean que todos este asunto del 3D no es tan impresionante como lo pintan algunos “profesionales de la industria”. Desarrollar un Engine Gráfico no es mas dificil que desarrollar cualquier sistema de computación dedicado a cualquier otra cosa, la única diferencia es que necesitan saber matemáticas y ensamblador para que funcione de manera eficiente. No pierdan las esperanzas si es que han decidido intentar este tipo de proyectos. O por lo menos mantengan siempre presente que hacerlo es cuestión de conocimiento y dedicación y no de tener dinero o cumplir con el perfil como muchos por ahi les van a querer hacer creer.
Programación Gráfica: Introducción a la Vista 3D
–Plano de Proyección y Proyectores–
Pues bien, hemos recorrido un largo camino desde el inicio de esta serie de entradas sobre programación gráfica. Hemos aprendido desde cero y con el lenguaje menos técnico que me ha sido posible conceptos matemáticos que ni siquiera se ven en las clases de ingeniería de nivel superior (o al menos eso es lo que demuestran la mayoria de los game developers latinoamericanos que conozco) y otros mas que vamos a ver en el futuro. Conocemos como armar mundos completos con vértices, aristas y polígonos y tenemos una buena idea de como se crean las estructuras de datos necesarias para almacenar esta información en memoria. Y lo mas impresionante de todo es que hasta ahora no hemos tenido necesidad de mas equipo que una libreta de cuadrícula, lapiz con borrador y una calculadora escolar. Con lo aprendido hasta ahora ya somos capaces de crear mundos bastante elaborados aunque no tenemos manera de representarlos en una superficie plana como una pantalla o una hoja de papel. A partir de aquí las entradas van a tratar sobre como obtener una vista en 3D.

El concepto mas importante de la proyección en 3D son sin lugar a dudas los proyectores. Un proyector es una linea que va desde un vértice en el espacio hasta donde se encuentra el observador. En su viaje, este rayo proyector traspasa una superficie plana que se encuentra en un punto intermedio entre el observador y el objeto en el espacio. En la primera imagen tenemos una representación de esto. Imaginen que el rectángulo de cartón blanco es nuestro plano de proyección y los palos de madera que lo traspasan son los rayos proyectores. Si se acercan lo bastante a la foto pueden ver que hay una linea dibujada en el cuadro de cartón blanco que une los puntos en que los rayos proyectores lo perforan. Esta linea es la proyección de la arista en el plano. Todo el problema de la vista en 3D se resume en esta imagen. El cuadro blanco es el plano de proyección donde se van a dibujar las imágenes que existen en el espacio y luego de usa serie de transformaciones la imagen proyectada se va a mostrar en pantalla. Piensen por un momento que caminan por la calle con una pantalla de cristal que flota frente a ustedes a donde quiera que van o miran. Todo lo que pueden ver pasa por esa ventana de cristal antes de llegar a sus ojos y lo que no ven es simplemente ignorado. Cuando creamos una vista en 3D para mostrar en pantalla seguimos 3 pasos, en el primero descartamos todo aquello que no podemos ver, en el segundo proyectamos lo que si podemos ver en ese cuadro de cristal y en el tercero tomamos ese cuadro de cristal y lo mandamos a la pantalla de la computadora. Por supuesto para hacer esto necesitamos saber como manejar ese cuadro de manera programable. Pero antes de ver como hacer esto tenemos que ver que hay dos tipos muy diferentes de proyección.
Tipos de Proyección: Paralela y Perspectiva
Dependiendo de lo que tengamos que hacer con nuestro mundo 3D podemos optar por la proyección paralela o en perspectiva. La proyección en perspectiva es la mas realista de las dos y es la que da esa sensación de profundidad en la que los objetos parecen aumentar de tamaño a medida que se acercan. Por el contrario la proyección paralela no da sensación de profundidad y los objetos se ven del mismo tamaño sin importar a que distancia estén. Y aunque no es realista este tipo de proyección es muy util para editores gráficos 3D pues permite trabajar con medidas exactas de los objetos y así es mas facil hacerles cambios. Ahora veamos mas detalles de cada una. Lo mas importante es que lo único que hace la diferencia entre una proyección y otra son un par de parámetros de transformación que se le pasan a la matriz de proyección. No hay que hacer ningún otro cambio en la cámara o el mundo para pasar de un tipo de proyección al otro.
Proyección Paralela: Se le llama Proyección Paralela porque todos los rayos proyectores que dan desde los vértices hasta el plano de proyección son paralelos entre si. El volumen de vista que abarca una proyección paralela tiene la forma de una caja donde su lado frontal coincide con el plano de proyección y que puede extenderse hasta el infinito si así lo queremos, aunque en la práctica siempre ponemos una distancia máxima a la que podemos ver. En los inicios de los juegos tipo First Person Shooter a principios de la década de 1990 se usaba la proyección paralela para simular miras de muy largo alcance. Aunque esto ya no se hace porque tales vistas eran muy difíciles de controlar. El concepto mas importante a recordar en las proyecciones paralelas es que se considera que el observador se encuentra a una distancia infinita del plano de proyección.
Proyección en Perspectiva: Esta es la mas interesante para un programador de videojuegos por tratarse de la proyección de vista mas realista. La principal diferencia con la anterior es que en la proyección en perspectiva los rayos proyectores no son paralelos, sino que se unen todos en un punto donde se supone se encuentran los ojos del observador. En la proyección en perspectiva el volumen de vista tiene forma de pirámide con la punta truncada por el plano de proyección. En la segunda imagen se ve un ejemplo de una arista definida por dos vértices cuyos rayos proyectores traspasan el plano de visión. El punto donde se unen los dos proyectores es el centro de proyección donde se supone se encuentra el observador. Piensen por un momento lo que pasaría con los rayos proyectores y el volumen de vista a medida que el observador camina hacia atrás para alejarse de la ventana. Llegaría un momento en que estaría tan lejos que los rayos proyectores se harían cada vez mas paralelos y la base de la pirámide se estrecharía hasta convertirse en la misma caja de la proyección paralela.

Un concepto que no he aclarado aún es el del volumen de vista. El volumen de vista es un sólido que abarca la parte del mundo que los jugadores pueden ver. Estos volúmenes de vista se limitan por razones técnicas y si alguno de ustedes es lo bastante viejo para recordar los primeros videojuegos 3D del primer Playstation o el Nintendo 64 recordarán que algunas figuras parecían aparecer de la nada conforme uno avanzaba hacia adelante. Este fenómeno se conocía como Pop-Up y se debía a que el volumen de vista era demasiado corto en comparación con el mundo que estaba siendo generado. Una imagen solo podía ser generada cuando entraba en este volumen de vista. En ese tiempo se usaron muchos trucos para disimular este efecto como por ejemplo el uso de niebla u oscuridad y algunos mas avanzados mostraban siluetas de muy bajo nivel de detalle cuando detectaban que un objeto se encontraba fuera de los límites de visión de este volumen de vista.
Otro fallo de esos tiempos era el ver como los modelos 3D se abrían cual cascarones de huevos cuando nos acercábamos demasiado a ellos. Esto es porque el plano de proyección es también otro límite del volumen de vista. En ese tiempo hubo otro tipo de fallas por esto mismo.
Ya para terminar y comenzar de lleno con este asunto de la vista 3D voy a describirles lo que vamos a hacer a lo largo de las próximas entradas. Primero vamos a averiguar como demonios funcionan las matemáticas que gobiernan las proyecciones. Luego veremos como proyectar una imagen en un plano de proyección en el espacio y luego como modificar este para poder crear una imagen representable. Luego veremos como se definen las cámaras en el espacio y haremos vistas del mismo objeto de diferentes ángulos y al final veremos como recortar el mundo para quedarnos solamente con lo que contenga el volumen de vista. Aquí en confianza, puedo decirles que un buen libro sobre gráficas por computadora se distingue por la manera como maneja el tema del recorte del volumen de vista. Muchos viejos libros ni siquiera tocan el tema y muchos otros manejan técnicas que cuando no son terriblemente ineficientes acaban por desgraciarse toda la información de los objetos que queremos recortar. Afortunadamente hay métodos que aunque muy viejos son muy efectivos especialmente para alguien que programa en ensamblador. Y recuerden, no necesitan de grandes fortunas ni de haber estudiado en ninguna universidad de prestigio para programar juegos 3D.
Programación Gráfica: Como posicionar objetos 3D
–Uso de Coordenadas de Modelado y Mundiales–
En la entrada anterior sobre cambios de sistemas de coordenadas se discutió como estos se usan para un sinfin de cosas en la programación de juegos 3D. También se mostró que era posible construir una matriz de rotación a partir de un sistema de coordenadas arbitrario formado por 3 vectores ortonormales en el espacio y lo mas importante, que es posible obtener las inversas de las transformaciones geométricas a partir del cálculo de su matriz inversa. En esta entrada vamos a ver como posicionar una figura de sus coordenadas de modelado a un sistema arbitrario en coordenadas mundiales y viceversa. Y a ver una vez mas el como se invierten las transformaciones.

En la primera imagen vemos la situación: Tenemos nuestra nave triangular en su propio sistema de coordenadas de modelado y queremos posicionarla en el espacio de modo que apunte y dispare a un objetivo dados como parámetros las posiciones de la nave y el blanco. El resto de los números se explicarán conforme vayamos haciendo la entrada. Lo que vamos a hacer es usar los puntos dados al principio para construir un sistema de coordenadas.
Como ya hemos visto, cuando hacemos un producto escalar entre un vector cualquiera y los vectores que integran una base ortonormal el resultado es ese vector expresado en términos de los vectores que forman la base. De hecho cuando hacemos una multiplicación matricial entre una matriz de transformación 4×4 y un vector columna 4×1 y los renglones de la matriz 4×4 son esos vectores ortonormales el efecto es ese. La matriz de 4×1 que obtenemos como resultado es el mismo vector V expresados en términos de los vectores renglón de la matriz de 4×4. Si esos puntos los volvemos a graficar en el mismo sistema de coordenadas mundiales el objeto será trasladado al centro del espacio de coordenadas mundiales y se alineará con los vectores que lo forman (ejecutando también una traslación). Este proceso lo hacemos cuando queremos por ejemplo obtener una vista centrada de un objeto o poner el mundo en relación con un punto de vista.
También sabemos de la nota anterior que es posible invertir una matriz de transformación geométrica para hacer que esta haga exactamente lo contrario a lo que hacía antes. Entonces, pregúntense que pasaría si invirtiéramos esa matriz de vectores renglón. El efecto sería colocar cualquier imagen centrada en el sistema de coordenadas mundiales en cualquier posición y orientación en el espacio. Para hacer las cosas todavía mejores, una matriz que representa una base ortonormal puede invertirse con tan solo calcular su traspuesta (intercambiar los renglones por columnas). Todo esto nos permite hacer las tranformaciones geométricas en ambos sentidos, revertir una transformación haciendo un UNDO y otras cosas mas, pero primero revisemos bien ese asunto de las transformaciones reversibles y las matrices inversas
Como invertir transformaciones geométricas
Como ya saben, es posible encadenar una secuencia de transformaciones geométricas como la traslación, rotación y escala por medio de la multiplicación de matrices y luego aplicar esa matriz ‘concentrada’ a una serie de vértices para aplicarle a un modelo vectorial todas esas transformaciones en una sola operación. Pues bien, si calculamos la inversa de esa matriz de transformación el resultado será ejecutar todas esas transformaciones en sentido inverso. Esto aunque es posible rara vez se hace en la práctica, pues es mucho mas eficiente volver a leer los datos de los vectores originales en lugar de invertir la matriz y aplicar la a todos los vértices. Lo que si sucede con mucha frecuencia es que queremos anular algunas secuencias determinadas de la cadena de transformaciones. Antes de regresar al tema de como posicionar un modelo 3D de manera arbitraria en el espacio debo aclarar dos puntos sobre las transformaciones geométricas inversas y las matrices.
Lo primero que deben de saber es que existe un método directo para invertir matrices llamado método de Gauss-Jordan del que solo voy a mencionar el nombre porque además de lento, ineficiente y muy pero muy impreciso, en programación gráfica solo se usa cuando verdaderamente no queda mas remedio. Si le aplican el método de Gauss-Jordan a las matrices de traslación, rotación y escala verán que obtienen las “anti-matrices” mencionadas en la entrada anterior. La segunda cosa a tomar en cuenta es que cuando se calcula la inversa de una cadena de matrices de transformacion, el orden de las matrices se invierte, es decir que si tenemos la cadena de matrices A, B y C y le sacamos la inversa, el resultado será C^-1, B^-1, A^-1.
Bien, ya vimos suficiente teoría sobre inversa de matrices y transformaciones geométricas. Ahora vamos a ver como hacer el problema del inicio de la entrada. En la segunda imagen tenemos nuesta nave triangular que hemos usado desde el inicio de esta serie. Así como está se encuentra expresada en coordenadas mundiales. Lo primero que haceremos será ponerla en términos de coordenadas de modelado. Así que elegimos un punto que corresponderá al centro y otros dos que definirán los ejes X,Y de su sistema de coordenadas de modelado. Como estos ejes son paralelos a los del sistema de coordenadas mundiales bastará una traslación al origen para convertir estos puntos expresados en coordenadas mundiales a coordenadas de modelado. Aunque la operación general consta de una traslación al origen, una rotación y un escalamiento. Aunque aquí la rotación y escalamiento serían matrices identidad. Es bueno que se acostumbren a aplicar siempre toda la secuencia de transformaciones para evitar código condicional. Si quieren pueden dibujar en otra hoja cuadriculada la nave en sus propias coordenadas de modelado para que estén bien seguros de lo que están haciendo.
El sistema de coordenadas de modelado no existe en el sistema de coordenadas mundiales. Para entender mejor esto piensen en uno de esos juegos de mesa que constan de un tablero y figuras a escala. El tablero donde se da toda la acción es el sistema de Coordenadas Mundiales y las cajas donde se guardan las miniaturas cuando no participan en el juego son sistemas de coordenadas de modelado. Para cada figura existe un espacio de modelado definido por su propio sistema de coordenadas. Cuando queremos colocar una de estas figuras en el tablero primero la colocamos en el centro y luego la movemos a su posición final. El sistema de coordenadas de modelado y el mundial funcionan como estos juegos de mesa. De hecho si no hiciéramos ninguna transformación para convertir coordenadas de modelado a mundiales (digamos que usamos una matriz identidad) la figura quedaría centrada en el origen del sistema de coordenadas mundiales. Pero ahora lo que queremos es hacer aparecer la nave de tal forma que pueda apuntar y disparar a un objetivo en el espacio. Ahora veamos por fin como.
Para orientar un objeto en el espacio (como por ejemplo una cámara) necesitamos por lo menos 3 puntos: El primero es el punto donde va a aparecer. El segundo es el punto hacia donde está mirando. Y el tercero es un punto que nos indique hacia donde queda arriba. Este último nos asegura que la figura no rote como lo haría un pollo rostizado. A partir de esos 3 puntos necesitamos construir un sistema de 3 vectores ortonormales. Y es ahí donde entran las abreviaturas del primer dibujo. Los 3 vectores que necesitamos son el vector de ataque, el vector horizontal y el vector de vista hacia arriba. Ahora veamos como se calculan. Primero explicado con palabras y luego en notación matemática.
Vector de Ataque: Para calcular el vector de ataque primero tomamos las coordenadas del objetivo y a estas les restamos las del punto en el que queremos posicionar la nave. La diferencia entre esos puntos nos va a dar como resultado las componentes del vector de ataque. Para normalizarlo obtenemos la longitud por medio del teorema de pitágoras y dividimos cada componente por esa longitud. Ahora tenemos un vector de longitud uno que apunta hacia el objetivo. Por la transformación que hicimos a la hora de obtener las coordenadas de modelado de la nave, ahora la nariz de la nave apunta hacia el eje Z del sistema de coordenadas de modelado. Y ese vector Z y el vector de ataque ahora son el mismo.
Vector Arriba (VUP). El vector de vista hacia arriba nos indica por supuesto hacia donde queda arriba y es una referencia muy util para que las cosas no se vayan de lado a la hora de posicionarlas en el espacio. El problema es que si queremos posicionarlas de modo que el vector de ataque fuera paralelo a este vector tendríamos problemas. Para calular el vector VUP tomamos las coordenadas del punto que definimos como arriba y le restamos las coordenadas del punto donde definimos la nave. Por cierto, el vector de vista hacia arriba no forma parte del sistema ortonormal y por lo tanto no es necesario hacer que su longitud sea igual a uno. Solo se usa para obtener el vector horizontal. Incluso el vector VUP puede definirse de manera completamente independiente a los 3 puntos de posicionamiento y así solo tendríamos que usar las coordenadas de posición y objetivo. En los juegos de simulador de vuelo el vector VUP puede ser la normal al plano del terreno, así podríamos mantener el avión paralelo a este creando un sistema de estabilización automática.
Vector Horizontal También conocido como Vector Horizonte, nos permite hacer que el modelo quede horizontal en el espacio, a menos que queramos hacer un “Barrel Roll” que es hacer que el modelo gire como un taladro. Este vector si pertenece al sistema de base ortonormal y coincide con el eje X de las coordenadas de modelado. Para obtener el Vector Horizonte hacemos un producto vectorial entre el vector de ataque y el vector de vista hacia arriba (en ese orden) y luego lo normalizamos igual que como hicimos con el vector de ataque.
Vector Vertical Aunque no se muestra en la imagen, el vector vertical (y que es diferente al vector de vista hacia arriba) es el últimos vector que forma la base ortonormal. Para obtenerlo basta con hacer un producto vectorial entre el Vector Horizonte y el Vector de Ataque. Como ambos vectores tienen una longitud de uno. El resultado será un vector ya normalizado y no tendremos que dividirlo por su longitud como los otros dos. Este vector corresponde al vector Y del sistema de coordenadas de modelado. A este vector también se le conoce como el Vector Mastil.
Una vez que tenemos estos 3 vectores los acomodamos en una matriz de 4 por 4 (aunque en realidad sería en la submatriz de 3×3) de modo que las componentes del Vector Horizonte queden en la primer COLUMNA, las del Vector Mastil en la segunda y las del Vector de Ataque en la tercera. Esta será nuestra matriz de orientación. Ahora para posicionar la nave de modo que pueda apuntar y disparar contra el blanco vamos a concatenar primero una matriz de escala (si es necesario cambiar la nave de tamaño), luego la matriz de orientación que tanto nos costó obtener y finalmente la matriz de traslación que colocará la nave en el punto que queremos. La matriz que obtengamos de estas multiplicaciones la usaremos para transformar todos los puntos de la nave que originalmente estaban en coordenadas de modelado y al final obtendremos la nave ya posicionada y orientada donde queremos dentro del sistema de Coordenadas Mundiales.
Pues bien, hasta aquí ya hemos visto las suficientes matemáticas para estar en posición de entender las gráficas vectoriales. Con lo visto hasta ahora ya están en capacidad de construir sus propios mundos vectoriales definidos por objetos independientes construidos por vértices, aristas y polígonos. Pero todavía no saben como moverse por esos mundos ni mucho menos crear una vista de cámara desde dentro de ellos. En las siguientes entradas veremos como hacer esta clase de vistas y proyecciones 3D. Y mas adelante, pero mucho mas adelante veremos como darle detalle a las superficies de nuestros objetos, pues hasta ahora todos nuestros queridos objetos 3D son poco mas que simples esqueletos vectoriales. Y confirmarán que no necesitan de millones de dólares o doctorados universitarios para poder hacer sus propios juegos 3D desde cero, pues hasta ahora y si han seguido estas entradas al pie de la letra, solo han necesitado lapiz, papel y calculadora. Y conocimientos de matemáticas que cualquier adolescente ve en una secundaria pública. Y si no las han visto, no les será dificil encontrar libros donde puedan aprenderlo sin ayuda de nadie.
Programación Gráfica y el Cambio de Sistemas de Coordenadas
–Transformaciones Inversas y Modelado–
Sin exagerar, uno de los conocimientos mas importantes que debe de tener cualquiera que se interese por programar juegos 3D es saber transformar imágenes vectoriales de un espacio tridimensional a otro. Algunas de las muchas aplicaciones que tiene esto son el manejo de cámaras múltiples, la construcción de objetos compuestos de muchas partes móviles (conocido como modelado jerárquico), y otras tantas que no terminaría de mencionarles. Lo mas importante para nosotros es que por fin vamos a poder manejar diferentes espacios además del viejo sistema de coordenadas mundiales. En la primera imagen vemos 3 sistemas diferentes de coordenadas y un punto. Ese punto rojo aunque es uno solo tiene diferentes coordenadas dependiendo de que sistema de coordenadas tomemos como base. Primero veamos como manejaríamos esta situación en términos tradicionales.

Con lo que sabemos hasta ahora, cada vez que quisiéramos transformar las coordenadas de uno de estos subsistemas tendríamos que trasladar el origen de modo que coincidiera con el origen del sistema de Coordenadas Mundiales, luego lo rotaríamos y escalaríamos de manera que coincidieran ambos. Todas esas operaciones las concatenaríamos en una sola matriz y luego de una buena cantidad de cálculos impredecibles que si son listos involucrarán raices cuadradas, divisiones y funciones trigonométricas (y si no son listos también funciones trigonométricas inversas). No me hace falta poner un ejemplo de esto porque lo mas seguro es que ya hayan tratado de hacer esto y si no hay muchos ejemplos en libros y tutoriales de internet. Así que voy a pasar al modo directo de transformar sistemas, pero antes veamos un poco de esas ahora ya no tan temibles matemáticas.
Matrices y Transformaciones Inversas
Como hemos visto hasta ahora, existen transformaciones geométricas que podemos aplicar a nuestros objetos 3D como la traslación, rotación y escala. Sabemos también que podemos generar una secuencia de transformaciones tan extensa como queramos y la podemos almacenar en una sola matriz. Que existen matrices que no hacen nada llamadas matrices de identidad y que esas matrices las usamos para transformar puntos y vectores en el espacio. Lo que hasta ahora no hemos visto es que por cada matriz capaz de aplicar una transformación, existe una gemela maligna capaz de revertirla. Dichas matrices son conocidas como Matrices Inversas y se representan por una letra mayúscula que tiene un exponente -1. Así la inversa de la matriz M es (en notación ascii) M ^(-1). Se sabe que una matriz es la inversa de la otra porque al multiplicarlas en cualquier orden dan como resultado una matriz identidad que solo tiene unos en su diagonal y ceros en el resto de sus partes. No es muy dificil imaginarse cuales son las matrices inversas para la escala y traslación. Pues la de escala Tx, Ty y Tz se sustituyen por -Tx, -Ty y -Tz. Mientras que en la de escala se cambian los factores Sx, Sy y Sz por sus recíprocos 1/Sx, 1/Sy y 1/Sz. La que es verdaderamente dificil de entender es la inversa de la rotación. Por suerte las matrices ortonormales cuentan con una propiedad sin la cual la programación gráfica habría resultado casi imposible: En las matrices ortonormales la inversa es la traspuesta.
Primero veamos que demonios es una matriz traspuesta. Para trasponer una matriz lo que hacemos es separarla por renglones y luego reacomodarlos en columnas verticales tal y como se muestra en la segunda imagen. Esta operación tan engañosamente sencilla esconde el secreto de la inversa de la rotación. Si recuerdan, una matriz ortogonal es la que representa un conjunto de vectores que tienen una longitud de una unidad (por eso lo de “normales”) y hay un ángulo recto de 90 grados entre cualquier par de ellos (de ahí lo del “orto”). En las matrices que hemos manejado hasta ahora cada renglón representa un vector dimensional pero tras aplicarles la trasposición estos vectores pasan a ser las columnas. Podemos obtener mucha información del sistema coordenado que representa una matriz por medio de su determinate. Pero por ahora lo que nos interesa es ver como obtener las rotaciones inversas. Si escriben la matriz básica de rotación que usa el eje Z como eje y la multiplican por su traspuesta el resultado va a ser una matriz identidad. Sin importar si usan el eje Z o cualquier otro solo van a obtener 3 tipos de resultados:
La identidad trigonométrica fundamental
Sen(angulo) ^ 2 + Cos(angulo) ^ 2 = 1
sen(angulo) * cos(angulo) – sen(angulo) * cos(angulo) = 0
0

En resumen, no importa el ángulo en que giremos, si el sistema está compuesto por una base de vectores ortonormales bastará con trasponer la matriz para obtener su inversa. Si los sistemas ortogonales no tuvieran esta propiedad tendríamos que obtener la inversa por el método de Gauss-Jordan. Que consiste en sumar y multiplicar renglones que viene en cualquier libro de álgebra lineal escolar. Proceso que no solo es tardado e impredecible sino que tiene unas pérdidas de precisión demasiado grandes para ser manejados con valores flotantes de precisión sencilla o incluso de precisión doble. Sin mencionar que frecuentemente dan errores de división entre cero.
Pues bien, si queremos hacer una transformación como un cambio de sistema de coordenadas lo primero que tenemos que hacer es definir un sistema de coordenadas que aunque diferente comparte el mismo sistema de Coordenadas Mundiales. En la tercera imagen vemos la nave de los ejemplos anteriores en el plano Z = 0. En la siguiente la hemos rotado y trasladado de modo que quede horizontal sobre el plano XZ (lo que desde donde estamos sería el suelo. Y la nariz queda apuntando en dirección al eje Z. Su centro ahora corresponde con el origen. En la siguiente imagen (la que tiene el triángulo azul apuntando hacia abajo) se muestra la nave en la posición antes descrita que de paso coincide con sus coordenadas de modelado. Veamos ahora como se separan estos dos sistemas.
Coordenadas de Modelado

Los mundos 3D no se diseñan de una sola pieza sino que son una composición de muchas piezas en diferentes posiciones. Piensen en un tablero de ajedrez en el que las fichas no solo tienen formas diferentes sino que pueden cambiar de posición a lo largo del juego. Para poder generar cualquier tipo de escena es necesario contar con un conjunto de modelos básicos que se acomodan en su lugar por medio de una serie de transformaciones geométricas concatenadas en una matriz. Siguiendo con el ejemplo del ajedrez, tenemos un modelo para cada tipo diferente de pieza y mediante esas transformaciones acomodamos una instancia de cada una de ellas en el lugar del tablero que le corresponde. Cuando usamos el Sistema de Coordenadas de Modelado, cada modelo de pieza se mantiene en su propio espacio coordenado ajeno al sistema de coordenadas mundiales del mismo modo que un juguete se guarda en su estuche. Por regla general, los modelos se definen en su propio sistema coordenado de modo que su centro de rotación coincida con el origen y su frente quede en dirección al eje Z de su sistema. Tal y como se ve en la imagen de vista superior de nuestra triangular nave. Por cierto, el que una figura exista en el sistema de coordenadas de modelado no significa que tenga que existir en el sistema de coordenadas mundiales. Como por ejemplo un jefe de final de nivel que no va a aparecer hasta que hayamos vencido al resto de los villanos.
Cuando queremos presentar una figura dentro de nuestro mundo 3D lo primero que hacemos es hacer coincidir las coordenadas de modelado con las mundiales, lo que haría que nuestra figura apareciera en el origen de este último. Luego mediante transformaciones de traslación, rotación o escala acomodamos la imagen donde realmente la queremos. Es importante que recuerden que una cosa es el modelo y otra la instancia. En el ejemplo del ajedrez podemos tener muchos peones en el tablero pero solo necesitaremos un modelo original para crearlos a todos. O poniendo un ejemplo mas acorde a los videojuegos, podemos tener un ejército de miles de robots de dos o tres modelos diferentes, solo necesitamos esos dos o tres modelos diferentes para crear con ellos a todo nuestro ejército. Es por eso que deben de entender bien el concepto de Coordenadas de Modelado y saber la diferencia entre este sistema y el de Coordenadas Mundiales.
Esta nota resultó mucho mas extensa de lo que pensé que sería. Voy a tener que continuarla en la entrada siguiente donde veremos ejemplos de posicionamiento arbitrario de modelos en nuestro mundo 3D. De momento solo puedo adelantarles que existe un método que puede transformar entre coordenadas mundiales y de modelado con tan solo una traspuesta de una matriz y que para hacer esto es necesario conocer el producto vectorial. Poco después de esto vamos a hacer una muy ligera pero significativa modificación a nuestra nave para hacerla verdaderamente 3D y cuando terminemos con todo ello (no mas de 2 o 3 entradas) ahora si entaremos de lleno a lo que es la proyección de imágenes en 3D.
Programación Gráfica: Lineas Rectas en el Espacio 3D
Calcular lineas y sus puntos intermedios
Como ya hemos visto, los objetos en los juegos 3D se definen por 3 arrays que contienen información sobre los vértices, aristas y polígonos. Ya vimos que los polígonos son triángulos definidos por 3 vértices y que el plano en el espacio que contiene a esos polígonos planos puede definirse matemáticamente a partir de las coordenadas de los 3 vértices. Ahora vamos a ver lo mismo pero con las aristas.

Una arista es la linea recta que une 2 vértices. Tanto esta linea como los 2 vértices o puntos de sus extremos están contenidos en una linea de longitud y delgadez infinitas que no tiene ni principio ni fin. Para poder trabajar con estas lineas nos basta con los puntos inicial y final y realmente lo que pase antes y después de esos dos puntos nos tiene sin cuidado. De hecho, cuando nos referimos a estas lineas definidas por dos puntos, ya sean aristas o cualquier otra cosa, les llamamos ‘segmentos de recta’.
Cuando programamos juegos 3D es muy común que necesitemos ubicar puntos dentro de uno de estos segmentos de recta. Por ejemplo saber el punto exacto en el que un rayo golpea a un enemigo o si un objeto se encuentra dentro de una cierta linea, como en una de esas alarmas activadas por laser o algo tan simple como hacer que un personaje avance en linea recta de un punto a otro. Entonces necesitamos un modo de obtener esos valores intermedios a partir tan solo de los puntos en el espacio p0 y p1. Existe algo llamado forma paramétrica de una linea que nos permite calcular precisamente eso. Digamos que queremos obtener el punto P que pertenece a la linea definida por p0 y p1. La ecuación paramétrica de la linea es:
P = p0 + (p1 – p0) * t
O visto por cada componente Px, Py y Pz sería:
Px = p0_x + (p1_x – p0_x) * t
Py = p0_y + (p1_y – p0_y) * t
Pz = p0_z + (p1_z – p0_z) * t
Estas son las 3 expresiones para calcular un punto dentro del segmento de recta definido por los dos puntos en el espacio. Lo mas interesante aquí es el valor de t. Ese valor va a ser igual a cero en el punto inicial del segmento p0 e igual a uno en el punto final p1. En cualquier punto intermedio a estos dos el valor de t se va a mantener entre cero y uno. Si el punto se encuentra fuera de esos extremos el valor va a ser negativo o mayor que uno. Ahora bien, la forma paramétrica se usa para ubicar puntos dentro de la recta, por ejemplo si queremos obtener el punto medio solo sustituimos t por un medio. Aunque puede darse el caso opuesto en que queramos ver si un punto cualquiera en el espacio pertenece o no al segmento de recta. Para hacer esto lo que tenemos que hacer es emplear la forma simétrica de la recta en el espacio. Para obtener esta forma lo único que hacemos es despejar el valor de t en cada una de las expresiones e igualarlas entre si (o simplemente comprobar los valores de t en cada componente. Un punto en el espacio pertenece a la linea en el espacio si al sustituir Px, Py y Pz por sus coordenadas se obtiene el mismo resultado t en las 3 expresiones.
Otros usos de las rectas en el espacio se relacionan con la animación. El motivo por el que el parámetro es representado por la letra t es porque t puede representar el tiempo. Supongamos que queremos hacer que un objeto se mueva del punto p0 al punto p1. Podemos hacer que el objeto aparezca en diversos puntos de esa trayectoria conforme el tiempo t avanza. Incluso es posible agregar términos t de mayor grado para representar curvas mas elaboradas en el espacio. Aunque no es buena idea ir mas allá de las ecuaciones de tercer grado por motivos de eficiencia.
Y hablando de motivos de eficiencia. El trabajo con rectas en el espacio tiene sus trampas, lo mas importante a recordar es que las operaciones geométricas que se usan en programación gráfica son siempre entre rectas y planos en el espacio o solo entre planos. No es buena idea trabajar solo con rectas cuando queramos obtener información. Por ejemplo si queremos saber si dos rectas en el espacio se encuentran, primero tenemos que ver si se encuentran en el mismo plano del espacio y luego obtener los valores de t en cada una de ellas para obtener el punto que tienen en común. Esto es demasiado tardado para una computadora. Lo que se hace, y lo habrán visto en muchos juegos 3D si son observadores, es que cosas como los tiros de rifle, rayos laser o ciertos tipos de ataques de energía dirigida en realidad se representan por pirámides poligonales muy delgadas y no por lineas rectas. Si son lo bastante veteranos y jugaron el primer Star Fox recordarán que los disparos se representaban de esta manera. Es mucho mas eficiente comparar las intersecciones entre estas pirámidas que entre lineas rectas en el espacio.
En fin, lo mas importante es saber cuando usar las rectas en el espacio y cuando los planos. La regla general es que las rectas en forma paramétrica se usan para definir puntos a partir de un parámetro t definido por nosotros y los planos cuando queremos obtener información. Las operaciónes mas importantes entre una linea recta y un plano en el espacio son el recorte y la proyección.
Es posible obtener el plano perpendicular a partir de una linea en forma paramétrica. La diferencia entre las coordenadas nos da las componentes del vector normal al plano y las coordenadas de cualquier punto en la linea, ya sea p0, p1 o cualquier otro punto dado por el parámetro t. Esto nos permite definir un plano perpendicular a cualquier punto dentro de una trayectoria. Por cierto, la forma paramétrica no solo sirve para lineas rectas, se trata de un caso especial de la forma de curvas mas avanzadas.
En la siguiente entrada vamos a ver algo llamado conversión de sistemas de coordenadas, donde verán que todas las transformaciones geométricas pueden reducirse a matrices y que podemos jugar con lo que podríamos llamar ‘cámaras’. Terminando eso ya estaremos en condiciones de trabajar con verdadero 3D. Pues si bien hasta ahora hemos trabajado con un espacio tridimensional XYZ no hemos sido capaces de proyectar una imagen 3D en una superficie plana como la pantalla o una hoja de libreta. Y recuerden que hasta ahora no hemos necesitado de mas herramientas que lapiz papel y calculadora para que luego no digan que no aprenden a hacer juegos 3D porque no poseen una PC con tecnología gráfica super-cara ni el dinero para pagar las licencias de ese software tan exclusivo del que tanto hablan los autodenominados profesionales en los moribundos foros de videojuegos.
Programación Gráfica y los Polígonos en 3D
–Triángulos y Planos en el Espacio–
En los juegos 3D es muy común escuchar que tal o cual modelo está compuesto por no se cuantos miles y miles de polígonos. Cuando escuchamos sobre las capacidades de algún coprocesador gráfico normalmente se nos dice que puede procesar una determinada cantidad de polígonos por segundo y hace algunas entradas vimos aquí que las figuras en los juegos 3D se componen de vértices, aristas y polígonos. Hoy vamos a ver todo lo que un programador de videojuegos debe de saber sobre los polígonos planos en el espacio.

Lo primero que tenemos que dejar claro es que los famosos “polígonos” que forman nuestros amados modelos 3D en realidad son todos triángulos. Los triángulos tienen una serie de propiedades matemáticas que los hacen especialmente eficientes en el campo de la programación gráfica. Por ejemplo, los 3 puntos que definen los vértices de un triángulo siempre se encontrarán en un mismo plano en el espacio (a menos que estén todos dispuestos en linea recta). Cualquier figura que se nos ocurra puede ser subdividida en triángulos, los triángulos pueden ser procesados de un solo paso en sistemas de procesamiento vectorial, siempre son convexos, pueden ser recortados con muy pocas operaciones y muchas otras cosas mas que ya verán cuando tengan que programar estas cosas en una PC. En la primera imagen vemos un triángulo formado por 3 vértices (en plastilina blanca) y 3 aristas (en madera). Como pueden ver, pueden poner ese triángulo en la posición que ustedes quieran y siempre quedará plano.
Como ya saben las caras poligonales se definen como una lista de índices a los 3 vértices que lo conforman. Pero un plano a nivel matemático es mucho mas que eso, lo bueno es que podemos obtener toda la información del plano en el espacio en el que se encuentra este polígono con tan solo los 3 vértices que forman el polígono. Para eso lo primero que tenemos que hacer es convertir esos 3 vértices en dos vectores a los que les podamos aplicar un producto vectorial. Si recuerdan en la nota sobre como modelar objetos en 3D, se dijo que los vértices del polígono se escribian en sentido contrario al de las manecillas del reloj cuando uno los veía de frente. Entonces tenemos los 3 puntos que forman el polígono como P0, P1 y P2. Para obtener los dos vectores U y V hacemos una resta vectorial de modo que U = P1 – P0 y V = P2 – P1. La diferencia entre las coordenadas entre 2 vértices es igual a las componentes del vector que los une. O lo que es lo mismo, se hace una minitraslación. En fin, ya con los vectores U y V podemos hacer un producto vectorial y obtener un vector normal al plano al que llamaremos aquí vector N. Por cierto, el vector N puede llegar a tener una magnitud de cero o un valor muy cercano a este en caso de que los 3 puntos proporcionados estén en linea recta. En cuyo caso no podríamos representar un plano, pues el seno del ángulo entre los 2 vectores U y V sería cero.
En la segunda imagen se ve junto con el triángulo que define nuestro polígono otra pequeña flecha vertical de punta roja. Ese es nuestro vector normal N. Ese vector atraviesa el plano por completo como si fuera un clavo. No importa que punto del plano elijamos, como se trata de una superficie plana este vector va a ser siempre el mismo. Piensen en una de esas camas de clavos en las que descansan los magos de la India. Ahora bien, a menos que el plano que contiene al polígono pase por el origen todavía nos falta un último paso para obtener toda la información del plano. Las coordenadas de cualquiera de los 3 vértices. Aunque nos habría servido igual cualquier otro punto de los infinitos que caben dentro del plano. Ahora veamos la ecuación del plano a nivel matemático.
Ecuación del Plano
Ax + By + Cz + D = 0
Para obtener la ecuación del plano que contiene el polígono definido por los 3 vértices necesitamos calcular los valores de A, B, C y D. Los 3 primeros corresponden a las componentes x,y,z del vector normal N. Para calcular D necesitamos las coordenadas de cualquiera de los 3 puntos que componen el triángulo. Digamos que elegimos P0. Sus coordenadas serían P0_X, P0_Y y P0_Z. Entonces hacemos lo siguiente:
A * (x – P0_x) + B * (y – P0_Y) + C * (z – P0_Z) = 0

Luego de sumar y multiplicar se obtiene el valor de D. Aunque bien hubiéramos calculado D directamente con la expresión -1*(A*P0_X + B*P0_Y + C*P0_Z). Ahora bien, seguro se preguntarán para que demonios queremos esta aburrida expresión. Pues esta aburrida expresión puede servirnos para mas cosas que solo dibujar un simple polígono. Lo mas directo es sustituir los valores de x,y,z por cualquier punto en el espacio. Si el resultado de la expresión es cero o muy cercano a cero (la precisión en una computadora es finita) entonces el punto está dentro del plano. Si el resultado es positivo el punto se encuentra por encima del plano y si es negativo entonces es un lugar por debajo de este. Esta información es muy util para saber de que lado del plano nos encontramos y se usa para detectar colisiones y recortar figuras. La normal del plano nos da información hacia donde apunta la cara del plano. Podemos por ejemplo saber que dos planos son perpendiculares entre si cuando hacemos un producto escalar entre sus normales y el resultado es igual a cero. Si quisiéramos crear por ejemplo una figura alargada (lo que en arte digital llaman extrusión o ‘lofting’ basta tan solo con cambiar el valor de D y redibujar la figura. El vector normal al plano se usa para cálculos de textura e iluminación sobre el polígono, aunque existe una técnica conocida como Normal Mapping en la que se asigna un vector arbitrario a cada punto del polígono para dar la apariencia de que este no es plano. Pero el uso mas interesante de la ecuación de los planos en el espacio es sin duda la proyección geométrica. Pues lo que vemos en pantalla cuando jugamos un videojuego 3D es la proyección sobre un plano de una parte de ese mundo vectorial, como si viéramos por una ventana. Esa ventana es un plano en el espacio y necesitamos lo visto hasta ahora para poder hacerlo.
Algunas otras cosas que deben de tener en cuenta con esto de los planos es que a nivel matemático los planos tienen una extensión infinita y su grosor es infinitamente pequeño. Cuando un plano es perpendicular a uno de los ejes coordenados los valores de A, B o C excepto el del eje que lo traspasa son iguales a cero. Por ejemplo, si hacen esta operación con cualquier polígono en el plano z = 0 que se puede desplegar en la hoja de libreta A y B y D siempre les va a dar cero. Es posible calcular el punto en el que el plano corta los ejes coordenados si dividen los valores de A, B o C entre -D. Por cierto, un mismo plano en el espacio puede ser definido por lo que parecen un sinfin de ecuaciones diferentes. Pero esto siempre va a poder descubrirse si existe un factor por el cual A, B, C y D puedan multiplicarse. Se recomienda en ciertos casos dividir el vector N entre su longitud para evitar errores de pérdida de precisión a la hora de hacer los cálculos.
Por cierto, no está de mas una pequeña advertencia, hay una correspondencia entre los planos en el espacio 3D y las lineas rectas en el mundo 2D. Se considera que el 2D es el plano XY donde Z es igual a cero. La ecuación de este plano es precisamente Z = 0. Una recta en ese plano es en realidad un plano perpendicular a Z = 0 que se alza sobre la hoja como lo haría un muro. Esto es importante que lo tengan en cuenta porque esto tiene muy poco que ver con lo que consideramos una linea recta en el espacio. En la siguiente entrada vamos a hablar sobre las rectas y otras curvas sencillas en el espacio, por ahora esperemos a que salga la nueva nota mientras rezamos a nuestros respectivos dioses que la reciente hola de inactividad en las redes mexicanas de desarrollo de videojuegos se deban a que están planeando algo grande o por lo menos que estén trabajando en algún nuevo juego que pueda pagar sus nóminas atrasadas.
Programación Gráfica y el Producto Vectorial
–Y su uso en cámaras y superficies en los juegos 3D–
Conocido también como el Producto Cruz, el producto vectorial es otra herramienta importante en programación gráfica. Sirve para obtener un tercer vector a partir de otros dos vectores. Este tercer vector es ortogonal (está en ángulo recto) respecto a los otros dos y su magnitud se relaciona tanto con la de los dos vectores originales como con el ángulo que hay entre ellos. En los juegos 3D su mayor utilidad es la de crear sistemas de coordenadas en cualquier parte del espacio a partir de los dátos de una cámara aunque también se utiliza muchísimo al trabajar con superficies y texturas. Ahora veamos como funciona el producto vectorial

En la primera imagen vemos una representación del producto vectorial. Como siempre, los dos vectores que se van a procesar deben de estar anclados en el origen (y si no lo están hay que hacer una traslación). Luego hacemos el producto cruz con los vectores U y V en ese orden. Tras hacer la operación vamos a obtener las componentes de un tercer vector. Ese vector es UxV y se muestra en la foto como la flecha vertical mas pequeña. Antes de meternos con los complicados cálculos matemáticos para obtener UxV veamos algunas propiedades interesantes del producto vectorial aplicables a los juegos 3D.
Lo primero que vemos en la foto es que las flechas de madera y plastilina que representan los vectores U y V descansan en la mesa. Esta mesa representa un plano en el espacio y no es necesario que sea horizontal. Los dos vectores pueden estar en cualquier posición sobre un plano en el espacio. El vector UxV se mantiene vertical sobre la mesa, lo que significa que UxV es un vector perpendicular al plano que contiene los vectores U y V. Este vector UxV está en ángulo recto con los otros dos y su longitud es igual al producto de las longitudes de U y V multiplicadas por el Seno del ángulo que los separa. Esto último es especialmente importante para obtener información sobre el plano en el que se encuentran los vectores originales así como la relación que hay entre ellos. Lo primero es que si los vectores U y V son paralelos (el ángulo entre ellos es 0 o 180 grados o bien 0 o Pi radianes) la longitud de este vector va a ser cero. Esto es muy importante cuando trabajamos con las caras poligonales que forman un objeto 3D. Del mismo modo, si el ángulo entre los vectores U y V es recto (90 grados o 0.5 Pi radianes) el seno del ángulo será igual a uno y la longitud del vector UxV será directamenté igual al producto de las longitudes de sus vectores originales. Esto es especialmente importante al trabajar con las bases ortonormales que se usan para hacer las vistas de cámara.
Por cierto, si hasta ahora no hemos visto la utilidad del producto cruz es porque hemos estado trabajando en el plano XY que forma la hoja de la libreta. Si hiciéramos un producto cruz entre dos vectores en este plano, el resultado sería un vector que saldría hacia afuera de la hoja, o hacia adentro dependiendo del orden en que tomáramos los vectores. El orden en que se toman los vectores influye en que el vector tome una de dos direcciones perpendiculares a los vectores originales. Para entender esto, y otras complejidades del producto escalar es importante que entienda la regla de la mano derecha.
La regla de la mano derecha
Para poder orientarnos en el espacio 3D es necesario adoptar una convención de hacia donde crece el eje Z. La regla de la mano derecha se usa para definir hacia donde va Z en el espacio. Digamos que tenemos dos vectores U y V en el espacio y queremos saber hacia donde se va a dirigir el vector UxV. Para averiguar esto hay que hacer lo siguiente: Primero extienda el brazo derecho con los dedos extendidos en la dirección a la que apunta el primer vector U. Ni se le ocurra hacer esto en público si vive en Alemania porque es delito. Luego doble todos los dedos excepto el pulgar en la dirección que apunta el vector V. Rote el brazo si es necesario. Por último extienda el dedo pulgar. La dirección en la que apunta el pulgar será la que va a tomar el vector UxV. En la foto donde sale una mano junto al modelo del producto vectorial puede verse la regla de la mano derecha en acción. Otra aplicación que tiene la regla de la mano derecha en juegos 3D es la rotación. Es posible saber la forma como un objeto va a rotar dados un vector fuerza y un centro de rotación. Otro buen ejemplo de la vida diaria de la regla de la mano derecha son las roscas de los tornillos y las tapas de las botellas. Solo hay que señalar con el dedo pulgar hacia donde queremos que estos se muevan y al doblar los dedos estos nos indicarán el sentido en el que tenemos que girar.
Por cierto, la regla de la mano derecha es básica para entender el origen y funcionamiento del producto vectorial. Su origen se basa completamente en eso, si quieren saber mas acerca del producto vectorial pueden encontrar mas información en cualquier libro de matemáticas escolar. Por cierto, hasta ahora he hablado mucho de para que sirve pero no he dado nada de información sobre como se calcula. Para ello lo primero que necesitamos es tomar los 2 vectores que queremos cruzar en ese orden. En la última imagen se toman los vectores tridimensionales U y V cuyas componentes son Ux, Uy, Uz y Vx, Vy, Vz respectivamente. Queremos obtener el producto cruz UxV y almacenarlo en un nuevo vector llamado N. Para calcular las componentes Nx, Ny y Nz hacemos los siguientes cálculos

Nx = Uy*Vz – Uz*Vy
Ny = Uz*Vx – Ux*Vz
Nz = Ux*Vy – Uy*Vx
Hay varias maneras de calcular esta fórmula, de momento y para no meternos con términos matemáticos complicados me limitaré a darles un consejo para recordar mejor esta expresión. Lo llamo El 1221. Recordar que hay una resta de dos productos es sencillo, así como recordar que los factores de esos productos van en el mismo orden en el que se lleva a cabo la operación de producto vectorial, en este caso primero U y luego V. La parte dificil es recordar cuales son las componentes vectoriales que necesitamos tomar en cada caso. Aquí es donde entra la técnica 1221. Tenemos 3 componentes vectoriales, el primero es X, el segundo es Y y el tercero es Z. Para calcular por ejemplo el componente X del vector N (Nx) necesitamos tomar las componentes de los 2 vectores en este orden YZZY, para Ny ZXXZ y para Nz XYYX. Aquí es donde entra el 1221, pues son los índices relativos al índice que queremos calcular. Si la suma da un resultado mayor que 3 se le resta 3 al resultado y obtenemos la posición, si eso se les hace muy complicado mejor busquen la fórmula del producto cruz por medio la matriz de cofactores o usando directamente la forma del determinante, conocida en tiempos remotos como “el método de la lluvia”.
Para acabar solo queda mencionar el modo como el producto vectorial se asocia a los polígonos en un objeto 3D. Un polígono o cara triangular se define por 3 vértices no colineales en el espacio. Para obtener 2 vectores a partir de estos 3 puntos se hace una resta entre los vértices que forman 2 de las aristas y luego se hace con ellas un producto vectorial. Este proceso se va a ver con mas detalle en la siguiente entrada cuando veamos como esos 3 vértices definen una cara plana en un objeto 3D y todo lo que se puede hacer con esta. Por ahora tengan paciencia y recuerden que un programador de videojuegos no le teme a las matemáticas.
Programación Gráfica y el Producto Escalar
Aplicaciones del producto punto en los juegos 3D

Antes de continuar con la explicación del producto escalar y sus aplicaciones en programación gráfica quiero dejar clara la diferencia entre cantidades escalares y vectoriales en el mundo de la programación. Una cantidad escalar no es mas que una sencilla variable de punto flotante (o entera si están usando matemáticas Fixed-Point). Ejemplos de cantidades escalares en los videojuegos son por ejemplo el nivel de vida, la cantidad de combustible, el tiempo restante y cualquier otra cantidad representable por un solo valor numérico. Por contra las cantidades vectoriales se representan por arrays donde cada uno de los elementos del array manejan una dimensión. Ejemplos de cantidades vectoriales en los videojuegos son la dirección en la que un personaje se mueve,la fuerza que recibe un objeto al ser golpeado el comportamiento de las luces y la posición en la que los objetos se encuentran en un instante dado. En el caso de las gráficas por computadora la diferencia es mas sencilla. Las cantidades escalares se representan por rectas unidemensionales y las vectoriales por las tradicionales flechas ancladas en el origen. En esta entrada vamos a ver el Producto Escalar.
Todo comienza cuando tenemos un par de vectores de cualquier dimensión atados como siempre por el origen. Para hacer un producto escalar se multiplican cada una de las componentes de uno de los vectores por las respectivas componentes del otro. Los resultados se suman y se obtiene una sola cantidad final. Digamos que tenemos los vectores U y V y sus respectivas componentes en 3D son Ux, Uy, Uz y Vx, Vy, Vz. El producto escalar, también conocido como producto punto se obtiene así: U.V = Ux*Vx + Uy*Vy + Uz*Vz. Esta operación tan sencilla es soprendentemente util en programación gráfica pero antes de ver todas sus aplicaciones veamos todo lo que esconde el aparentemente inocente producto escalar.
Pues resulta que ese inofensivo numerito que se obtiene de aplicarle a dos vectores el producto escalar es lo mismo que si multiplicáramos las longitudes de ambos vectores por el coseno del ángulo que hay entre ellos. Y eso sin necesidad de raices cuadradas ni operaciones raras para obtener ángulos. En el dibujo no lo puse por distraido pero cuando nos referimos a la magnitud de un vector se escribe la letra o nombre del vector entre dos pares de rayas verticales. Algo así como ||V||. Ahora veamos que es lo que podemos ganar por obtener en una sola cantidad la magnitud (como también se le llama a la longitud) de dos vectores y el coseno de un ángulo entre ellos. En la primera imagen se representan los vectores U y V en negro y azul. El ángulo que los separa en verde y la linea roja es el escalar representado.
El primer uso que tiene el producto punto en los videojuegos 3D es ver si 2 vectores son perpendiculares. De serlo el resultado va a ser cero o muy cercano a cero. Esto puede servir para saber si estamos ante una pared recta o inclinada respecto a nuestro punto de vista, es una de las maneras para determinar si una linea o polígono es o no visible. Sirve para ver que tanto refleja la luz en modelos de sombreado plano o en juegos donde el jugador se mueve por superficies irregulares como las montañas, puede combinarse con las normales del suelo para saber hacia donde se moverá. Otra aplicación directa es ver si el ángulo entre dos vectores es muy cerrado o muy abierto dependiendo del signo. Si el ángulo entre los 2 vectores está entre cero y 90 grados (cero y 0.5*Pi radianes) el signo del resultado va a ser positivo. Si es mayor de 90 y menor de 180 (mayor que 0.5*Pi y Pi radianes) el resultado va a ser negativo. Por cierto, como lo que el producto punto calcula es el ángulo interno, que siempre es el menor, el ángulo no puede nunca ser mayor de Pi radianes o 180 grados. Otra propiedad interesante del producto escalar es que no importa si estamos en el espacio 3D o en el mismísimo hiperespacio de 4 dimensiones. El producto escalar siempre va a ocurrir en el plano que contiene a los vectores.

En la segunda imagen se ve como se comporta el producto escalar conforme el ángulo entre ambos vectores aumenta.
Esas son apenas algunas aplicaciones del producto escalar tal y como está. Pero lo mas interesante es cuando combinamos el producto escalar con los vectores normales. Para los que no saben, un vector normal en el sentido escalar de la palabra es un vector que tiene una longitud igual a una unidad. Lo siguiente solo puedo explicarlo con un ejemplo. Supongamos que queremos rotar un cañón de modo que apunte hacia cierto objetivo pero no conocemos el ángulo al que debemos rotar. De momento no sabemos como vamos a obtener el angulo pero sabemos que cuando lo obtengamos vamos a obtener el seno y el coseno y los vamos a meter en una matriz de rotación. Para resolver este problema necesitamos 3 puntos: El punto que indique el centro de rotación del cañón, un punto en la boca de este y el punto en el objetivo al que va a disparar. Lo siguiente es obtener 2 vectores. Para esto trasladamos tanto el canón como el objetivo de modo que el origen coincida con el centro de rotación del cañon. Ahora la boca del cañon y el objetivo forman 2 vectores amarrados por el origen. Se obtiene su magnitud con el teorema de pitágoras y se calcula el producto escalar. El resultado del producto punto se divide por el producto de las longitudes de ambos vectores y obtenemos como resultado el coseno del ángulo que queremos rotar. Para obtener el seno recurrimos al complemento de ángulos o despejamos de la identidad trigonométrica fundamental de seno cuadrado mas coseno cuadrado de un ángulo cualquera es igual a uno. Esto sería para lograr una rotación lenta y dramática. Existe otro método para orientar una figura en cualquier posición dentro del espacio 3D en un solo paso.
Producto Punto y los Sistemas de Coordenadas

Sin duda lo mas importante que se puede hacer al combinar el producto punto con los vectores normales es expresar un vector en términos de otros vectores. Esto hace posible los cambios de cámara, la correspondencia de textura (texture-mapping), manipulaciones en el modelado de objetos y otras cosas que hacen posible eso que los gamers llaman 3D. En la segunda imagen vemos un vector de longitud 5 construido en un sistema de 3 vectores X,Y,Z. Los 3 vectores que definen nuestro espacio tienen una longitud de uno y el ángulo que los separa es recto. Esto en matemáticas se llama Base Ortonormal. Ahora bien, si hacemos un producto punto entre el vector de color azul y cada uno de los vectores X,Y,Z el resultado es la componente del vector en esos ejes. Lo interesante de esto es que esto también aplica a cualquier otro conjunto de vectores en el espacio. Aunque se obtienen muchas ventajas si se trata de un conjunto de vectores ortonormales. Por cierto, si notaron similitud entre el producto escalar y la multiplicación de matrices no es ninguna coincidencia. De hecho el multiplicar dos matrices de 1 por n y n por 1 siendo n un entero es exactamente lo mismo que hacer un producto escalar.
Una cosa mas, los procesadores de Intel a partir del Pentium 4 son capaces de hacer en una sola instrución máquina un producto escalar con precisión flotante de 64 bits. La instrucción se llama DPPD (Dot Product Packed Double). Pero por ahora sigamos con simple lapiz y papel, y la calculadora que hará las veces de nuestro GPU.
Programación Gráfica, Transformaciones y Coordenadas Homogeneas
Y el Secreto de la Cuarta Dimensión
En la entrada anterior vimos lo que son las matrices y su importancia en la Programación Gráfica, así como la manera de escribirlas y multiplicarlas. Esta vez vamos a ver como se hace para meter una o varias transformaciones geométricas en ellas. Pero antes de empezar hay que explicar algo muy importante sobre estas 2 matrices en particular. La verdadera razón de porqué miden 4 por 4 y 4 por 1.

La verdadera razón por la que las matrices miden 4 por 4 es porque en realidad estamos trabajando en 4 dimensiones. Este sistema se denomina Sistema de Coordenadas Homogeneas y es necesario para poder integrar la traslación con la rotación y escala. El fundamento matemático de las coordenadas homogeneas es digno de un argumento de película de ciencia ficcion con todo y viajes por el hiperespacio y la existencia de universos paralelos. El sistema es mucho mas facil de entender cuando se trabaja en el plano (3 dimensiones en coordenadas homogeneas) En tal sistema el mismo punto existe de manera simultanea en una infinidad de planos paralelos de tal manera que todos están alineados por una linea que pasa por el origen. Todos estos planos son perpendiculares a su vez al vector que representa la dimensión extra. De momento lo único que necesitamos saber sobre las coordenadas homogeneas es que nos permiten manejar cualquier tipo de transformación en una matriz de 4 por 4. Además que por la forma como las computadoras trabajan, es mucho mas rápido tener acceso a estructuras de datos cuyo espacio en memoria sea una potencia de dos. Solo para que estén prevenidos, la dimensión extra en una matriz de coordenadas homogeneas es representada por el último renglón. Y aunque no vamos a necesitar cambiar de espacio, la componente hiperespacial (este no es un chiste geek, el término hiperespacio realmente existe en los libros de matemáticas y se usa para referirse al espacio de 4 dimensiones) suele nombrarse simplemente como W y si no quieren meterse en lios mantengan siempre ese valor W igual a 1.
En el primer par de imágenes que acompaña esta entrada se muestran todas las matrices de transformación geométrica que hemos visto hasta ahora mas unas pocas que aunque no son comunes pueden resultar útiles. Otras tantas son de interés mas bien matemático, por lo que aunque no se aplican directamente siguen siendo necesarias en la programación grafica. Ahora veamos la explicación de cada una.
Matriz Identidad
La Matriz Identidad es neutral. Tiene unos en su diagonal y ceros en todos los demás espacios. Cualquier matriz que sea multiplicada por la Identidad permanece sin cambio. Para nosotros, una matriz identidad es como una hoja en blanco o un disco recién formateado y listo para guardar nuestra información. Cuando queramos iniciar una cadena de transformaciones siempre iniciamos con una Matriz Identidad.
Matriz de Traslación
Esta matriz suma a cada una de las componentes vectoriales los valores indicados por Tx, Ty y Tz. Nótese que si no tuviéramos una matriz de 4 por 4 hacer este cálculo con matrices resultaría imposible. Tampoco afecta la componente hiperespacial W.

Matriz de Rotación
Esta es la matriz que implementa los cálculos de rotación vectorial en el plano. La del ejemplo hace la rotación en el plano Z = 0 (tengo que explicar las matemáticas de los planos en el espacio). Si recuerdan lo dicho al principio, cada renglón de las matrices representa una dimensión del espacio. En este caso el renglón correspondiente a Z permanece igual que el de la matriz identidad y si se fijan tanto en sentido vertical solo hay ceros. Esta es la clave para hacer rotaciones en cualquiera de los otros ejes. Tan solo hay que elegir el eje de rotación, tomar el renglón correspondiente en la matriz identidad, poner ceros en sentido vertical y horizontal usando como centro el 1. (como si fuera una cruz) y acomodar los términos trigonométricos en los 4 espacios que queden en los renglones correspondientes a las 3 primeras dimensiones. De momento traten de no meterse con la dimensión W.
Matriz de Escala
La Matriz de Escala tiene en la diagonal principal los factores en los que los vectores se van a escalar en cada uno de sus componentes. Si queremos hacer un escalamiento uniforme en las 3 dimensiones los valores de los 3 primeros renglones deben de ser iguales. Tengan cuidado de no escalar la dimensión W porque pueden terminar con un vector proveniente de un universo paralelo que no les va a servir en los cálculos de nuestro espacio 3D de todos los dias.
Matriz Espejo
(no representada)
La matriz espejo voltea las figuras de la misma manera como un espejo crea un reflejo simétrico de quien se para frente a él. Su uso mas importante es el de ayudar en la transformación de Coordenadas de Vista a Coordenadas de Dispositivo pero puede usarse siempre que necesitemos invertir la dirección de un eje. Para voltear con respecto a un eje basta con tomar la matriz identidad y multiplicar por -1 los unos correspondientes al renglón en cuya dimensión querramos hacer el efecto del espejo. Puede ser en mas de una dimensión. En realidad la matriz espejo es una matriz escala, cuando escalamos una imagen vectorial por un factor de -1 estamos haciendo la misma operación que la matriz espejo
Matriz de Sesgo o Shear
(no representada)
Esta es la mas extraña de las matrices básicas de transformación geométrica. La única aplicación que he encontrado para esta transformación sirve para ajustar Coordenadas de Vista. De todos modos puede que la necesiten para cálculos mas avanzados que veremos en detalle en una entrada futura. Esta matriz puede ser paralela a alguno de los ejes.
Composición de Transformaciones
Como ya se dijo desde la entrada pasada, las matrices pueden contener no solo una sino una larga serie de transformaciones geométricas que a la hora de aplicarse a un vector el efecto es el mismo que si aplicáramos cada una de esas transformaciones en el mismo orden en que las guardamos en la matriz. También sabemos que esta concatenación y aplicación de transformaciones se da por medio de la multiplicación de matrices. Lo que no sabemos es exactamente como se hace esto ni mucho menos como se representa. En estas entradas por convención se ha decidido que los vectores se representan como matrices columna de 4 renglones por 1 columna que se post-multiplican por las matrices de transformación. Aunque hay algunos libros sobre gráficas por computadora que premultiplican usando matrices de 1 por 4. Como en la multiplicación de matrices el orden de los factores si altera el producto se le llama premultiplicar a multiplicar a la izquierda y postmultiplicar a multiplicar hacia a la derecha. En estas notas se usan vectores columna para representar puntos y vectores y las matrices se concatenan multiplicándolas por la izquierda. Espero que la última imagen deje estos conceptos lo bastante claros.

Para terminar esta nota me queda escribir el modo como se representan las matrices en forma simbólica. Ya saben que la matriz se representa por una letra mayúscula y que cada uno de sus elementos se escribe con esa misma letra en minúscula seguida de los subíndices que representan renglón y columna. En escritos como este, así como en muchos otros libros sobre gráficas por computadora se suelen escribir las matrices de transformación seguidas de un grupo de argumentos entre paréntesis y separados por comas como se hace en funciones de lenguajes como C/C++. Por ejemplo una matriz de traslación puede escribirse T(tx,ty,tz) o una de rotación como R(angulo). Cuando se multiplican dos matrices algunos libros solo escriben las letras mayúsculas juntas y otros las separan con un punto. Cuando se concatenan transformaciones se multiplican las matrices por la izquierda (premultiplicación). Digamos que queremos trasladar al origen, rotar, escalar y regresar un punto P de una imagen mas grande. La operación se vería así:
T(Tx,Ty,Tz).S(factor).R(angulo).T(-Tx,-Ty,-Tz).P
Otra cosa que vale la pena mencionar es que cuando se saca la inversa de una cadena de transformaciones estas no solo cambian por sus “gemelas malignas” sino que también se invierte el orden en que se multiplican. Veremos eso mas adelante cuando veamos como se hacen transformaciones espaciales mas avanzadas. De momento en las próximas notas veremos como se manejan los objetos en el espacio y algunas sencillas pero muy valiosas herramientas matemáticas usadas en la programación de videojuegos 3D. Ya no hago mas advertencias sobre números porque estoy seguro de que para este nivel los que se asustan con eso ya dejaron de leer estas lineas. Solo les recuerdo que si tienen dudas recuerden la primera ley del programador de videojuegos que es un programador de videojuegos no le teme a las matemáticas.
Programación Gráfica y las Matrices
–La Mecanización de los Cálculos–
Las matrices son una interesante entidad matemática muy relacionada con los juegos 3D. Son cuadros de números que las computadoras modernas pueden procesar mucho mas rápido que las tradicionales expresiones aritméticas de todos los dias. El tema de las matrices llena libros enteros de esos que las únicas palabras que se entienden son “sea”, “tal que” y “entonces”. Así que para no fastidiarlos voy a discutir sobre el tema cuando sea absolutamente necesario. De momento les basta saber que necesitan entender de matrices no solo para hacer programación gráfica sino para poder programar hardware de aceleración 3D como se debe.

En la primera imagen vemos los dos tipos de matrices que vamos a necesitar. Una matriz es un array bidimensional donde cada elemento se localiza por el renglón y la columna en la que se encuentra. En el dibujo los subíndices (los pares de números mas chiquitos) indican el renglón y la columna. Aunque las matrices pueden tener cualquier tamaño, nosotros solo vamos a necesitar las de 4 renglones por 4 columnas para las operaciones de transformación y las de 4 renglones por una columna para los vectores y vértices que vamos a procesar. Antes de ver como se usan las matrices en programación gráfica voy a tratar de explicarles en términos sencillos porqué son tan importantes.
Hasta ahora hemos visto fórmulas aritméticas que transforman gráficos vectoriales por medio de la traslación, rotación y escala. Estas fórmulas son muy diferentes unas de otras y como hemos visto para poner una imagen vectorial en su posición final es necesario aplicar una larga cadena de transformaciones geométricas a una lista aún mas larga de vectores. La complejidad del código para hacer esto así como la enorme cantidad de operaciones es demasiado pesada aún para una computadora muy poderosa. Recuerden que los mundos 3D actuales pueden estar formados por varios millones de polígonos. Pero no se preocupen porque las matrices vienen al rescate.
La primera gran ventaja de las matrices es que son capaces de almacenar secuencias de transformaciones geométricas y luego aplicarlas de un solo golpe. Digamos que para acomodar una figura en un cierto lugar primero tenemos que trasladarla al origen, escalarla, rotarla un cuarto de vuelta y luego colocarla en su posición final. Tendriámos que aplicar esas 4 transformaciones a cada uno de los vectores que forman la imagen en ese orden. Pero si usamos matrices podemos formar una cadena de esas 4 transformaciones y obtener una matriz que pudiera aplicar esas 4 transformaciones a un vector en un solo paso. La cantidad de transformaciones que podemos encadenar en una matriz no tiene mas límite que la pérdida de precisión por parte de los valores flotantes que pueda manejar el sistema. En una matriz podemos meter no solamente transformaciones geométricas, sino también avanzados cálculos de vista de cámara e iluminación. Por no mencionar que los sistemas gráficos actuales son capaces de procesar estas matrices en apenas unos pocos ciclos de reloj.
La segunda ventaja que tienen las matrices es su versatilidad. Basta con crear un par de funciones para procesar matrices en lugar de tener una función para cada transformación geométrica. Esas funciones son la que concatena transformaciones y la que las aplica a los vectores. Aunque existe una matriz diferente para cada tipo de operación gráfica el código que las implementa es siempre el mismo.
Si todos estos argumentos no los convencen, déjenme decirles que la primera vez que me topé con las matrices cuando estudiaba (por mi cuenta) programación gráfica lo primero que pensé fue que era demasiado esfuerzo para el CPU. Luego vi que había muchas formas de implementarlas. La mas sencilla involucra 3 ciclos anidados y ocupa apenas unas 5 lineas de código en C/C++. Esta es la mas tardada. Usando la FPU puede tomar de 50 a 200 lineas pero es mucho mas rápido que la de ciclos anidados en alto nivel. Luego usando la Streaming SIMD Extensions toma unas 30 lineas y se ejecuta en unos 20 ciclos de reloj y finalmente las aceleradoras mas potentes pueden levantar lotes compuestos por millones de matrices y vectores de una sola vez y procesarlos de manera independiente del CPU en un tiempo todavía menor por unidad. Ahora sigamos con un poco de teoría aburrida sobre estas poderosas y cuadradas entidades.
Como Multiplicar Matrices
Lo primero que tenemos que ver es que las matrices son rectangulares. Sus medidas se especifican por la cantidad de renglones y columnas que las componen, pueden ser tan pequeñas como un renglón y una columna o extenderse de manera indefinida. Para referirnos a una matriz completa le ponemos por nombre una letra mayúscula y cuando queremos mencionar un elemento de esa misma matriz escribimos la letra que la nombra en minúscula seguida de los 2 números que indican el renglón y columna separados por una coma. Por ejemplo, si la matriz se llama A el elemento del primer renglón y la segunda columna de esa matriz sería a_1,2. El guión bajo _ es tan solo para que la expresión sea mas sencilla de leer.
Nosotros solo necesitamos matrices de dos tamaños. La primera mide 4 renglones por 4 columnas y es la que almacena y concatena las transformaciones vectoriales. La segunda tiene 4 renglones y una sola columna y guarda las componentes vectoriales o las coordenadas de los vértices según sea el caso. La operación mas importante con matrices es el producto o multiplicación matricial. Para multiplicar dos matrices, la cantidad de columnas de la primera debe de ser igual a la de renglones de la segunda. La matriz que de como resultado el producto va a tener la misma cantidad de renglones de la primera y de columnas que la segunda. Explicado con abejitas y flores, para que dos matrices puedan casarse y tener hijos la cantidad de columnas de la primera debe de ser igual a la de renglones de la segunda y el hijo que tengan va a salir con la cantidad de renglones de la primera y columnas de la segunda. A diferencia de la multiplicación de todos los dias, aquí el orden de los factores SI altera el producto. Es decir que AB es distinto de BA.
La definición seria de la multiplicación de matrices involucra letras griegas, signos raros y subíndices que me da mucha flojera escribir así que lo explicaré con palabras. Si tenemos 2 matrices multiplicables A y B y la matriz C va a ser el producto. Cada elemento de la matriz C es el resultado de la suma de los productos del renglón de la matriz A y la columna B correspondiente. Si saben lo que es un producto escalar no tendrán problemas para entender esto pues la multiplicación de dos matrices de 1 por 4 y 4 por 1 es exactamente la misma que da este producto vectorial. Pero como esto es bastante dificil de entender lo voy a explicar de manera gráfica.

En la segunda imagen se muestra la mejor manera de acomodar las matrices en una hoja para multiplicarlas de manera manual. Primero la hoja se divide en 4 partes iguales.El cuarto de arriba a la izquierda se deja para anotaciones y cálculos intermedios, en el cuarto de abajo a la izquierda se escribe la primera de las matrices que se van a multiplicar. En el cuarto superior derecho la segunda matriz que multiplicaremos y finalmente el cuarto inferior derecho es donde vamos a escribir el resultado. Para que los resultados salgan bien los elementos de las matrices deben de quedar bien alineados. Recuerden que estamos usando papel cuadriculado para hacer esto mas facil. Ahora bien. En el ejemplo del dibujo se multiplican 2 matrices de 4 por 4. Para calcular el primer elemento del resultado correspondiente al primer renglón y primera columna tomamos el primer renglón de la matriz A y la primera columna de la matriz B (aquí encerrados en rojo) y llevamos a cabo la operación de la última imagen. En este caso se escribiría:
(c_1,1) = (a_1,1)*(b_1,1) + (a_1,2)*(b_2,1) + (a_1,3)*(b_3,1) + (a_1,4)*(b_4,1).
El resultado de esta operación se escribe en la posición (c_1,1) y se repite el mismo procedimiento para los otros quince elementos de la matriz C. Recuerden que acomodar las matrices de esta manera permite saber que renglones y columnas de que matriz necesitamos tomar para calcular el resultado de una posición en la matriz C. Solo basta con mirar hacia arriba y a la izquierda del elemento que queremos obtener.
La multiplicación de matrices de 4 por 4 se usa para concatenar transformaciones. Cuando queremos aplicarle una transformación o una cadena de transformaciones (en términos de performance da igual si es una o un millón) a un vector. Repetimos el mismo proceso pero poniendo un vector de 4 renglones por una columna como la segunda matriz. El resultado es una matriz de 4 renglones por una columna cuyos 4 elementos son las componentes del vector ya transformado.
Espero que hayan seguido mi consejo de la entrada anterior y dispongan de una manera rápida de multiplicar matrices. De lo contrario les va a llevar por lo menos media hora multiplicar cada una a mano. En la siguiente entrada veremos como implementar las transformaciones geométricas básicas usando matrices y cuando hayamos visto esto estaremos en posición de entender uno de los conceptos mas importantes de la programación gráfica: La Transformación de Sistemas de Coordenadas. Aunque puede que antes de llegar a eso debamos de ver unas cuantas cosas sobre matrices y vectores en el espacio 3D.
Programación Gráfica y la Rotación Puesta en Práctica
–Como rotar y orbitar una figura en 3D–
En una entrada anterior se explicó todo lo que había que saber sobre la rotación de imágenes vectoriales. Ahora vamos a ver como se aplica lo ya visto. Para rotar una imagen vectorial un ángulo determinado usando Z como el eje de rotación lo que hacemos es aplicarle a todos los vértices que la componen las fórmulas de rotación:
Nueva_X = Vieja_X * coseno(angulo) – Vieja_Y * seno(angulo)
y
Nueva_Y = Vieja_X*seno(angulo) + Vieja_Y * coseno(angulo).
Y al igual que como sucedió con la traslación y escala, la rotación tiene efecto en el vector que encadena a cada vértice con el origen del sistema coordenado y no directamente con el vértice. Lo que significa que las rotaciones son siempre con respecto al origen.

En la primera imagen vemos la nave rotada sucesivamente en montos de 45 grados sin centrarse en el origen en rojo y la misma nave primero trasladada para que su centro coincidiera en el origen antes de aplicar la misma rotación. De este modo puede apreciarse como los objetos vectoriales siempre rotan con respecto al origen. A veces cuando se desea conseguir el efecto de que algo orbita alrededor de un punto se hace la rotación con origen en el punto sobre el que va a rotar. Pero la mayor parte del tiempo las rotaciones se hacen siempre respecto a un punto interior de la propia figura.
Ahora bien, se han de estar preguntando como se hace para que una figura en cualquier lugar del espacio rote respecto a su propio centro sin que se ponga a dar vueltas como un insecto en torno a una luminaria. La respuesta es que no se puede, al menos no sin involucrar una operación de traslación que primero desplace la figura hasta el origen y otra al final para regresar a la figura al lugar donde se encontraba al principio. De hecho, en programación gráfica, toda la geometría se hace combinando muchas transformaciones geométricas. Por fortuna existe un método para hacer esas transformaciones muy rápido, un método que veremos en la siguiente entrada, pero por ahora sigamos con las rotaciones.
Hay una cosa mas que deben de saber sobre las rotaciones. Que como la precisión de los números de punto flotante influye directamente en la velocidad y el espacio en memoria suelen usarse flotantes de 32 o a lo mucho 64 bits. Esto hace que exista un error que va acumulándose conforme se llevan a cabo las rotaciones. Si a los valores de los vértices de la figura les aplicamos muchas rotaciones va a llegar un momento en el que la figura se va a comenzar a deformar. Para evitar este desagradable efecto lo que se hace es conservar los valores originales de la figura y mostrar la figura ya transformada en pantalla. Voy a tratar de explicarlo: Digamos que ustedes quieren que una figura centrada en el origen se mantenga dando vueltas hasta que el usuario presione algún botón. Si aplicamos tablas precalculadas y grados de 8 bits como se explicó en la nota sobre las rotaciones haríamos un ciclo infinito en el que rotáramos la figura un grado de 8 bits cada vez. Bueno, si hacemos esto la figura comenzará a deformarse luego de unas cuantas vueltas. Ahora veamos como evitarlo. De nuevo hacemos ese mismo ciclo infinito, solo que ahora en lugar de rotar los vértices un grado en cada iteración lo que hacemos es incrementar un contador inicializado en cero y pasárle su contenido como el ángulo en el que la figura va a rotar. En la iteración cero va a rotar 0 grados, en la 1 un grado y así sucesivamente. Para evitar el error acumulado en lugar de actualizar los valores de los vértices usamos los valores devueltos por la rotación para desplegar la figura en pantalla y luego nos olvidamos de ellos.
En general este es el principio de las Coordenadas de Modelado, que es asignarle un espacio propio a los modelos básicos a partir del que se hacen los modelos finales que van a aparecer en el sistema de Coordenadas Mundiales. Para explicarlo piensen en un ejército de miles de robots idénticos cada uno en haciendo sus propios movimientos en su propio lugar. Aunque en el campo de batalla representado en Coordenadas Mundiales parezca que son muchos todos se crean a partir de un mismo modelo de robot creado en su propio espacio independiente al que se le han hecho miles de copias y a cada una se le ha aplicado una transformación geométrica diferente.
Es oportuno que les diga un par de cosas sobre las transformaciones geométricas, sobre todo las de rotación y escala, y es que rara vez se utilizan de la manera en que las acabamos de ver. La mayor parte del tiempo queremos rotar una imagen de modo que se alinea con un vector determinado como un cañon que apunta directo hacia el blanco o un escuadrón de naves espaciales que vuelan en una formacón determinada queremos escalar una pieza de modo que rellene el espacio vacio que dejan otros dos objetos. No caigan en la trampa por ejemplo de querer obtener un ángulo para alinear una figura a partir de funciones trigonométricas inversas, y aunque esta operación es posible en las avanzadas computadoras actuales verán que todo puede arreglarse echando mano de amistosas sumas y multiplicaciones.
Antes de continuar con esta serie de Programación Gráfica usando lapiz y papel, les advierto que a partir de la siguiente entrada vamos a comenzar a hacer cálclos que aunque son sencillos puede que les resulten en extremo tediosos. Si bien es posible llevarlos a cabo a mano o con una calculadora sencilla, les recomiendo que si tienen poca paciencia se consigan una calculadora capaz de hacer cálculos vectoriales (Sharp maneja unas a muy buen precio) o tengan cerca de la libreta una computadora con un programa de hoja de cálclo sencilla. Pues hacer los cálculos a mano va a llevarles casi media hora por cada transformación geométrica con los métodos que pronto vamos a ver.
Programación Gráfica y el Escalamiento
–Manejo de distancias y longitudes en 3D–
Escalamiento es cambiar la longitud de un vector. En esta siguiente entrada sobre la serie de programación grafica con lapiz y papel vamos a ver como los gráficos vectoriales pueden cambiar de tamaño. Pero antes tenemos que entender el concepto de distancia en el espacio 3D. Lo que seguro habrán escuchado en alguna clase de física elemental fue que un vector tiene magnitud, dirección y sentido. La magnitud se refiere a la longitud desde su base en el origen hasta la punta de flecha. No en todos los vectores la magnitud tiene relación con la longitud. Por ejemplo en los vectores de fuerza e iluminación el significado de su magnitud no tiene nada que ver con la longitud. Pero ahora que trabajamos con figuras si lo será.

De seguro todos ustedes han escuchado del Teorema de Pitágoras, ese que dice el cuadrado de la hipotenusa es igual a la suma del cuadrado de los dos catetos.. De forma breve se discutió en la entrada sobre las rotaciones, Para medir la magnitud de un vector basta con elevar al cuadrado (multiplicar por si mismas) cada una de las componentes del vector y luego sumarlas. A la suma se le saca la raiz cuadrada y el resultado es la magnitud del vector. De seguro muchos de ustedes ya sabian esto. Lo que muchos no saben es que esta técnica funciona para espacios de cualquier dimensión, tanto si manejamos una, dos o tres dimensiones. En el caso de que queramos medir la distancia entre dos puntos en el espacio solo hay que restar ambos puntos para obtener las componentes del vector. Esto en realidad hace una traslación al origen.
Ahora bien, supongamos que tenemos un segmento de linea en el espacio y queremos multiplicarlo por un factor S para cambiar su longitud. Para lograrlo basta multiplicar cada una de sus componentes por S. En la primera imagen se muestra que esto es perfectamente válido en el sentido matemático. Para los que quieren programalo de una vez las fórmulas son Nueva_X = Escala * Vieja_X y Nueva_Y = Escala * Vieja_Y . Sin embargo, el escalamiento vectorial aplicado a la programación gráfica no es tan sencillo como esto.
Como recordarán de la nota sobre la traslación. Los vértices de la imagen están asociados a un vector que los encadena con el origen cuyos componentes corresponden con sus coordenadas. Cuando hacemos un escalamiento lo que cambiamos de tamaño son esos vectores y no las aristas. Esto se debe a que el escalamiento y en la siguiente entrada verán que también la rotación dependen del origen. Escalar sin tomar en cuenta la posición relativa al origen puede hacer que las figuras cambien de lugar y no solo de tamaño. En la segunda imagen se ve la misma ‘nave’ de la entrada anterior escalada por el mismo factor de 2. La razón por la que se mueven de su lugar es por su posición con respecto al origen. Ahora lo que tenemos que averiguar es donde demonios tenemos que posicionar la figura para que se escale de manera simétrica y permanezca en su lugar. Si el factor se hubiera encontrado entre 0 y 1 la imagen no solo se hubiera reducido sino tambien acercado al origen. Al ser mayor que uno, la imagen aumenta sus medidas y se aleja del origen.

Por cierto, esto no es un error, a veces queremos escalar figuras vectoriales de manera no uniforme, por ejemplo estirar en una sola dirección un cilindro para simular una prensa mecánica o elevar el suelo en un juego de plataformas. O si queremos programar un editor gráfico. Pero como en este caso queremos escalar una figura de manera uniforme y que no se mueva lo que debemos hacer es que su centro coincida con el origen del sistema de coordenadas y luego escalar por el factor deseado. Hay cierto caso en el que es necesario tomar un factor de un medio pero eso lo veremos cuando manejemos el concepto del Puerto de Vista mas adelante.
La escala en programación gráfica tiene muchos usos además de cambiar las cosas de tamaño. Se usa por ejemplo para ajustar cosas a una cierta medida. También se usa para compensar las diferencias entre las proporciones de ancho y altura de los monitores (conocido como aspect-ratio) y para ajustarse a ventanas de cualquier tamaño cuando no trabajamos a pantalla completa. La verdad es que del escalamiento hay mas bien poco que decir.
Ya nada mas falta escalar esta entrada para que compense la longitud. La verdad era que pensaba abordar el tema de la rotación y escala en una misma nota pero era demasiado material para una sola nota y muy poco para dos así que voy a sacar ambas notas de manera casi simultanea. Y ya para terminar les recuerdo que estas entradas no solo le van a servir a programadores que quieran hacer su propio motor gráfico sino también aquellos que ya disponen de uno pero no saben como hacerlos funcionar. La verdad es que da pena ajena ver como algunos grupos no son capaces de hacer trabajar uno de esos sistema de manera decente ni siquiera después de esa exhaustiva capacitación de 3 meses que reciben los developers al entrar a trabajar a esas reputadas empresas de videojuegos que andan (o andaban) por ahí. Me pregunto si será acaso que estar titulado de lo que sea los deja sobrecapacitados para desempeñar esa clase de trabajos tan especializados.
Programación Gráfica, Modelado y Traslación
–Como definir y mover imágenes vectoriales–
La serie sobre programación gráfica con lapiz, papel y calculadora continua. Esta vez vamos a definir la figura vectorial mas sencilla que podemos representar. Esta nota consta de 3 partes donde primero vamos a acabar de definir el espacio de coordenadas, luego crearemos la figura mas sencilla posible que es posible representar con estas técnicas y luego vamos a moverla por el espacio. Comencemos.

Lo primero que haremos en nuestra libreta de cuadrícula será dibujar un cuadro de 20 por 20 cuadritos y lo partiremos en 4 para formar un espacio de coordenadas x,y,z. Recuerden que en el papel tenemos las coordenadas x,y y que la z sale de la hoja como si se tratara de un poste. Este espacio será nuestro mundo y lo vamos a limitar. Sus límites son de -10 a 10 en los 3 ejes. Aunque durante esta entrada solo vamos a trabajar en el plano de la hoja que corresponde a z = 0. El origen debe de quedar justo en el centro del cuadro. Por cierto, como esta vez estamos trabajando con coordenadas de punto flotante (o decimales en el caso de la calculadora) podemos representar puntos en cualquier parte dentro del cuadro y no solo en las intersecciones de la cuadrícula como en el caso de las coordenadas físicas. Aunque en este caso las intersecciones representan los números enteros.
Ahora viene lo que todos ustedes estaban esperando: Vamos a hacer una nave espacial en 3D. Pero como ustedes son principiantes y están trabajando solo con lapiz y papel vamos a hacer una muy pero muy sencilla. Un inofensivo triángulo. Con mucha pero mucha imaginación pueden imaginarse que se trata de un F-117 o un Destructor Imperial visto desde abajo. Aunque si entre ustedes hay gamers muy veteranos, de seguro verán que nuestra nave es idéntica a la del viejo juego Asteroids. Mas adelante modificaremos muy ligeramente este triángulo para hacerlo verdaderamente 3D pero por ahora lo mejor es dejarlo como está para no complicarnos la vida.
Como definir objetos vectoriales

Como se explicó brevemente en una entrada anterior. Los vectores no tienen nada que ver con los pixeles. En lugar de definir dibujos creados por cuadros de un solo color las gráficas vectoriales se definen por vértices, aristas y polígonos. En el caso de nuestra nave, esta se compone de 3 vértices, 3 aristas y un polígono. Cuando formamos una figura en 3D usamos 3 arrays para este tipo de datos. El primero es el array de vértices. Por cuestiones de eficiencia que verán en un par de entradas mas cada vértice ocupa 4 números flotantes de precisión sencilla de 32 bits o 128 bits en total. Aunque algunos sistemas mas avanzados de animación usan precisión doble de 64 bits o extendida de 80 bits. Cada vértice se identifica por su posición dentro del array. Luego sigue el array de aristas. Una arista es una linea que une dos puntos. Para guardar cada arista necesitamos dos enteros. Cada uno de estos enteros es el índice al array de vértices. En el ejemplo la arista 0 une los vértices 0 y 1, la siguiente el 1 y 2 y la última el 2 y 0. Por último tenemos el array de polígonos. Los polígonos se guardan de la misma forma de las aristas, solo que se usan 3 enteros porque cada polígono, o debería decir cara triangular. En este caso como solo tenemos una cara, esta se define por los vértices 0,1 y 2. Este es un ejemplo en extremo simplificado. En la actualidad tan solo un personaje de videojuego puede estar compuesto por cientos de miles o incluso hasta unos pocos millones de estos triángulos.
Otra cosa importante sobre los polígonos. El orden en la que enlistan los vértices que lo forman es cosa seria. No solo deben acomodarse de modo que al seguir los puntos con una linea se forme un triángulo sino que este triángulo debe dibujarse en sentido contrario al de las manecillas del reloj. Esto es porque los polígonos solo pueden ser vistos por una de sus caras. Además de que facilita ciertas operaciones vectoriales muy importantes tanto para la eliminación de partes ocultas como para los detalles de textura e iluminación. En la segunda imagen tenemos toda la información que necesitamos para construir nuestra nave espacial.
Ahora es buen momento para recordarles que los vértices, aunque pueden posicionarse en cualquier parte de nuestro espacio, en realidad no son libres. Sino que están anclados al origen por el vector que tiene por componentes. Aunque a la hora de hacer las gráficas no lo representemos ese vector siempre está ahí. Recordar esto es muy importante cuando hagamos transformaciones geométricas. Y la mas elemental de ellas es la Traslación.
Traslación
Pues bien, ya tenemos nuestro espacio bien delimitado y hasta una nave espacial suspendida en él. Ahora veremos la mas elemental de las transformaciones geométricas vectoriales: La traslación. Traslación es trasladar algo de un lugar a otro y es sumamente facil. Para mover nuestra nave por el espacio basta con hacer una suma vectorial. Como la explicación matemática es demasiado revuelta para una operación tan facil voy a irme directo al ejemplo. Digamos que queremos que nuestra nave se eleve 10 unidades. Solo tenemos que sumar 10 a la coordenada Y de cada uno de los vértices que componen la nave. Si quisiéramos centrarla de modo que el origen coincida con su centro restaríamos 2 a la coordenada X de todos los vértices y 3 a la coordenada Y. Por cierto, es muy importante que cuando definamos una figura de manera vectorial definamos un centro. Ese centro es importante para muchos cálculos como veremos mas adelante al estudiar la rotación y escala. De momento practiquen moviendo la nave de un lado a otro sin salirse del espacio definido

Realmente hay muy poco que discutir sobre la traslación de objetos en el espacio. Es tan sencillo como sumar componentes vectoriales. Ojo que cuando digo sumar, también puedo estar hablando de sumas con números negativos, lo que tendría el efecto real de una resta, y cuando digo multiplicar puedo estar hablando de números entre cero y uno, lo que en realidad divide. Lo único interesante sobre la traslación es que su fundamento técnico se basa en algo llamado Desplazamiento Vectorial. En la última de las imágenes de esta entrada se puede ver como la nave dibujada junto con los vectores que unen cada uno de sus vértices con el origen. En la parte de abajo la nave se desplazó dos unidades en el eje X y -6 unidades en el eje Y. Por simplicidad en la posición final solo se muestra el vector asociado al vértice V2. Ahora viene lo interesante. Si unimos el punto origen y destino de V2 obtenemos un vector cuyas componentes son 3,-6 y 0. En el dibujo ese vector se muestra en color rojo. En términos físicos. El vector rojo indica la distancia y el vector de la posición final el desplazamiento. Es una simple suma vectorial. Sin embargo también es posible hacer una resta vectorial para calcular ese vector rojo. Digamos que queremos mover una imagen a un punto determinado. Basta una resta vectorial (destino menos origen) y luego sumamos las componentes del vector a todos los vértices. Bueno, creo que ya estoy complicando algo que de por si era muy simple.
Para los que ya tienen algo de práctica haciendo juegos, con la información dada hasta ahora ya deberían ser capaces de hacer una sencilla animación de movimiento de esa nave triangular. Solo tendrían que hacer un ciclo donde en cada iteración trasladaran los vértices un poco. Pero la simple traslación no es muy impresionante. Mas adelante veremos como rotar la nave y hacer que cambie de tamaño. Cuando terminemos las transformaciones geométricas básicas veremos como mecanizar los cálculos usando matrices y luego ya verán que vamos a poder hacer algo en papel que hasta ahora muchos creían que solo era posible usando poderosas computadoras. Ya verán que serán capaces de entender el funcionamiento del 3D antes de lo que se imaginan. Y sin tener que gastar cientos de miles de dólares en alguna de esas escuelas de desarrollo de videojuegos que comienzan a proliferar en Mexico como hongos del Mario Bros. Muchas de las cuales invito a usar mis escritos para apoyar sus clases porque a como conozco a muchos profesionales de “la industria” que dan clases en esos lugares (especialmente los de las materias de programación), no dudo que van a necesitar esta y toda la ayuda que puedan obtener.
Programación Gráfica y la Rotación de Objetos
Un Programador de Videojuegos no le teme a las Matemáticas
La rotación es la marca que identifica a las verdaderas gráficas vectoriales y que las distingue de los humildes sprites. En la época de los 8 bits cuando las multiplicaciones eran demasiado tardadas cuando no imposibles de hacer los juegos simulaban rotaciones por medio de animaciones cíclicas de sprites. Mas tarde cuando la multiplicación de enteros estuvo disponible en las consolas fue posible rotar y escalar sprites con una técnica llamada matemáticas de punto fijo. No fue sino hasta la época en la que se implemento el procesamiento de punto flotante que las computadoras pudieron hacer auténticos cálculos trigonométricos que las rotaciones no se vieron realistas. En esta entrada se va a ver todo lo que un interesado en la programación gráfica debe de saber para implementar rotaciones vectoriales.

En la primera imagen se muestra una entidad metemática muy especial conocida como el Círculo Unitario. Se trata de un círculo con centro en el origen y un radio de una unidad. El radio como ya han de saber es la distancia del centro del círculo a cualquier parte de este y se mantiene constante. Supongo que todos ustedes ya saben todo esto así que pasaré a lo siguiente. Si examinamos el círculo veremos una flecha negra inclinada. Esa flecha es un vector cuya longitud es una unidad, y proyecta sombras en los ejes coordenados (en rojo) esa sombras son las componentes del vector radio o como vimos en la entrada anterior los pasos que hay que dar a partir del origen en dirección de cada uno de los ejes para alcanzar la punta del vector. O explicado con abejitas y flores, el vector radio es hijo del vector X y el vector Y en las proporciones que indican las sombras.
Pero aún hay mas, si tomamos el radio y las sombras que este proyecta en los ejes coordenados podemos formar un triángulo. Para ser exactos un triángulo rectángulo. El símbolo redondo partido por la mitad que recuerda al logotipo de una marca de autos japoneses significa para nosotros ángulo. El ángulo va desde el eje horizontal X hasta el vector radio siempre en sentido contrario a las manecillas del reloj. Este ángulo se mide en radianes y no en grados. Finalmente, las sombras o componentes vectoriales que conforman el lado horizontal y vertical del rectángulo pueden tomar cualquier valor entre -1 y 1 dependiendo del lugar hacia donde apunte el vector radio. Estos dos lados son conocidos en matemáticas como Seno y Coseno.
Hay otra cosa interesante relacionada con el vector radio y las funciones Seno y Coseno. Como ya dije, estos 3 elementos forman un triángulo rectángulo donde, si tomamos como referencia el vértice o esquina donde se encuentra el ángulo (el del simbolo que parece marca japonesa de automóviles). Para los que no recuerdan el teorema de pitágoras es el que dice que el cuadrado de la hipotenusa es igual a la suma del cuadrado de los dos catetos. La hipotenusa es el lado inclinado que es también el mas largo. Los catetos son los lados cortos horizontales y verticales. El cateto adyacente es el que está pegado al ángulo que estamos midiendo y el cateto opuesto es el que le queda de frente. En un círculo unitario la hipotenusa es también el vector radio, el cateto adjacente es el Coseno del angulo y componente X del vector. Mientras que el cateto opuesto es el Seno del ángulo y componente Y del vector radio. Sencillo.
El cateto adyacente es el Coseno, el cateto opuesto es el Seno y la hipotenusa es el propio vector que siempre va a medir una unidad en el círculo unitario. De este modo, siguiendo el viejo y muy conocido teorema de Pitágoras podemos obtener algo llamado identidad trigonométrica fundamental que dice que si elevamos al cuadrado el Seno y el Coseno de un ángulo cualquiera y luego los sumamos el resultado siempre va a ser igual a 1. Eso en notación matemática nos da (Sen(x))^2 + (Cos(x))^2 = 1. Por cierto, el viejo teorema de Pitágoras es muy importante en programación gráfica y juegos 3D en general, pues se usa mucho para medir distancias y hacer cálculos de iluminación.
Aquí es donde vamos a usar la GPU de mano que es nuestra calculadora de bolsillo y vamos a buscar unos botones marcados como SIN y COS. Nos aseguramos de que la calculadora esté ajustada en radianes y nos ponemos a enviarle a estas funciones los números que queramos. El resultado siempra va a estar entre -1 y 1. Esto es porque seno y coseno son las componentes del vector radio de un círculo unitario y estas se mueven de -1 a 1 conforme la flecha apunta a cualquier parte del círculo como si fuera un reloj. El ángulo en radianes nos indica hacia donde la flecha negra se encuentra apuntando. Ahora vamos a ver que demonios es un radian.
Pizzas y Radianes
El radian se usa para medir el arco de las circunferencias. En lugar de usar expresiones como ‘medio círculo’ en matemáticas usamos el radián. Un radián es la longitud de arco que mide lo mismo que el radio del círculo. Si recuerdan sus clases básicas de geometría recordarán que había un número llamado Pi que era mas o menos 3.1416. Ese número es la proporción entre el diámetro y la longitud del perímetro del círculo. Y como el diámetro mide el doble del radio, necesitamos 2*Pi o mas o menos 6.1832 radianes para igualar la circunferencia total del círculo. Para entender mejor el valor de los radianes voy a mostrar una interesante propiedad a la que llamo la propiedad de la rebanada de pizza y que se muestra en la imagen junto a este párrafo.
La propiedad de la rebanada de pizza dice que si tenemos una pizza de radio R y le cortamos una rebanada tan amplia como ese mismo radio R, el área total de esa rebanada de pizza será igual a la de la mitad de una pizza cuadrada de lado R
Lo anterior se demuestra en la segunda imagen. El área de un círculo de radio R es Pi multiplicado por el cuadrado del radio o Pi*R^2 y el perímetro es el doble del radio multiplicado por Pi o 2*Pi*R. Si ambas expresiones las dividimos simultaneamente por 2*Pi obtenemos la extensión del arco de longitud R y el area de la rebanada de pizza cuyo lado redondo es tan largo como R. Obtenemos un perímetro de R y un área de (1/2)(R^2). En fin, toda esta explicación es solo para demostrar la importancia que tienen los radianes como medida de los ángulos a la hora de hacer rotaciones. También sirven para cuando trabajamos con arcos o círculos incompletos.
Y hablando de arcos incompletos. Como la medida de un radian es muy poco intuitiva para los seres humanos. A la hora de trabajar con ellos siempre se manejan en múltiplos de Pi. La proporción mas importante es la siguiente: 3.1416 radianes equivalen a medio círculo. O mas exacto Pi*radian = 1/2 circulo. A partir de esta proporción se obtienen todas las demás medidas intuitivas de la circunferencia:
| 2*Pi*r | Círculo Completo |
| Pi*r | Medio Círculo |
| (1/2)*Pi*r | Cuarto de Círculo |
| (1/4)*Pi*r | Octavo de Círculo |
Otro consejo: Como tanto Pi como relación del radian con la circunferencia no son lo que se dice muy amistosos. Lo que la gente hace es manejar una unidad híbrida conocida en el bajo mundo como el PiRadian. Un PiRadian como ya se dijo equivale a medio círculo. Sin necesidad de usar decimales raros.
Fórmulas de Rotación Vectorial
Bueno, ya le di muchas vueltas al asunto y no hemos visto nada de rotaciones. Supongamos que queremos hacer una función que reciba como entrada un vector y un ángulo en radianes. Digamos que queremos rotar el vector R un cuarto de vuelta. En radianes un cuarto de vuelta es Pi/2 o aproximadamente 1.5708. Las fórmulas para hacer esta rotación se muestran en la última imagen de la entrada. El error mas común en las rotaciones es sobreescribir los mismos valores a la mitad del cálculo. Para evitar esto los valores iniciales del vector se guardan como ‘valores viejos’ y a partir de ellos se calculan los valores nuevos. Una vez hecho el cálculo pueden desecharse los valores viejos o ser sobreescritos.

En cuanto al origen de las fórmulas, podría explicarles de donde salieron pero esto sería muy largo y tedioso. Si son tan nerds como para querer saberlo vayan y busquen en su libro de trigonometría de la escuela. Pueden encontrar estas fórmulas y su explicación mas profunda en el tema de suma de ángulos y sus propiedades trigonométricas. Por cierto, estas rotaciones son siempre respecto a un plano perpendicular a los ejes coordenados tridimensionales. Piensen en el piso y las paredes de su cuarto. Es posible hacer que un objeto rote respecto a cualquier eje en el espacio por medio de otras fórmulas que comentaré en el futuro. Proceso que puede aplicarse por ejemplo en un cañon que le apunta al jugador mientras este se mueve por el campo de batalla.
Tablas Precalculadas y Grados de 8 Bits
Ahora que saben como se rotan vectores dado un ángulo en radianes es hora de que les revele un par de optimizaciones. La primera es la de usar grados de 8 bits. Todo el mundo acostumbra dividir una circunferencia en 360 grados. Pero si nosotros la dividimos en 256 grados podemos obtener muchas ventajas. La mas obvia sería usar máscaras de bits para hacer medias vueltas, o cuartos de vueltas o mantener girando un objeto incrementando indefinidamente el indicador de grados de 8 bits y combinando este valor con una máscara AND. Para obtener grados de 8 bits dividimos la circunferencia que mide 2*Pi entre 256, o lo que es lo mismo Pi/128 que nos da un total aproximado de 0.02454 radianes por grado de 8 bits.
La segunda optimización depende directamente de la anterior. Si dividimos la circunferencia en 256 partes podemos calcular una sola vez el valor del Seno y el Coseno de cada uno de esos 256 grados de 8 bits una única vez al inicializar el programa y guardar los resultados en 2 arrays de punto flotante. De ese modo cuando queramos obtener el seno y el coseno de un grado determinado solo usaríamos ese número como índice del array y convertiríamos un cálculo trigonométrico en una sencilla multiplicación. Digamos por ejemplo que queremos rotar un vector un cuarto de vuelta. En el sistema de grados de 8 bits un cuarto de vuelta sería 32. Tomamos el valor en la posición 32 de las tablas y los usamos en las fórmulas de rotación de la última imagen. Esto también sirve para evitar las operaciones de stack en una FPU de Intel. Solo habría que cargar las componentes vectoriales a la FPU y pasarle la posición de memoria de la tabla precalculada, multiplicar y escribir el resultado en la memoria.
En fin, luego de toda esta explicación pueden haber sucedido dos cosas, una es que decidieran renunciar a la programación gráfica por miedo a las matemáticas y otra es que hayan puesto cara del ‘MeGusta’. En la siguiente entrada vamos a ver como se aplican la traslación, rotación y escala de vectores para animar modelos vectoriales en el espacio tridimensional. Recuerden que hasta ahora no hemos tenido necesidad de otra cosa aparte de libreta de cuadrícula, lápiz con borrador y una calculadora escolar
Programación Gráfica y el Espacio 3D
–Puntos y Vectores en un mundo tridimensional–
Esta entrada es la continuación de la nota donde trato de explicar conceptos básicos de las gráficas por computadora usando solo lapiz, papel y calculadora. Ya hemos visto lo que es un sistema de coordenadas y somos capaces de definir puntos en el espacio. Conocemos los cálculos para convertir puntos entre el sistema de coordenadas de dispositivo, en este caso una hoja de libreta. Antes de entrar con las transformaciones geométricas voy a ponerme a hablar de este espacio en el que existe todo nuestro mundo en 3D.

En la foto se muestran los vectores que forman el espacio tridimensional. Podemos ubicar cualquier punto en el espacio de manera única usando 3 números. Cada uno de estos números nos indican cuantos pasos debemos de dar en la dirección que nos indican las flechas x,y,z. El punto en donde se cruzan las tres flechas se llama Origen y para llegar a él no hay que dar ningún paso en ninguna dirección, por lo que le corresponde el punto (0, 0, 0). Si ustedes construyen una figura como esta pueden ubicar cualquier cosa con una tercia de números. Estas flechitas pueden definir universos enteros pero de momento vamos a quedarnos con nuestra libreta de cuadrícula, lápices y calculadora. Y para ello vamos a reducir esa figura de plastilina a la representación en papel que se ve en la segunda imagen. Ahora veamos lo que es un vector.
Explicar un vector no es nada facil sin recurrir al lenguaje de “sea/tal que/entonces” que viene en todos esos libros de cálculo que tanto aburren a los estudiantes de artes digitales. Para fines prácticos, un vector es una secuencia de números en la memoria de la computadora y en el espacio 3D un vector es una flecha que parte del Origen y que llega a un punto en el espacio. A nivel computadora no hay diferencia entre un punto y un vector y para los cálculos geométricos un punto es representado por el vector que llega hasta él desde el origen. De hecho los componentes de un vector que llega hasta el punto coinciden con las coordenadas del mismo. Piensen en un perro que muerde el punto pero que a la vez está encadenado en el origen. Aunque hay mas cosas interesantes sobre los vectores que iré contándoles cuando sea necesario.
Por cierto, en la nota anterior hice un comentario sobre como figuras como la de la primera foto eran capaces de definir universos enteros. Esto es llamado espacio vectorial y combinaciones lineales. Para que todos me entiendan lo voy a explicar con abejitas y flores. Resulta que los vectores son capaces de tener hijos. En la segunda foto se muestra un vector (la flecha roja) que es una combinación lineal del vector ‘x’ y el vector ‘y’ (las flechas negras). El vector X mide una unidad y sus componentes son 1,0,0 y el vector Y aunque también mide una unidad sus componentes son 0, 1, 0. Las componentes del vector V son 0.75, 0.5, 0. Esas componentes significan que tenemos que multiplicar el vector X por 0.75, el vector Y por 0.5 y el vector Z por 0. Lo que deben de recordar es que aún estos vectores pueden seguir reproduciéndose infinidad de veces. Recuerden esto cuando quieran hacer cámaras múltiples para ver la acción de diferentes puntos de vista.

Los Vectores pueden crear no solo otros vectores, también espacios completos
Algunas otras cosas que deben de recordar sobre los puntos y vectores es que los puntos carecen de dimensiones. Son infinitamente pequeños y carecen de longitud, altura o profundidad. Los vectores son flechas que comienzan en el origen y que terminan o se clavan en un punto del espacio. Un punto se define como el vector que llega hasta él desde el origen. Los espacios pueden ser definidos por un conjunto de estas flechas o vectores. Estos vectores pueden reproducirse y crear nuevos y lo mas importante. Un vector puede ser siempre definido en términos de otros vectores. Por cierto, los vectores aunque tienen magnitud (puede medirse su longitud) carecen de grosor. Son como lineas infinitamente delgadas.
Lo que muchos ya se estarán preguntando es que tiene que ver todo esto con los videojuegos 3D. La respuesta es que estos puntos y vectores se utilizan para definir todos los objetos del juego. Los puntos en el espacio, (o las cabezas de los vectores) en modelado 3D se llaman vértices. Si se unen dos vértices con una linea recta obtenemos una arista. Y si unimos 3 vértices por medio de lineas obtenémos un triángulo plano o cara. Con estos triángulos planos es como se forman todos los objetos 3D de los videojuegos. A mayor cantidad de triángulos mas suaves van a lucir las superficies. Aunque aplicando ciertos algoritmos de iluminación y detalle de superficie puede hacerse pasar una cara plana como si tuviera la textura irregular de una roca o incluso lucir como si tuviera relieve. Estas construcciones pueden ser manipuladas mediante operaciones de transformación geométrica como la traslación que mueve las cosas de un lado a otro, la rotación que hace que giren en torno a un punto determinado y la escala, que las hace cambiar de tamaño. A estas transformaciones a veces se les llama de cuerpo rígido porque alteran una figura sin cambiar la posición en que los vértices se encuentran unos respecto a otros. Y esas transformaciones no solo se usan para mover a los personajes en el campo de batalla sino que también se usan para la vista individual de cada jugador en una partida multiplayer.
Antes de terminar quiero dejar claro una cosa, no existe un solo espacio sino muchos. Cada espacio cuenta con su propio sistema de coordenadas y es importante saber como convertir puntos de un sistema a otro de la manera mas rápida que sea posible. Los sistemas de coordenadas mas importantes son 3 a saber: El sistema de Coordenadas Mundiales que es donde el mundo del juego se desarrolla. El sistema de Coordenadas de Modelado que se usa para construir los personajes del juego (cada objeto tiene su propio sistema de coordenadas) y por último las Coordenadas de Vista. De momento vamos a trabajar de modo tal que estos 3 sistemas de coordenadas coincidan. Mas adelante veremos como separarlos y trabajar con cada uno de manera individual.
Saben, me siento como un estúpido hablando de estas cosas en internet. Solo lo hago porque se que en algún lugar hay alguien que sabe que para hacer videojuegos no basta con estar titulado de lo que sea o tener contactos con gente importante. O que por mucho dinero que le puedan sacar al gobierno nunca van a poder conseguir que esas consolas se programen solas. Se bien que ahí afuera hay alguien queriendo hacer su propio game engine o por lo menos poder usar uno con pleno conocimiento de lo que están haciendo. Y aunque esta información fue pensada en un inicio para los programadores se que los grafistas mas principiantes les vendrá bien saber lo que son los vectores y como estos son independientes de los pixeles.
Por cierto, hace muy poco me volvieron a preguntar que porqué no he fundado mi propia empresa de videojuegos. No es la primera vez que me lo preguntan. Solo digamos que he aprendido de errores ajenos y prefiero no exhibirme mas de lo necesario. Solo puedo decir que cuando eso suceda, primero van a jugar el juego, luego van a querer investigar quien lo hizo y solo entonces sabrán si he logrado fundar una empresa de juegos o no. Puede que algunos disfruten del juego sin que ni siquiera les importe quién lo hizo. Pero prefiero mil veces, si es que un dia hago un buen videojuego (yo solo o con un equipo respaldándome) este vaya por delante mio y no que un juego que sea un fracaso comercial me lleve por delante a mi. Es por eso que no me gusta exhibirme sin un producto de calidad en mis manos. Pero hasta que ese día llegue, seguiré siendo una sombra mas en el internet. Una sombra que comparte con ustedes sus modestos (o debería decir molestos) conocimientos de Programación en Lenguaje Ensamblador.
Programación Gráfica para Principiantes
–Solo necesitan papel, lapiz y calculadora–
“Programación Gráfica” Dos palabras que en el pasado hicieron que muchos dedicaran su vida a las computadoras y hoy se han convertido en una especie de creencia malentendida entre muchos desarrolladores aficionados. En las comunidades de desarrollo de videojuegos, la tercera cosa que mas me hace enojar despues del esnobismo y el abuso del outsourcing es esa idea de que programación gráfica es aprenderse todas las funciones de una API o hacer scripts para un engine. En esta entrada voy a concentrarmé en las gráficas mas que en la programación. Tanto así que van a ver que es posible aprender sobre gráficas sin necesidad de una computadora.

Seguro pensarán que es algo imposible. Pero en la imagen que acompaña esta entrada pueden ver todo lo que necesitamos. Así como una descripción de su equivalente dentro de una computadora. Para los que no reconocen estos objetos les diré para que es cada uno:
Libreta de cuadrícula: Puede ser de cuadro de 5 o 7 milímetros. Estas hojas cuadriculadas es lo único que necesitamos para simular la manera en que se comporta un monitor de computadora así como sus registros y memoria interna. Existe un tipo de hoja conocida como cuadro alemán cuyos cuadros son aún mas grandes y que es particularmente util para aprender sobre estructuras de datos en una memoria de computadora. Pues cada cuadro es lo suficientemente grande para escribir un byte con 2 cifras hexadecimales.
Lapiz y borrador: Es importante que el lapiz sea facil de borrar y que la goma no maltrate demasiado el papel, pues va a ser necesario escribir y borrar varias veces los mismos trazos y números. Así como hacer algunos cálculos manuales.
Calculadora: Esta va a ser nuestra unidad de procesamiento gráfico. No es necesario que sea una calculadora muy poderosa aunque algunos modelos capaces de trabajar con sistemas de matrices puede acelerar muchísimo este trabajo. Por cierto, la calculadora electrónica mas sencilla que puedan encontrarse trabaja de manera muy similar a nivel abstracto a una unidad de punto flotante básica con la que vienen equipados de fábrica los procesadores de Intel.
Y eso es todo, no necesitamos mas poder computacional que una modesta calculadora escolar, un cuaderno de cuadrícula y lápices. Con esto podemos comenzar a estudiar lo que son las gráficas por computadora desde cero. Lo primero que haremos será tomar una hoja y dibujar un cuadro lo mas grande que sea posible y que mida la misma cantidad de cuadritos de ancho que de altura. Es importante basarnos en la cuadrícula de la hoja en todo momento. Una vez que tengamos el cuadro estaremos listos para aprender el primer concepto de las gráficas por computadora: Sistemas de coordenadas.
Sistemas de Coordenadas
Coordenadas Físicas: El primer sistema de coordenadas que debemos conoces es el sistema de coordenadas físicas. Para los que no saben matemáticas básicas y desconocen el concepto de coordenadas. Estas son una secuencia de números que indican un punto en el espacio de manera única. En el caso de nuestra hoja se trata de un espacio plano de dos dimensiones. Una dimensión es la horizontal y otra la vertical. Podemos obtener la posición de cualquier punto a partir de un par de números de manera única. No va a haber otro punto al que correspondan esos mismos dos números (en ese orden) ni ese mismo punto. Ese par de números nos indican la cantidad de pasos para llegar a un punto. La pregunta es de donde comenzamos a contar los pasos y en que dirección.

Como estamos trabajando en coordenadas físicas y la hoja trata de imitar el monitor de una computadora. El punto del que se comienzan a contar los pasos y que es conocido como Origen se va a ubicar en la esquina superior izquierda. El lado superior e izquierdo de ese cuadro serán nuestros ejes del sistema de coordenadas físicas. El primero es el eje horizontal que crece a la derecha y el otro el vertical que crece hacia abajo siendo (0,0) el punto superior izquierdo del cuadro. Ya se que así no es como se manejan los verdaderos sistemas de coordenadas pero esto es lo mas parecido a como trabajan los monitores de las computadoras.
Como ubicar puntos individuales. Contrario a lo que casi todos ustedes están pensando. Los cuadros que componen la cuadrícula de la hoja no representan los pixeles. En realidad los sitios en donde se cruzan las lineas que forman la cuadrícula representan los centros de los pixeles. Esto tiene un porqué. A nivel matemático los puntos en el espacio no solo carecen de dimensión sino que son infinitamente pequeños. Mientras que los pixeles son cuadros bidimensionales con ancho y altura perfectamente medibles. En gráficas por computadora se trabaja con lo que los matemáticos llaman Números Reales, y se aproximan por medio del formato de Punto Flotante. Pero no se preocupen, voy a tratar de explicar estos temas de manera que cualquier estudiante de educación pública básica pueda entenderme.
Digamos que el cuadro que dibujamos mide 20 por 20 cuadros. El punto de arriba a la izquierda que corresponde con el origen (0,0). Significa que partiendo de ahí damos 0 pasos a la derecha y cero hacia abajo. Recuerden que los puntos son las intersecciones de las lineas de la cuadrícula y no el interior de los cuadros. El punto mas lejano del origen seria la esquina inferior derecha a las que corresponderian las coordenadas (20, 20). Jueguen un rato a ubicar puntos por sus coordenadas y a obtener las coordenadas de puntos dentro de esa ‘pantalla’
Si les interesa esto de la programación probablemente se han preguntado como le hacen los juegos 3D para poder desplegar el mismo juego en diferentes resoluciones y tipos de pantalla. La respuesta son las coordenadas lógicas normalizadas. En matemáticas se llama normalizar a poner una cantidad en un rango entre cero y uno (no es la definición oficial pero con eso nos basta) Esto tiene aplicaciones muy interesantes como en este caso el poder manejar imágenes que no cambien de tamaño cuando hagamos un cambio de resolución. Las coordenadas lógicas de dispositivo son el primer nivel de abstracción en las gráficas vectoriales. En este sistema el origen sigue estando en (0,0) pero el punto mas alejado es (1,1). Aunque técnicamente es (0.9999999,0.9999999) quedando todos los demás puntos en un rango de cero a uno. De este modo el centro de la pantalla corresponderá siempre con el punto (0.5,0.5) sin importar que resolución en pixeles manejemos.
Como ya se habrán dado cuenta para cambiar de un sistema a otro es necesario hacer una serie de cálculos. Para convertir las coordenadas físicas a coordenadas lógicas dividimos las coordenadas del punto (x,y) por el valor máximo que las ‘x’ y las ‘y’ puedan tomar. Por ejemplo si estamos trabajando con una cuadrícula de 10 por 10 y queremos convertir el punto físico (5,5) basta con dividir entre 10 y obtener (5/10, 5/10) que es igual a (0.5, 0.5). Para convertir de coordenadas lógicas a físicas hacemos el proceso inverso y multiplicamos de modo que (0.5 * 10, 0.5 * 10) es igual a (5, 5). Experimenten con cuadrados de diferentes tamaños y verán como los puntos siempre se mantienen en las mismas posiciones unos respecto a otros sin importar el tamaño del cuadro.
Sistema de Coordenadas Mundiales

Si ustedes pertenecen a esa rama de los otakus que se interesa por programar videojuegos lo mas probables es que no se hayan percatado que algo no está bien en el sistema de coordenadas que acabo de describirles. Y es que por tradición los sistemas coordenados usados en matemáticas tienen su origen en el centro y el eje vertical (conocido como el eje ‘y’) crece hacia arriba y no hacia abajo. Para que me entiendan, un verdadero sistema de coordenadas se parece al dibujo de cabellos cruzados con el que cuentan las miras de los rifles sniper en cualquier FPS. En otra entrada voy a hablar de lo importante que es esto pero por ahora solo tienen que saber que necesitamos de este sistema para que los cálculos nos funcionen. Para convertir coordenadas lógicas de dispositivo a este sistema es necesario primero restar 0.5 a x y para que el origen quede en el centro del area de trabajo. Para voltear el eje ‘y’ basta con multiplicarlo por -1. De nuevo, para convertir a coordenadas de dispositivo a la x se le suma 0.5 y a la ‘y’ primero se multiplica por -1 y a ese resultado se le suma 0.5. En una entrada posterior se van a repasar estas sencillas fórmulas.
Por cierto, aunque estamos trabajando con una hoja de papel plano en realidad hemos definido un espacio de 3 dimensiones. El eje Z es perpendicular a la hoja y crece a medida que los puntos se alejan de ella. Todos los puntos pueden tomarse como que su coordenada Z es igual a cero.
Si todo va bien voy a seguir con estas notas. Como dije alguna vez, tan solo escribo aquello que me hubiera gustado encontrar cuando comenzaba a programar y para que la gente le tenga respeto a las computadoras. Como esta entrada ya quedó muy extensa voy a dejar para la siguiente los temas de los sistemas de coordenadas. Y para los newbies que creen que no necesitan nada de esto porque tienen acceso al unreal engine (o Unity si es que no les alcanza) créanme que tener esta base teórica les va a resultar de mucha utilidad para al menos saber que es lo que hacen esos scripts que copian y pegan de los foros de desarrollo.

