Hace tiempo que quiero llegar el tema de los modelos 3D (de hecho desde que empezamos con WEBGL) ya que P5Js nos permite cargar modelos OBJ (objetos 3D).
Varios alumnos ya vieron en clase "WOW, hay miles de modelos online gratis", así que pueden descargar desde archivos OBJ desde mi sketchfab, free3d.com o Turbosquid.
Antes que nada, he preparado un archivo con varios objetos 3D e una subcarpeta llamada MODELOS.
Archivos OBJ
Antes que nada debemos explicar algo sobre que es un archivo .OBJ que es un antiguo formato de 3D de Alias WaveFront estándar de la industria para modelos de visualización y cine en los 90´s. El archivo contiene una lista de 3 números (posición en el eje X, Y , Z) en el espacio, y tal como hacíamos cuando éramos chicos, la computadora va conectando esos puntos en el espacio y creando los polígonos que establecen las superficies.
Parece simple, pero este "conectar con puntos" puede ser realizado con millones de polígonos por segundo por la computadora, ya que P5Js nos da la posibilidad de cargar el modelo simplemente llamándolo por el nombre.
Lowpoly
P5js está creado sobre Javascript o sea que su uso primario es la web, por ello se recomienda usar movelos de baja poligonización o LOWPOLY (mi sketchfab, free3d.com o Turbosquid) ya que una gran cantidad de polígonos podría sobrecargar la memoria y detener el script.
No tengo en claro CUANTOS polígonos son demasiados para P5Js, de hecho creo que depende de cuanta memoria de vídeo pueda manejar el navegador web , pero en el aula prefiero que usen modelos LOWPOLY (menores a 1000 polígonos) ya que la previsualización es más rápida.
En la imagen de abajo podemos ver como en 1996 juegos como Tomb Raider usaban 540 polígonos para su personajes, mientras que las consolas actuales poseen memoria para mucho más.
Nuevo Sketch.js
En el sketch que usamos ahora, tenemos creada una variable llamada OBJETO y otra IMAGEN1 e IMAGEN2, luego en el functionSetup usamos loadModel() para cargarle un modelo .obj o loadImage para cargar una imagen.
Nota: Recordemos que los tamaños de imagen para WEBGL deben ser múltiplos de 8, como 128x128 píxels, 256x256, 512x512, 1024x1024... etc.).
El function Draw sólo tiene un background(255) y nos da un fondo blanco, aunque podemos poner o para tener negro, o alguna combinación de rgb como hicimos en clases anteriores:
- background(255,0,0) es color rojo.
- background(255,255,0) es color amarillo.
- background(0,255,0) es color verde.
En la parte inferior está la detección de teclas direccionales (izquierda, derecha, arriba y abajo, como vimos en la clase 11) que permiten que el valor alojado en las variables x e y cambie de 40 en 40, de hecho le digo a los chicos que cambien ese valor por otro y que pueden usar ambas variables como deseen en algún translate o incluso rotateX, Y o Z.
Dibujando el Modelo
Como ya dije, en el functionDraw, es donde ocurre la magia, para eso debemos llamar la función model() especificando entre los paréntesis, en nuestro caso lavariable objeto que contiene el modelo (cargado en la línea 10).
En las líneas 18 y 19, ponemos los rotateX y rotateY para que podamos ver el modelo de distintos ángulos (como hicimos en clases anteriores).
Ahora aplicaremos con texture() la textura cargada en imagen1, el archivo OBJ carga un archivo secundario .mtl que le indica como mapearla sobre la superficie (el mtl lo genera el programa de 3D que exportó el modelo, es común que al bajar de internet archivos OBJ tegamos un mtl en la misma carpeta).
El punto CERO del modelo, o punto de origen de éste modelo está en la base de los pies, para "bajarlo" y poder tenerlo en el centro de la pantalla usamos un translate(0,-100,0).
Para éste nuevo ejemplo, cambié en la línea 10 el modelo por el poke3.obj y en la línea 11 la imagen por poke3.jpg.
Este modelo tiene un tamaño menor al anterior, por ello utiliza en la línea 21 el scale(2) que permite que sea del doble de tamaño (si deseamos que sea más pequeño podemos usar fracciones como 1/2, 1/3... o decimales como 0,5 para indicar la mitad).
Xwing
Para éste nuevo ejemplo, tenemos un xwing de starwars (este fué el primer modelo que hice hace 20 años en 3D studio r4) que cargamos con su textura en el functionSetup (en las líneas 10 y 11).
En las líneas 21 y 22, cargamos la imagen2 como textura de la esfera de tamaño 1000 (que servirá como fondo 3D).
Para éste ejemplo he comentado el translate() de la línea 26 ya que éste modelo fué creado con el origen en el centro.
El rotateX(PI/2*2) es rotar 180 grados el modelo, ya que por lo general lo archivos OBJ están boca abajo, y PI/2 es el equivalente en radianes a 90 grados.
Camaro
El camaro, es un modelo que sólo contiene la carrocería, y puse la rueda en otro modelo. Para cargar ambos debemos crear una segunda variable llamada rueda (línea 2), algunos chicos crearon múltiples variables para cargar todos los modelos. Luego la variable se carga con el modelo de la rueda en la línea 12.
En el function Draw () agregamos un translate (80,30,150) para mover el punto de origen al hueco de la carrocería y ponemos el modelo en ése lugar con model(rueda).
Repetimos la operación con otro translate, pero en éste caso, sólo queremos moverlo en un eje, por lo tanto dejamos los otros 2 valores en cero.
Para terminar, agregamos las 2 ruedas traseras, como se ve en la imagen, el valor amarillo mueve el punto de origen hacia atrás, y en el próximo translate() hacia el otro lado de la carrocería.
La idea de éstos ejercicios es que combinen las transformaciones para obtener diferentes resultados, y agregar los valores de x e y para alterarlas, por ejemplo en el translate(), los permite mover el objeto, si lo usamos en los rotateX/Y/Z podremos reorientar el modelo o bien cambiar la escala con scale().