28 – Como hacer una blob animado en HTML - Parte II
Esta es la parte II de nuestro tutorial para dibujar un blob como el de compilersforhumans.com
Si te perdiste la primera parte haz clic aquí
En esta parte veremos como dibujar un pequeño anillo 3D proyectado en una plano 2D. Veremos un poco de matemáticas, y expandiremos un poco más nuestros conocimientos de Canvas API.
Dibujando un punto 2D
Primero, dibujaremos un punto 2D en el canvas, pero esta vez usando un objeto y ya no coordenadas al azar. Vamos a tomar como referencia un plano cartesiano. Los puntos entonces no van a ser más que un conjunto de coordenadas en X, Y.
Creemos un punto, en la coordenadas (10,10)
|
|
Como podemos ver, este punto va a tener el valor en X: 0 y en Y: 0;
Ahora a dibujarlo. Ya que un punto no tiene ni color ni radio de por si usaremos un radio de 5, y el color red
.
Usaremos el boilerplate code
que vimos en la parte 1, y añadiremos el punto que acabamos de crear.
|
|
Dibujando un punto 3D.
Ahora dibujaremos un punto en 3D. Primero, tenemos que dejar en claro algo, en nuestro Canvas solo podemos especificar dos coordenadas: X e Y. Para poder representar un punto en 3D necesitamos hacer lo que se conoce como una proyección
. En específico usaremos una proyección proporcional, que es basicamente como perciben las cámaras de nuestros celulares las figuras 3D de nuestro mundo.
Veamos como funciona, la cámara ubicada a la izquierda asumimos que tiene un campo de visión fov
de ~180 grados. Es decir que puede ver todo lo que esta en frente. El sujeto, está a la derecha, en este caso una manzana se encuentra a una distancia de la camara. Por último, el plano, se encuentra entre la cámara y el sujeto de modo que en el plano se proyecta el sujeto.
La matemática para convertir el sujeto 3D en el plano es algo trivial, solo se necesita un poco de conocimientos de trigonometría. Si no te interesa la matemática en específico puedes saltarte al parrafo que empieza con ‘Veamos la formula en javascript’.
Simplifiquemos nuestro diagrama a solo 2 puntos.
Vemos que se forma un triangulo rectángulo. Al ser un triangulo rectangulo podemos usar las identidades trigonométricas que aprendimos en el colegio: SOHCAHTOA. Es decir Seno (Opuesto sobre Hipotenusa), Coseno (Adyacente sobre Hipotenusa) y Tangente (Opuesto sobre Adyacente). Para nuestro ángulo Theta, podemos ver que el lado Adyacente es D, y el lado Opuesto es X’. Para el segundo triangulo, el más grande. Nuestro lado adyacente sería la suma de D y Z. Mientras que nuestro lado Opuesto es X.
Pásandolo a nuestras identidades trigonométricas, podemos crear la siguiente equivalencia usando la tangente.
tan(theta) = Opuesto/Adyacente
tan(theta) = X'/D // 1
tan(theta) = X/(ZC-Z) // 2
Como vemos, podemos igualar 1 y 2, para formar 3.
X'/D = X/(ZC-Z) // 3
Usando un poco de algebra podemos despejar X'.
X' = (D*X)/(ZC-Z) // 4
Listo, ahora tenemos la fórmula para pasar un punto (X,Z) a un punto (X’,Z’) a un plano ubicado a una distancia D de una Cámara, ubicada en ZC. A su vez, podemos pasar las coordenadas (Y, Z) usando la misma formula, a un punto en (Y’, Z’).
Veamos la fórmula en Javascript:
|
|
D
lo escribimos como distance
, XY
vendria ser X
o Y
(dependiendo lo que le insertemos a la función), z
, el punto en z
y z_camera
la distancia del origen a la cámara.
Ahora sí, declaremos nuestro punto 3D y dibujemoslo en el plano:
|
|
Primero, declaramos una distancia fija y la posición de la cámara. Luego, pasamos el punto 3D a una proyección en 2D.
Ahora a dibujamos el punto en 2d como siempre lo hemos hecho, pero empezando a contar desde la mitad del canvas (para eso el w/2
y h/2
)
|
|
Resultado:
Un pequeño puntito rojo en medio del canvas. No parece mucho, ni siquiera se nota la proyección quizás. Pero está ahi. Ahora que haremos el anillo se notará mucho más.
Esta sección fue un poco densa, pero ahora ya podemos hacer un anillo en 3D en nuestro canvas 2D.
Dibujando un anillo
Primero, veamos un pequeño sketch de lo que queremos hacer:
Como ven es un círculo visto de 3/4 de la horizontal. Digamos que queremos que nuestro circunferencia va a tener 25 puntos alrededor, y que tenga un radio de 10u (10 unidades).
Esta vez, para guardar los puntos vamos a usar un arreglo o “lista” de puntos.
|
|
Estos puntos tendrán logicamente 3 coordenadas. Para crear los puntos haremos un pequeño for-loop
(bucle) que ejecutara el código 25 veces (la cantidad de puntos que queremos). Como queremos que los puntos equidistantes vamos a dividir el largo total de la circunferencia en 25 partes iguales y poner un punto en ese lugar.
|
|
Finalmente, tendremos que rotar en el eje X nuestros puntos para poder ver nuestra circunferencia correctamente.
Esto desplazará en amount
(expresado en radianes), nuestro círculo. Para conveniencia nuestra, crearemos una función que convierte grados sexagesimales a radianes.
|
|
Una vez que tenemos los puntos, dibujémoslos. Para simplificar el proceso de dibujo crearemos una funcion de ayuda llamada draw_point(point, color='red', radius='5');
|
|
Por último, veremos como usaremos esta función:
|
|
Integrando todo, obtenemos lo siguiente:
|
|
Y el resultado, una bella circunferencia ligeramente rotada: Los puntos más cercanos se ven más juntos dada su proximidad. Y los puntos más alejados se separan ligeramente debido a que estan más lejos de la cámara.
Por ultimo cambiemos la variable points_in_circle
a un valor mayor, como 100 y veamos el resultado:
🥳 Excelente, podemos ver ahora claramente nuestra circunferencia.
Este post ha sido algo extenso, pero espero que hayan aprendido varias cosas, solo les recomiendo que jueguen con las variables, aprendan que hace cada una de ellas, entiendan el código, y si pueden las matemáticas que hemos usado.
En la siguiente parte (Parte III) veremos como construir la esfera completa basándonos en este circunferencia, y como rotarla.