# Transformationsmatrix invertieren



## Runtime (22. Mai 2011)

Hallo,
ich will (wiedermal) etwas mit OpenGL/JOGL machen. Nun habe ich eine Klasse Matrix geschrieben, die eine 4x4 Matrix enthält. Alle Funktionen konnte ich irgendwie implementieren / zusammenguttenbergen, aber bei der Inversion kann / will mir weder der Mathematiklehrer noch Google helfen. Weiss jemand die 16 Formeln aus dem Stand heraus  oder kennt einen Link, in dem alle Formeln beschrieben sind oder zu einem Gratisprogramm mit dem man die Berechnen kann?
Gruss Cyrill


----------



## Guest2 (23. Mai 2011)

Moin,

die Formel für die Inverse einer 4x4 Matrix gibt es z.B. hier: Inverse matrix of 2x2 matrix, 3x3 matrix, 4x4 matrix

(Je nach Problem kann es aber auch sein, das Du nicht die vollständige Inverse brauchst, sondern die Inverse der Rotationskomponente schon reichen würde. Die Rotationskomponente liegt in den oberen linken 3x3 Komponenten der Transformationsmatrix. Die Inverse davon ist dann einfach die Transponierte davon. Wenn Du also z.B. so was wie CubeMapping vorhast, gibt das weniger Rechnerei.)  

Viele Grüße,
Fancy


----------



## AlexSpritze (23. Mai 2011)

Schau dir mal das Apache Projekt common math an .. da gibt es schon fertige Implementierungen von Matrizen, die natürlich auch die Inversenberechnung enthalten.


----------



## Runtime (23. Mai 2011)

Vielen dank euch beiden


----------



## Runtime (29. Mai 2011)

