lunes, 2 de marzo de 2026

Página 159, Parte 2: Apuntes de "Cómo entender los shaders en Godot"

Continuamos con otra tanda de shaders, centrada en dibujar formas básicas.
Veremos cómo crear un cuadrado, un cuadrado animado con rotación, un rombo, un rectángulo y, como extra, cómo añadir bordes gruesos al sprite para darle un estilo tipo Paper Mario.

Altamente recomendable haberse leído la entrada anterior 

Página 157, Parte 1: Apuntes de  "Cómo entender los shaders en Godot" 


 Ejercicio 6: Dibujando un cuadrado.

Cuando dibujábamos un círculo usábamos la función dist().
Para los cuadrados se emplea la fórmula max(abs(UV.x - center.x), abs(UV.y - center.y)), que en lugar de calcular una distancia radial, compara cuánto se aleja el píxel del centro en cada eje.
El valor más alto define el borde, lo que da como resultado la forma cuadrada.

Vamos a ir a mas por detalle de esta linea, la función abs elimina el signo "-" para trabajar de forma simétrica respecto al centro, y max se queda con el valor más alto de ambos ejes.

 

Sprite estirado para que se perciba mejor la forma

 Ejercicio 7: Dibujando un rectángulo.

Algo que veremos en los próximos dibujos es la línea vec2 p = UV - vec2(0.5, 0.5);.
Una forma que me ayudó a entenderla es pensar que estamos creando un “segundo dibujo”, cuyo centro está en (0.0, 0.0) en lugar de (0.5, 0.5).
A partir de esa variable decidimos si cada píxel se dibuja con el color original del sprite o con el del rectángulo.

El resultado de esta operación, nos dará la distancia con respecto al centro, hay que tener en cuenta que el tamaño que le pongamos en el rect_size, acabara siendo el doble.

 

 

Ejercicio 7: Dibujando un rombo.

En este apartado no sabía explicar de inmediato por qué sumamos d.x + d.y en
float diamond_dist = d.x + d.y;.

Tras investigar, descubrí que esta forma de medir corresponde a lo que se llama distancia Manhattan.
A diferencia de la distancia euclídea (como en un círculo), que mide la distancia en línea recta, la distancia Manhattan suma las distancias en cada eje.

Es muy útil para generar formas tipo rombo cuando trabajamos con coordenadas centradas. 

  

Ejercicio 8: El cuadrado giratorio.

Este ejercicio es muy similar al del cuadrado anterior, pero aquí centramos el sistema de coordenadas en (0.0, 0.0) mediante vec2 p = UV - center;.
Esto es importante porque, si no lo hacemos, la rotación se realizaría alrededor de la coordenada (0,0), que corresponde a la esquina superior izquierda del sprite, en lugar de hacerlo desde el centro. 

En este apartado se calcula la posición que debería ocupar cada píxel al aplicar una rotación de X grados.
Para ello se utiliza la fórmula clásica de rotación en el plano cartesiano, basada en seno y coseno.
En lugar de rotar el cuadrado directamente, rotamos las coordenadas del espacio, lo que hace que la forma se perciba como rotada sin complicar el cálculo.

 

Código completo. 

  

Ejercicio 9: Bordes en blanco en blanco.

Aquí aparecen conceptos nuevos. En la línea vec2 px = TEXTURE_PIXEL_SIZE * outline_size; convertimos un tamaño expresado en píxeles (outline_size) al espacio UV. De esta forma sabemos cuánto debemos desplazarnos en UV para muestrear píxeles vecinos.

En las siguientes líneas de código sumamos el canal alfa de los píxeles vecinos. Si la suma es mayor que cero, significa que alguno de los píxeles adyacentes es opaco, lo que indica que estamos cerca del borde del sprite.

 

 Código completo.

 

 

Antes de cerrar esta entrada, hago un pequeño resumen de las técnicas que hemos utilizado para crear las diferentes formas.


Parece que esas clases de matemáticas, en las que creías firmemente que nunca te iban a servir para nada, empiezan a asomarse por la esquina. Aquí son totalmente necesarias, ya que, a diferencia de GDScript, no puedes guardar información como un atajo: en un shader todo se calcula para decidir cómo se pinta cada píxel.

Tenía preparados varios scripts, pero no tenía del todo claro cómo funcionaban. En estas entradas quiero evitar copiar y pegar sin analizar, algo que ya me pasó siguiendo tutoriales como los de MakerTech. En su momento mostraba ejemplos sencillos que no llegué a entender del todo, pero al revisarlos ahora, con más contexto, encajan mucho mejor.

De hecho, incluso habría añadido referencias a discard, una instrucción que indica a la GPU que no pinte el píxel actual, algo que en su momento pasé completamente por alto.

Para la próxima entrada, intentaré apoyarme en algún tutorial de shaders que me permita seguir ampliando el ritmo de aprendizaje, pero siempre con la idea de entender qué estoy haciendo y por qué.


No hay comentarios:

Publicar un comentario