53 Stimmen

Android: Matrix -> was ist der Unterschied zwischen preconcat und postconcat?

Ich benutze Matrix zum Skalieren und Drehen von Bitmaps. Jetzt frage ich mich, was der Unterschied zwischen preconcat & postconcat ist, oder genauer gesagt der Unterschied zwischen:

Nach dem, was ich bisher herausfinden konnte, überschreibt setRotate immer die gesamte Matrix, während ich mit preRotate und postRotate mehrere Änderungen auf eine Matrix anwenden kann (z. B. Skalierung + Drehung). Die Verwendung von postRotate oder preRotate führte jedoch in den Fällen, in denen ich sie verwendete, zu keinen unterschiedlichen Ergebnissen.

142voto

Cheezmeister Punkte 4839

Die Antwort auf Ihre Frage ist nicht wirklich spezifisch für Android; es ist eine Frage zu Grafik und Mathematik. In dieser Antwort steckt viel Theorie - Sie sind gewarnt! Für eine oberflächliche Antwort auf Ihre Frage, springen Sie zum Ende. Da es sich um eine langatmige Tirade handelt, kann es sein, dass ich den einen oder anderen Tippfehler habe, der die Dinge unklar macht. Ich entschuldige mich im Voraus, falls dies der Fall sein sollte.

In der Computergrafik können wir Pixel (oder in 3D, Scheitelpunkte) als Vektoren darstellen. Wenn Ihr Bildschirm eine Größe von 640x480 hat, sehen Sie hier einen 2D-Vektor für den Punkt in der Mitte Ihres Bildschirms (verzeihen Sie mir die schlampige Darstellung):

[320]
[240]
[  1]

Ich werde später erklären, warum die 1 wichtig ist. Transformationen werden oft dargestellt mit Matrizen weil es dann sehr einfach (und sehr effizient) ist, sie miteinander zu verknüpfen, wie Sie bereits erwähnt haben. Um den obigen Punkt um den Faktor 1,5 zu skalieren, können Sie links-multiplizieren es durch die folgende Matrix:

[1.5   0   0]
[  0 1.5   0]
[  0   0   1]

Sie werden diesen neuen Punkt erhalten:

[480]
[360]
[  1]

Das ist der ursprüngliche Punkt, skaliert um 1,5 in Bezug auf die Ecke des Bildschirms (0, 0). Dies ist wichtig: Die Skalierung erfolgt immer in Bezug auf den Ursprung. Wenn Sie mit einem anderen Punkt als Zentrum skalieren wollen (z. B. der Mitte eines Sprites), müssen Sie die Skalierung in Translationen zum und vom Ursprung "einwickeln". Hier ist die Matrix, um unseren ursprünglichen Punkt zum Ursprung zu übersetzen:

[1  0  -320]
[0  1  -240]
[0  0     1]

Daraus ergibt sich:

[320*1 + 1*-320]   [0]
[240*1 + 1*-240] = [0]
[     1*1      ]   [1]

Sie erkennen das oben Gesagte als die Identität Matrix mit den Verschiebungskoordinaten, die in der oberen rechten Ecke stehen. Deshalb ist die 1 (die "homogene Koordinate") notwendig: um Platz für diese Koordinaten zu schaffen und so eine Übersetzung durch Multiplikation zu ermöglichen. Andernfalls müsste es durch Matrixaddition dargestellt werden, was für den Menschen intuitiver ist, aber Grafikkarten noch komplizierter machen würde, als sie ohnehin schon sind.

Die Matrixmultiplikation ist im Allgemeinen ist nicht kommutativ so dass beim "Hinzufügen" einer Transformation (durch Multiplizieren Matrix) müssen Sie angeben, ob Sie linksmultiplizieren oder rechtsmultiplizieren. Der Unterschied liegt in der Reihenfolge, in der die Transformationen verkettet werden. Durch Rechtsmultiplikation Ihrer Matrix (mit preRotate() ) geben Sie an, dass der Rotationsschritt erfolgen soll antes de all die anderen Umwandlungen, um die Sie gerade gebeten haben. Das könnte das sein, was Sie wollen, ist es aber normalerweise nicht.

Oft spielt das keine Rolle. Wenn du zum Beispiel nur eine Verwandlung hast, spielt das keine Rolle :) Manchmal können die Transformationen in beliebiger Reihenfolge mit demselben Effekt stattfinden, wie z. B. Skalierung und Drehung - meine lineare Algebra ist eingerostet, aber ich glaube, dass in diesem Fall die Matrixmultiplikation tatsächlich kommutativ ist, weil die Skalenmatrix symmetrisch d.h. sie spiegelt sich an der Diagonale. Aber denken Sie doch einmal darüber nach: Wenn ich ein Bild um 10 Grad im Uhrzeigersinn drehe und es dann auf 200 % skaliere, sieht es genauso aus, als hätte ich es erst skaliert und dann gedreht.

Wenn Sie etwas seltsamere zusammengesetzte Transformationen durchführen würden, würden Sie eine Diskrepanz bemerken. Mein Rat ist, sich an die postRotate() .

6voto

chikeong Punkte 49

Ich habe die Frage gestern beantwortet, aber ich habe das Gefühl, dass ich heute etwas falsch gemacht habe, also korrigiere ich die Antwort hier:

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, wenn wir die Transformation wie unten beschrieben durchführen:

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, wenn wir die Transformation wie unten durchführen:

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, wenn wir die Transformation wie unten beschrieben durchführen:

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, wenn wir die Transformation wie unten beschrieben durchführen:

 matrix.preSkew(0.4f,0.4f);

ist gleichbedeutend mit einer Sequenztransformation in Matrix2 wie unten:

 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);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X