```
public final class Matrix implements Cloneable {

    double[] mx;

    public Matrix() {
        mx = new double[16];
        identity();
    }

    public Matrix(double[] mx) {
        if (mx.length != 16) {
            throw new IllegalArgumentException("mx.length != 16");
        }
        this.mx = mx;
    }

    public double[] getMatrix() {
        return mx;
    }

    public void multiplicate(double[] nm) {
        int x, a, b;
        double[] tm = new double[16];

        for (x = 0; x < 16; x++) {
            a = x % 4;
            b = (x / 4) * 4;

            tm[ x] = nm[ a] * mx[ b]
                    + nm[ a + 4] * mx[ b + 1]
                    + nm[ a + 8] * mx[ b + 2]
                    + nm[ a + 12] * mx[ b + 3];
        }

        for (x = 0; x < 16; x++) {
            mx[ x] = tm[ x];
        }
    }

    public void multiplicate(Matrix matrix) {
        multiplicate(matrix.mx);
    }

    public void rotate(double alpha, Vector3f dir) {
        double[] rm = new double[16];

        if (dir.length() < 0.0001) {
            return;
        }

        dir = dir.mul(1.0 / dir.length());
        double x = dir.x, y = dir.y, z = dir.z;

        double s = Math.sin(Math.toRadians(alpha));
        double c = Math.cos(Math.toRadians(alpha));

        rm[ 0] = x * x * (1 - c) + c;
        rm[ 4] = x * y * (1 - c) - z * s;
        rm[ 8] = x * z * (1 - c) + y * s;
        rm[ 12] = 0;
        rm[ 1] = x * y * (1 - c) + z * s;
        rm[ 5] = y * y * (1 - c) + c;
        rm[ 9] = y * z * (1 - c) - x * s;
        rm[ 13] = 0;
        rm[ 2] = x * z * (1 - c) - y * s;
        rm[ 6] = y * z * (1 - c) + x * s;
        rm[ 10] = z * z * (1 - c) + c;
        rm[ 14] = 0;
        rm[ 3] = 0;
        rm[ 7] = 0;
        rm[ 11] = 0;
        rm[ 15] = 1;

        multiplicate(rm);
    }

    public void rotate_x(double alpha) {
        rotate(alpha, new Vector3f(1, 0, 0));
    }

    public void rotate_y(double alpha) {
        rotate(alpha, new Vector3f(0, 1, 0));
    }

    public void rotate_z(double alpha) {
        rotate(alpha, new Vector3f(0, 0, 1));
    }

    public void rotate(double alpha) {
        rotate_z(alpha);
    }

    public void rotate(double x, double y, double alpha) {
        rotate(alpha, new Vector3f(x, y, 0));
    }

    public void translate(double xt, double yt, double zt) {
        double[] tm = new double[16];

        tm[ 0] = 1;
        tm[ 4] = 0;
        tm[ 8] = 0;
        tm[ 12] = xt;
        tm[ 1] = 0;
        tm[ 5] = 1;
        tm[ 9] = 0;
        tm[ 13] = yt;
        tm[ 2] = 0;
        tm[ 6] = 0;
        tm[ 10] = 1;
        tm[ 14] = zt;
        tm[ 3] = 0;
        tm[ 7] = 0;
        tm[ 11] = 0;
        tm[ 15] = 1;

        multiplicate(tm);
    }

    public void translate(double tx, double ty) {
        translate(tx, ty, 0);
    }

    public void scale(double xs, double ys, double zs) {
        double[] sm = new double[16];

        sm[ 0] = xs;
        sm[ 4] = 0;
        sm[ 8] = 0;
        sm[ 12] = 0;
        sm[ 1] = 0;
        sm[ 5] = ys;
        sm[ 9] = 0;
        sm[ 13] = 0;
        sm[ 2] = 0;
        sm[ 6] = 0;
        sm[ 10] = zs;
        sm[ 14] = 0;
        sm[ 3] = 0;
        sm[ 7] = 0;
        sm[ 11] = 0;
        sm[ 15] = 1;

        multiplicate(sm);
    }

    public void scale(double sx, double sy) {
        scale(sx, sy, 0);
    }

    public Point3d transform(Point3d p) {
        double wx = p.x * mx[ 0] + p.y * mx[ 4] + p.z * mx[ 8] + mx[ 12];
        double wy = p.x * mx[ 1] + p.y * mx[ 5] + p.z * mx[ 9] + mx[ 13];
        double wz = p.x * mx[ 2] + p.y * mx[ 6] + p.z * mx[ 10] + mx[ 14];

        return new Point3d(wx, wy, wz);
    }

    public Vector3f transform(Vector3f v) {
        double x = v.x * mx[ 0] + v.y * mx[ 4] + v.z * mx[ 8];
        double y = v.x * mx[ 1] + v.y * mx[ 5] + v.z * mx[ 9];
        double z = v.x * mx[ 2] + v.y * mx[ 6] + v.z * mx[ 10];

        return new Vector3f(x, y, z);
    }

    public void identity() {
        mx[ 0] = 1;
        mx[ 4] = 0;
        mx[ 8] = 0;
        mx[ 12] = 0;
        mx[ 1] = 0;
        mx[ 5] = 1;
        mx[ 9] = 0;
        mx[ 13] = 0;
        mx[ 2] = 0;
        mx[ 6] = 0;
        mx[ 10] = 1;
        mx[ 14] = 0;
        mx[ 3] = 0;
        mx[ 7] = 0;
        mx[ 11] = 0;
        mx[ 15] = 1;
    }

    public void rows(Vector3f a, Vector3f b, Vector3f c) {
        double[] rm = new double[16];

        rm[ 0] = a.x;
        rm[ 4] = a.y;
        rm[ 8] = a.z;
        rm[ 12] = 0;
        rm[ 1] = b.x;
        rm[ 5] = b.y;
        rm[ 9] = b.z;
        rm[ 13] = 0;
        rm[ 2] = c.x;
        rm[ 6] = c.y;
        rm[ 10] = c.z;
        rm[ 14] = 0;
        rm[ 3] = 0;
        rm[ 7] = 0;
        rm[ 11] = 0;
        rm[ 15] = 1;

        multiplicate(rm);
    }

    public void columns(Vector3f a, Vector3f b, Vector3f c) {
        double[] cm = new double[16];

        cm[ 0] = a.x;
        cm[ 4] = b.x;
        cm[ 8] = c.x;
        cm[ 12] = 0;
        cm[ 1] = a.y;
        cm[ 5] = b.y;
        cm[ 9] = c.y;
        cm[ 13] = 0;
        cm[ 2] = a.z;
        cm[ 6] = b.z;
        cm[ 10] = c.z;
        cm[ 14] = 0;
        cm[ 3] = 0;
        cm[ 7] = 0;
        cm[ 11] = 0;
        cm[ 15] = 1;

        multiplicate(cm);
    }

    public double determinant() {
        return mx[12] * mx[9] * mx[6] * mx[3]
                - mx[8] * mx[13] * mx[6] * mx[3]
                - mx[12] * mx[5] * mx[10] * mx[3]
                + mx[4] * mx[13] * mx[10] * mx[3]
                + mx[8] * mx[5] * mx[14] * mx[3]
                - mx[4] * mx[9] * mx[14] * mx[3]
                - mx[12] * mx[9] * mx[2] * mx[7]
                + mx[8] * mx[13] * mx[2] * mx[7]
                + mx[12] * mx[1] * mx[10] * mx[7]
                - mx[0] * mx[13] * mx[10] * mx[7]
                - mx[8] * mx[1] * mx[14] * mx[7]
                + mx[0] * mx[9] * mx[14] * mx[7]
                + mx[12] * mx[5] * mx[2] * mx[11]
                - mx[4] * mx[13] * mx[2] * mx[11]
                - mx[12] * mx[1] * mx[6] * mx[11]
                + mx[0] * mx[13] * mx[6] * mx[11]
                + mx[4] * mx[1] * mx[14] * mx[11]
                - mx[0] * mx[5] * mx[14] * mx[11]
                - mx[8] * mx[5] * mx[2] * mx[15]
                + mx[4] * mx[9] * mx[2] * mx[15]
                + mx[8] * mx[1] * mx[6] * mx[15]
                - mx[0] * mx[9] * mx[6] * mx[15]
                - mx[4] * mx[1] * mx[10] * mx[15]
                + mx[0] * mx[5] * mx[10] * mx[15];
    }
    
    public void invert() {
        double[] inverse = new double[16];
        generateInverseMatrix(inverse, mx);
        mx = inverse;
    }

    private boolean generateInverseMatrix(double[] i, double[] m) {
        double x = determinant();
        if (x == 0) {
            return false;
        }

        i[0] = (-m[13] * m[10] * m[7] + m[9] * m[14] * m[7] + m[13] * m[6] * m[11]
                - m[5] * m[14] * m[11] - m[9] * m[6] * m[15] + m[5] * m[10] * m[15]) / x;
        i[4] = (m[12] * m[10] * m[7] - m[8] * m[14] * m[7] - m[12] * m[6] * m[11]
                + m[4] * m[14] * m[11] + m[8] * m[6] * m[15] - m[4] * m[10] * m[15]) / x;
        i[8] = (-m[12] * m[9] * m[7] + m[8] * m[13] * m[7] + m[12] * m[5] * m[11]
                - m[4] * m[13] * m[11] - m[8] * m[5] * m[15] + m[4] * m[9] * m[15]) / x;
        i[12] = (m[12] * m[9] * m[6] - m[8] * m[13] * m[6] - m[12] * m[5] * m[10]
                + m[4] * m[13] * m[10] + m[8] * m[5] * m[14] - m[4] * m[9] * m[14]) / x;
        i[1] = (m[13] * m[10] * m[3] - m[9] * m[14] * m[3] - m[13] * m[2] * m[11]
                + m[1] * m[14] * m[11] + m[9] * m[2] * m[15] - m[1] * m[10] * m[15]) / x;
        i[5] = (-m[12] * m[10] * m[3] + m[8] * m[14] * m[3] + m[12] * m[2] * m[11]
                - m[0] * m[14] * m[11] - m[8] * m[2] * m[15] + m[0] * m[10] * m[15]) / x;
        i[9] = (m[12] * m[9] * m[3] - m[8] * m[13] * m[3] - m[12] * m[1] * m[11]
                + m[0] * m[13] * m[11] + m[8] * m[1] * m[15] - m[0] * m[9] * m[15]) / x;
        i[13] = (-m[12] * m[9] * m[2] + m[8] * m[13] * m[2] + m[12] * m[1] * m[10]
                - m[0] * m[13] * m[10] - m[8] * m[1] * m[14] + m[0] * m[9] * m[14]) / x;
        i[2] = (-m[13] * m[6] * m[3] + m[5] * m[14] * m[3] + m[13] * m[2] * m[7]
                - m[1] * m[14] * m[7] - m[5] * m[2] * m[15] + m[1] * m[6] * m[15]) / x;
        i[6] = (m[12] * m[6] * m[3] - m[4] * m[14] * m[3] - m[12] * m[2] * m[7]
                + m[0] * m[14] * m[7] + m[4] * m[2] * m[15] - m[0] * m[6] * m[15]) / x;
        i[10] = (-m[12] * m[5] * m[3] + m[4] * m[13] * m[3] + m[12] * m[1] * m[7]
                - m[0] * m[13] * m[7] - m[4] * m[1] * m[15] + m[0] * m[5] * m[15]) / x;
        i[14] = (m[12] * m[5] * m[2] - m[4] * m[13] * m[2] - m[12] * m[1] * m[6]
                + m[0] * m[13] * m[6] + m[4] * m[1] * m[14] - m[0] * m[5] * m[14]) / x;
        i[3] = (m[9] * m[6] * m[3] - m[5] * m[10] * m[3] - m[9] * m[2] * m[7]
                + m[1] * m[10] * m[7] + m[5] * m[2] * m[11] - m[1] * m[6] * m[11]) / x;
        i[7] = (-m[8] * m[6] * m[3] + m[4] * m[10] * m[3] + m[8] * m[2] * m[7]
                - m[0] * m[10] * m[7] - m[4] * m[2] * m[11] + m[0] * m[6] * m[11]) / x;
        i[11] = (m[8] * m[5] * m[3] - m[4] * m[9] * m[3] - m[8] * m[1] * m[7]
                + m[0] * m[9] * m[7] + m[4] * m[1] * m[11] - m[0] * m[5] * m[11]) / x;
        i[15] = (-m[8] * m[5] * m[2] + m[4] * m[9] * m[2] + m[8] * m[1] * m[6]
                - m[0] * m[9] * m[6] - m[4] * m[1] * m[10] + m[0] * m[5] * m[10]) / x;

        return true;
    }

    @Override
    public Matrix clone() {
        double[] matrix = new double[mx.length];
        System.arraycopy(mx, 0, matrix, 0, mx.length);
        return new Matrix(matrix);
    }
}
```
Irgendwas ist falsch (ich hoffe nicht getDeterminant oder generateInverseMatrix) sieht irgendjemand den Fehler vllt gleich? Spielt es eine Rolle, wenn ich eine Matrix invertiere, ob sie Column- oder Row-Major ist?
Edit:
KSKB:

