Componer transformaciones significa encadenar movimientos, giros y cambios de tamaño para construir una única operación. El resultado depende tanto de los valores como del orden en que se aplican.
En una escena 2D rara vez aplicamos una sola transformación. Un personaje puede cambiar de tamaño, girar para mirar en una dirección y después trasladarse hasta su posición. Una pieza de una interfaz puede definirse en coordenadas locales, pertenecer a un panel y, a su vez, formar parte de la pantalla.
La composición permite expresar toda esa cadena como una transformación. Comprenderla evita saltos, órbitas inesperadas, escalas aplicadas a la posición y muchos otros errores habituales.
Si una transformación A recibe un punto y B transforma el resultado, escribimos:
Primero actúa A y después B. La composición produce otra función que puede guardarse, reutilizarse o aplicarse a todos los vértices de un objeto.
Por ejemplo, si S escala, R rota y T traslada, la secuencia «escalar, rotar y trasladar» es:
En general, las transformaciones no son conmutativas. Esto significa que intercambiar su orden cambia el resultado:
Al rotar primero, la figura gira en su lugar y luego se desplaza. Al trasladar primero y rotar alrededor del origen, también gira el vector que separa la figura del origen: el objeto parece describir una órbita.
Una excepción importante es que dos traslaciones sí conmutan. También lo hacen dos escalados respecto del mismo centro y las rotaciones 2D respecto del mismo pivote. Esto no autoriza a reordenarlas libremente cuando se mezclan operaciones diferentes.
Tomemos P=(2,1), una rotación de 90° alrededor del origen y una traslación t=(3,0).
Los resultados (2,2) y (−1,5) son distintos aunque las operaciones y sus parámetros sean los mismos.
Con coordenadas homogéneas, traslación, rotación y escala pueden expresarse con matrices 3×3. Si usamos vectores columna, la matriz situada más cerca de P actúa primero:
La matriz compuesta C=T·R·S se calcula una sola vez y después se aplica a cada vértice. Esta idea es especialmente valiosa cuando una figura contiene cientos de puntos.
Para escala uniforme o no uniforme, rotación de ángulo θ y traslación (tx,ty):
| sx | 0 | 0 |
| 0 | sy | 0 |
| 0 | 0 | 1 |
| cos θ | −sen θ | 0 |
| sen θ | cos θ | 0 |
| 0 | 0 | 1 |
| 1 | 0 | tx |
| 0 | 1 | ty |
| 0 | 0 | 1 |
El último renglón permite integrar la traslación en la misma multiplicación. El tema siguiente profundizará en estas matrices.
Una transformación afín puede escribirse como P'=A·P+t, donde A contiene la parte lineal y t la traslación. Si aplicamos primero (A₁,t₁) y después (A₂,t₂):
La segunda transformación no solo afecta al punto: también modifica la traslación producida por la primera. Esa es la razón algebraica por la cual el orden cambia el resultado.
Rotar o escalar respecto de C=(cx,cy) requiere tres pasos: mover C al origen, aplicar la operación y devolverlo a su lugar.
Leída de derecha a izquierda, la expresión coincide con los pasos físicos. Omitir una de las traslaciones hace que el objeto gire o crezca alrededor del origen global.
Un vértice comienza en el sistema local del objeto. La transformación del objeto lo lleva al mundo; la cámara lo lleva al sistema de vista y, finalmente, otra transformación lo convierte en coordenadas de pantalla.
En una jerarquía, la transformación mundial de un hijo combina la de su padre con la local:
Así, la mano acompaña al brazo y el brazo acompaña al personaje sin recalcular manualmente todas sus posiciones.
Un punto representa una posición y debe recibir la traslación. Un vector de dirección representa un desplazamiento y no debe trasladarse. En coordenadas homogéneas se distinguen por su último componente:
Las normales requieren un tratamiento especial cuando existe escala no uniforme: deben transformarse con la inversa transpuesta de la parte lineal y normalizarse después.
La inversa deshace una composición. Además de invertir cada operación, hay que invertir el orden:
Esto permite convertir un clic de pantalla a coordenadas locales, comprobar si el puntero está dentro de un objeto rotado o devolver un punto desde el mundo al sistema de una figura.
Una escala con sx=0 o sy=0 aplasta una dimensión y no tiene inversa.
Ambos paneles parten de la misma figura y utilizan exactamente los mismos valores. El panel izquierdo aplica escala, rotación y traslación; el derecho invierte ese orden. Activa las etapas para observar los estados intermedios.
Podemos expresar cada transformación como una función y componerlas explícitamente. El orden queda visible y es fácil de depurar:
const trasladar=(p,tx,ty)=>({x:p.x+tx,y:p.y+ty});
const escalar=(p,sx,sy)=>({x:p.x*sx,y:p.y*sy});
function rotar(p,angulo) {
const c=Math.cos(angulo), s=Math.sin(angulo);
return {x:p.x*c-p.y*s,y:p.x*s+p.y*c};
}
// Primero escala, después rota y finalmente traslada.
function transformar(p,sx,sy,angulo,tx,ty) {
return trasladar(rotar(escalar(p,sx,sy),angulo),tx,ty);
}Una representación afín compacta usa seis valores: a, b, c, d, e y f. Con ellos se representan escala, rotación, corte y traslación en una sola estructura.
function multiplicar(A,B) {
return {
a:A.a*B.a+A.c*B.b,
b:A.b*B.a+A.d*B.b,
c:A.a*B.c+A.c*B.d,
d:A.b*B.c+A.d*B.d,
e:A.a*B.e+A.c*B.f+A.e,
f:A.b*B.e+A.d*B.f+A.f
};
}
const angulo = 30 * Math.PI / 180;
const T = {a:1,b:0,c:0,d:1,e:4,f:2};
const R = {a:Math.cos(angulo),b:Math.sin(angulo),
c:-Math.sin(angulo),d:Math.cos(angulo),e:0,f:0};
const S = {a:1.5,b:0,c:0,d:0.8,e:0,f:0};
const p = {x:2,y:1};
const C=multiplicar(T,multiplicar(R,S));
const pTransformado={
x:C.a*p.x+C.c*p.y+C.e,
y:C.b*p.x+C.d*p.y+C.f
};
console.log("Punto transformado:", pTransformado);Una vez compuesta la matriz, podemos transformar todos los vértices sin depender de ningún sistema de dibujo.
function aplicarMatriz(p, M) {
return {
x: M.a*p.x + M.c*p.y + M.e,
y: M.b*p.x + M.d*p.y + M.f
};
}
const C = {a:1.3,b:0.75,c:-0.4,d:0.69,e:4,f:2};
const vertices = [
{x:-1,y:-1}, {x:1,y:-1},
{x:1,y:1}, {x:-1,y:1}
];
const figuraTransformada = vertices.map(
punto => aplicarMatriz(punto, C)
);
figuraTransformada.forEach((p, i) =>
console.log(`V${i}: (${p.x.toFixed(2)}, ${p.y.toFixed(2)})`)
);La misma matriz se aplica a cada vértice. Esto mantiene una única fuente de verdad para toda la figura y hace visible el resultado al ejecutar el código.
La composición sostiene la animación articulada, los árboles de escena, las cámaras, los editores vectoriales, las interfaces anidadas, los mapas, los videojuegos y la conversión entre sistemas de coordenadas.
Cada pieza hereda la transformación de su padre. Cuando gira el hombro también se desplazan el antebrazo, la pinza y el núcleo; cuando gira el codo, solamente cambia su rama del árbol.
Recuerda: componer es encadenar; el orden suele cambiar el resultado; con vectores columna, la matriz de la derecha actúa primero; y una transformación alrededor de un pivote necesita trasladar al origen y regresar.
En el próximo tema estudiaremos con mayor profundidad las matrices de transformación 2D.