Un motor 3D es un programa que nos permite movernos a través de un mundo 3D visualizando objetos 3D en una pantalla 2D, a través de una serie de algoritmos complejos que utilizan la información almacenada en estructuras de datos creadas para este fin.
Podemos realizar un programa que imprima objetos 3D en la pantalla, pero implementar un motor que nos permita movernos dentro de un mundo tridimensional puede ser una tarea realmente compleja. Intentaré, a través de una serie de posts, explicar algunos principios básicos para la implementación de un motor 3D sencillo.
La tarea de crear nuestro mundo 3D contiene dos grandes desafíos:
- La modelación de los objetos en estructuras de datos adecuadas
- La representación de estas estructuras en nuestra pantalla 2D
Las Estructuras de Datos
Para poder crear un mundo 2D en una computadora quizás la utilización de archivos de imagenes, animaciones o dibujado de estructuras geométricas pueda bastarnos; pero, ¿cómo representar en nuestra computadora un objeto tridimensional, el cual tiene infinidad de puntos de vista, acercamientos, movimientos, etc? Almacenar cada pixel del objeto no sería práctico ni nos daría una representación muy real a la hora de mover el objeto a través del mundo virtual.
La mejor forma de modelar los objetos es a través de polígonos. Gran parte de los motores 3D utilizados en los juegos y aplicaciones modernas utilizan polígonos para modelar casi cualquier objeto en su mundo 3D. Y quizás el polígono más utilizado es el triángulo, a partir de triángulos podemos representar cualquier polígono, incluso círculos y esferas.
![]() |
Para poder modelar cada uno de los triángulos que forman un objeto, solamente necesitamos almacenar las coordenadas de cada uno de sus tres vértices. Los vértices son los puntos principales sobre los que se basarán todos los cálculos de nuestro motor. Un vértice representa un punto en el espacio 3D y para modelarlo necesitamos almacenar su coordenada x, y, z. En C++, utilizaríamos una clase similar a esta:
class Vertex3D {
class Polygon3D {
int vertex[3];
class Object3D {
public:
Object3D();
int numVertex; //cantidad de vertices
Vertex3D *vertex; // Lista de vértices
Polygon3D *polygon; // Lista de Polygon3Ds
};
obj.numVertex = 8;
obj.vertex[1].x = 0.0; obj.vertex[1].y = 1.0; obj.vertex[1].z = 0.0;
obj.vertex[6].x = 1.0; obj.vertex[6].y = 1.0; obj.vertex[6].z = 1.0;
obj.vertex[7].x = 1.0; obj.vertex[7].y = 0.0; obj.vertex[7].z = 1.0;
Es importante siempre definir los vértices de los polígonos en el mismo sentido, ya sea en el orden de las agujas del reloj o en sentido contrario; pero todos los polígonos deben de ser definidos en el mismo sentido para así poder determinar cual es la cara frontal del polígono.
Como podemos ver, estas clases nos permitirán entonces (con algunos métodos añadidos y algunos otros atributos importantes), modelar cualquier objeto a través de polígonos y vértices. Diseñar un cubo es sencillo, pero ¿cómo modelaríamos un rostro humano o una nave espacial? A través de código sería imposible; esto lo hacemos a través de herramientas de diseño gráfico como 3dMax, Maya, etc. las cuales generan archivos que después podremos importar a nuestro motor para montar esta información en nuestras estructuras de datos; pero eso lo mostraremos más adelante.