```
public class MatrixInversionTest {
    
    public static void main(String[] args) {
        Matrix A = new Matrix();
        A.rotate(13, 15, 120);
        A.translate(13, 54, 62);
        A.scale(2, 4, 13);
        Matrix B = A.clone();
        B.invert();
        
        A.multiplicate(B);
        
        double[] mx = A.getMatrix();
        for (int i = 0; i < mx.length; i++) {
            System.out.println(mx[i]);
        }
    }
    
}
```


----------



## Runtime (30. Mai 2011)

Es funktioniert, solange ich nur drehe und verschiebe, sobald aber Skalieren dazukommt, funktionierts nicht mehr.


----------



## Marco13 (30. Mai 2011)

In Zeile 287 muss es bei der Berechnung von i[2] nicht "m[3] + m[5]" sondern "m[3] * m[5]" heißen.

:joke:

Mal im ernst: Wo hast du das her, und wie soll man dort einen Fehler erkennen?


----------



## Runtime (31. Mai 2011)

Im Internet gefunden. Ich hab eigentlich darauf gehofft, dass der Fehler nicht in diesem Codestück liegt.


----------



## AlexSpritze (2. Jun 2011)

Warum nimmst du nicht Apache Common Math?


----------



## Runtime (2. Jun 2011)

Weil ich nur zum Spass programmiere und ich dann einfach nicht gerne fremdes Zeug benutze, zudem enthält Apache Common Math noch anderes Zeug, das ich nicht brauchen kann.


----------



## Marco13 (2. Jun 2011)

Nochmal nacheinander:



Runtime hat gesagt.:


> AlexSpritze hat gesagt.:
> 
> 
> > Runtime hat gesagt.:
> ...





Genauso wie das bisherige "irgendwoher" ist, kannst du ja auch die benötigten Teile aus der Apache-Lib kopieren... solange du sie nicht weitervertreibst, ist das ja egal ... :bahnhof:


----------



## Runtime (2. Jun 2011)

Ok, ich geb mich geschlagen


----------

