Respuestas:
Sí, puede agregar un vector en el caso de la traducción. La razón para usar una matriz se reduce a tener una forma uniforme de manejar diferentes transformaciones combinadas.
Por ejemplo, la rotación generalmente se realiza utilizando una matriz (consulte el comentario @MickLH para conocer otras formas de lidiar con las rotaciones), por lo que para lidiar con múltiples transformaciones (rotación / traslación / escala / proyección ... etc.) de manera uniforme, necesitas codificarlos en una matriz.
Bueno, más técnicamente hablando; una transformación es mapear un punto / vector a otro punto / vector.
p` = T(p);
donde p` es el punto transformado y T (p) es la función de transformación.
Dado que no usamos una matriz, necesitamos hacer esto para combinar múltiples transformaciones:
p1 = T (p);
p final = M (p1);
Una matriz no solo puede combinar múltiples tipos de transformaciones en una sola matriz (por ejemplo, afín, lineal, proyectiva).
El uso de una matriz nos da la oportunidad de combinar cadenas de transformaciones y luego multiplicarlas por lotes. Esto nos ahorra una tonelada de ciclos generalmente por la GPU (gracias a @ChristianRau por señalarlo).
T final = T * R * P; // traducir proyecto rotar
p final = T final * p;
También es bueno señalar que las GPU e incluso algunas CPU están optimizadas para operaciones vectoriales; Las CPU que usan SIMD y las GPU son procesadores paralelos controlados por datos por diseño, por lo que el uso de matrices se adapta perfectamente a la aceleración de hardware (en realidad, las GPU se diseñaron para adaptarse a operaciones de matriz / vector).
Si todo lo que vas a hacer es moverte a lo largo de un solo eje y nunca aplicar ninguna otra transformación, entonces lo que estás sugiriendo está bien.
El poder real de usar una matriz es que puede concatenar fácilmente una serie de operaciones complejas y aplicar la misma serie de operaciones a múltiples objetos.
La mayoría de los casos no son tan simples y si gira su objeto primero y desea transformarlo a lo largo de sus ejes locales en lugar de los ejes mundiales, encontrará que no puede simplemente agregar 10 a uno de los números y hacer que funcione correctamente .
Para responder sucintamente a la pregunta "por qué", es porque una matriz 4x4 puede describir las operaciones de rotación, traslación y escalado de una vez. Ser capaz de describir cualquiera de estos de manera consistente simplifica muchas cosas.
Diferentes tipos de transformaciones pueden representarse más simplemente con diferentes operaciones matemáticas. Como observa, la traducción se puede hacer simplemente agregando. Escalado uniforme multiplicando por un escalar. Pero una matriz 4x4 adecuadamente diseñada puede hacer cualquier cosa. Por lo tanto, usar 4x4 constantemente hace que el código y las interfaces sean mucho más simples. Pagas un poco de complejidad para entender estos 4x4, pero muchas cosas se vuelven más fáciles y rápidas debido a eso.
La razón para usar una matriz 4x4 es para que la operación sea una transformación lineal . Este es un ejemplo de coordenadas homogéneas . Lo mismo se hace en el caso 2d (usando una matriz 3x3). La razón para usar coordenadas homogéneas es que las 3 transformaciones geométricas se pueden hacer usando una sola operación; de lo contrario, se necesitaría hacer una matriz de 3x3 y una matriz de 3x3 (para la traducción). este enlace de cegprakash es útil.
Las traducciones no pueden ser representadas por matrices 3D
Un argumento simple es que la traducción puede tomar el vector de origen:
0
0
0
lejos del origen, diga a x = 1
:
1
0
0
Pero eso requeriría una matriz tal que:
| a b c | |0| |1|
| d e f | * |0| = |0|
| g h i | |0| |0|
Pero eso es imposible.
Otro argumento es el teorema de la descomposición del valor singular , que dice que cada matriz puede estar compuesta por dos operaciones de rotación y una de escala. No hay traducciones allí.
¿Por qué se pueden usar matrices?
Muchos objetos modelados (por ejemplo, un chasis de automóvil) o parte de objetos modelados (por ejemplo, un neumático de automóvil, una rueda motriz) son sólidos: las distancias entre los vértices nunca cambian.
Las únicas transformaciones que queremos hacer en ellos son rotaciones y traslaciones.
La multiplicación de matrices puede codificar tanto rotaciones como traslaciones.
Las matrices de rotación tienen fórmulas explícitas, por ejemplo: una matriz de rotación 2D para ángulo a
tiene forma:
cos(a) -sin(a)
sin(a) cos(a)
Existen fórmulas análogas para 3D , pero tenga en cuenta que las rotaciones 3D toman 3 parámetros en lugar de solo 1 .
Las traducciones son menos triviales y se discutirán más adelante. Son la razón por la que necesitamos matrices 4D.
¿Por qué es genial usar matrices?
Porque la composición de múltiples matrices puede calcularse previamente mediante la multiplicación de matrices .
Por ejemplo, si vamos a traducir mil vectores v
del chasis de nuestro automóvil con matriz T
y luego giramos con matriz R
, en lugar de hacer:
v2 = T * v
y entonces:
v3 = R * v2
para cada vector, podemos calcular previamente:
RT = R * T
y luego haz una sola multiplicación por cada vértice:
v3 = RT * v
Mejor aún: si luego queremos colocar los vértices de la llanta y la rueda motriz en relación con el automóvil, simplemente multiplicamos la matriz anterior RT
por la matriz relativa al automóvil en sí.
Esto naturalmente lleva a mantener una pila de matrices:
Cómo agregar una dimensión resuelve el problema
Consideremos el caso de 1D a 2D, que es más fácil de visualizar.
Una matriz en 1D es solo un número, y como hemos visto en 3D, no puede hacer una traducción, solo una escala.
Pero si agregamos la dimensión extra como:
| 1 dx | * |x| = | x + dx |
| 0 1 | |1| | 1 |
y luego nos olvidamos de la nueva dimensión extra, obtenemos:
x + dx
como quisimos
Esta transformación 2D es tan importante que tiene un nombre: transformación de corte .
Es genial visualizar esta transformación:
Observe cómo cada línea horizontal (fija y
) se acaba de traducir.
Simplemente tomamos la línea y = 1
como nuestra nueva línea 1D y la traducimos con una matriz 2D.
Las cosas son análogas en 3D, con matrices de corte 4D de la forma:
| 1 0 0 dx | | x | | x + dx |
| 0 1 0 dy | * | y | = | y + dy |
| 0 0 1 dz | | z | | z + dz |
| 0 0 0 1 | | 1 | | 1 |
Y nuestras antiguas rotaciones / escalas 3D ahora tienen forma:
| a b c 0 |
| d e f 0 |
| g h i 0 |
| 0 0 0 1 |
También vale la pena ver este video tutorial de Jamie King .
Espacio afinado
El espacio afín es el espacio generado por todas nuestras transformaciones lineales 3D (multiplicaciones de matriz) junto con la cizalla 4D (traducciones 3D).
Si multiplicamos una matriz de corte y una transformación lineal 3D, siempre obtenemos algo de la forma:
| a b c dx |
| d e f dy |
| g h i dz |
| 0 0 0 1 |
Esta es la transformación afín más general posible, que realiza rotación / escalado 3D y traslación.
Una propiedad importante es que si multiplicamos 2 matrices afines:
| a b c dx | | a2 b2 c2 dx2 |
| d e f dy | * | d2 e2 f2 dy2 |
| g h i dz | | g2 h2 i2 dz2 |
| 0 0 0 1 | | 0 0 0 1 |
que siempre obtenemos otra matriz afín de la forma:
| a3 b3 c3 (dx + dx2) |
| d3 e3 f3 (dy + dy2) |
| g3 h3 i3 (dz + dz2) |
| 0 0 0 1 |
Los matemáticos llaman a esto cierre de propiedad , y se requiere para definir un espacio.
Para nosotros, significa que podemos seguir haciendo multiplicaciones matriciales para calcular felizmente las transformaciones finales, por lo que, en primer lugar, utilizamos matrices usadas, sin obtener nunca transformaciones lineales 4D más generales que no sean afines.
Proyección de frustum
Pero espera, hay una transformación más importante que hacemos todo el tiempo: glFrustum
que hace que un objeto sea 2 , parece 2 más pequeño.
Primero, tenga alguna intuición sobre glOrtho
vs glFrustum
en: https://stackoverflow.com/questions/2571402/explain-the-usage-of-glortho/36046924#36046924
glOrtho
se puede hacer solo con traducciones + escalado, pero ¿cómo podemos implementarlo glFrustum
con matrices?
Suponer que:
z = -1
tiene un cuadrado de longitud 2z = -2
Si solo permitiéramos 4 vectores más generales de tipo:
(x, y, z, w)
con w != 0
, y además identificamos cada (x, y, z, w)
con (x/w, y/w, z/w, 1)
, entonces una transformación de frustum con la matriz sería:
| 1 0 0 0 | | x | | x | | x / -z |
| 0 1 0 0 | * | y | = | y | identified to | y / -z |
| 0 0 1 0 | | z | | z | | -1 |
| 0 0 -1 0 | | w | | -z | | 0 |
Si tiramos z
y w
al final, obtenemos:
x_proj = x / -z
y_proj = y / -z
que es exactamente lo que queríamos! Podemos verificar eso para algunos valores, por ejemplo:
z == -1
, exactamente en el avión al que estamos proyectando, x_proj == x
y y_proj == y
.z == -2
, entonces x_proj = x/2
: los objetos son de la mitad del tamaño.Tenga en cuenta que la glFrustum
transformación no es afín: no se puede implementar solo con rotaciones y traslaciones.
El "truco" matemático de sumar w
y dividir por él se denomina coordenadas homogéneas.
Ver también: pregunta relacionada con el desbordamiento de pila: https://stackoverflow.com/questions/2465116/understanding-opengl-matrices
Vea este video para comprender los conceptos de modelo, vista y proyección.
Las matrices 4x4 no solo se usan para traducir un objeto 3D. Pero también para varios otros propósitos.
Vea esto para comprender cómo los vértices del mundo se representan como Matrices 4D y cómo se transforman.