Android: Matrix-> ¿cuál es la diferencia entre preconcat y postconcat?
(2)
La respuesta a tu pregunta no es realmente específica de Android; es una pregunta de gráficos y matemáticas. Hay mucha teoría en esta respuesta: ¡has sido advertido! Para una respuesta superficial a su pregunta, salte al final. Además, debido a que esta es una diatriba tan larga, podría tener un error tipográfico o dos que hacen que las cosas no estén claras. Me disculpo de antemano si ese es el caso.
En gráficos por computadora, podemos representar píxeles (o en 3D, vértices) como vectores. Si su pantalla es de 640x480, aquí hay un vector 2D para el punto en el medio de la pantalla (perdone mi marcado de mala calidad):
[320]
[240]
[ 1]
Explicaré por qué el 1 es importante más adelante. Las transformaciones a menudo se representan utilizando matrices porque es muy simple (y muy eficiente) encadenarlas, como usted mencionó. Para escalar el punto anterior por un factor de 1.5, puedes left-multiply por la siguiente matriz:
[1.5 0 0]
[ 0 1.5 0]
[ 0 0 1]
Obtendrás este nuevo punto:
[480]
[360]
[ 1]
Que representa el punto original, escalado por 1.5 relativo a la esquina de su pantalla (0, 0). Esto es importante: el escalado siempre se hace con respecto al origen. Si desea escalar con algún otro punto como su centro (como el centro de un sprite), debe "ajustar" la escala en las traducciones hacia y desde el origen. Aquí está la matriz para traducir nuestro punto original al origen:
[1 0 -320]
[0 1 -240]
[0 0 1]
Cuyos rendimientos:
[320*1 + 1*-320] [0]
[240*1 + 1*-240] = [0]
[ 1*1 ] [1]
Reconocerá lo anterior como la matriz de identity con las coordenadas de desplazamiento abofeteadas en la esquina superior derecha. Es por eso que el 1 (la "coordenada homogénea") es necesario: para hacer espacio para estas coordenadas, lo que hace posible traducir utilizando la multiplicación. De lo contrario, tendría que estar representado por la adición de la matriz, que es más intuitiva para los humanos, pero haría las tarjetas gráficas aún más complicadas de lo que ya son.
Ahora bien, la multiplicación de matrices generalmente no es conmutativa , por lo que cuando "se agrega" una transformación (al multiplicar su matriz), debe especificar si está multiplicando a la izquierda o multiplicando a la derecha. La diferencia que hace es en qué orden están encadenadas sus transformaciones. Al multiplicar correctamente su matriz (usando preRotate()
) está indicando que el paso de rotación debería ocurrir antes que todas las demás transformaciones que acaba de solicitar. Esto podría ser lo que quieras, pero por lo general no lo es.
A menudo, no importa. Si solo tiene una transformación, por ejemplo, nunca importa :) A veces, las transformaciones pueden ocurrir en cualquier orden con el mismo efecto, como escalado y rotación: mi álgebra lineal está oxidada, pero creo que en este caso el la multiplicación de la matriz en realidad es conmutativa porque la matriz de la escala es symmetric , es decir, se refleja en la diagonal. Pero en realidad, solo piénselo: si giro una imagen 10 grados en el sentido de las agujas del reloj y luego la escala al 200%, se ve igual que si primero la escalara, luego la roté.
Si estuvieras haciendo transformaciones de compuestos más extraños, comenzarías a notar una discrepancia. Mi consejo es seguir con postRotate()
.
Estoy usando Matrix para escalar y rotar Bitmaps. Ahora me pregunto cuál es la diferencia entre preconcat y postconcat, o más precisamente la diferencia entre:
De lo que pude deducir hasta ahora, setRotate siempre sobrescribe toda la matriz, mientras que con preRotate y postRotate puedo aplicar múltiples cambios a una matriz (por ejemplo, escala + rotación). Sin embargo, usar postRotate o preRotate no causó ningún resultado diferente para los casos que los utilicé.
Respondí la pregunta ayer, pero siento que algo anda mal hoy, así que corrijo la respuesta aquí:
matrix: float[] values ={1.2f,0.5f,30,0.5f,1.2f,30,0,0,1};
//as we all know, the basic value in matrix,means no transformation added
matrix2: float[] values2 ={1f,0,0,0,1f,0,0,0,1};
Let''s say our matrix values are the values above.
1, cuando hacemos la transformación como a continuación:
matrix.preTranslate(-50, -50);
is equals to do sequence transformation to matrix2 above like below:
matrix2.postTranslate(-50, -50);
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f);// note here
matrix2.postScale(1.2f, 1.2f);
matrix2.postTranslate(30, 30);
2, cuando hacemos la transformación como a continuación:
matrix.preRotate(50);
is equals to do sequence transformation to matrix2 like below:
matrix2.postRotate(50);
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f);
matrix2.postScale(1.2f, 1.2f);
matrix2.postTranslate(30, 30);
3, cuando hacemos la transformación como a continuación:
matrix.preScale(1.3f,1.3f);
is equals to do sequence transformation to matrix2 like below:
matrix2.postScale(1.3f,1.3f);
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f);
matrix2.postScale(1.2f, 1.2f);
matrix2.postTranslate(30, 30);
4, cuando hacemos la transformación como a continuación:
matrix.preSkew(0.4f,0.4f);
es igual a hacer la transformación de secuencia a matrix2 como a continuación:
matrix2.postSkew(0.4f,0.4f);
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f);
matrix2.postScale(1.2f, 1.2f);
matrix2.postTranslate(30, 30);