Matrix 2 Euler - Euler 2 Matrix

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
Benutzeravatar
Zudomon
Establishment
Beiträge: 2253
Registriert: 25.03.2009, 07:20
Kontaktdaten:

Matrix 2 Euler - Euler 2 Matrix

Beitrag von Zudomon »

Huhu! :D
Vielleicht kann mir jemand helfen.
Also ich wollte Shader Konstanten sparen und dafür die Rotation statt in einem Quaternion, in Eulerwinkeln speichern. Nun müsste ich dafür ja erstmal eine Matrix in Euler konvertieren, und im Shader dann wieder zurück... momentan versuche ich es erstmal auf der CPU, da kann man es direkt debuggen.
Nun habe ich zwar schon einige Routinen gefunden, aber immer nur einzeln. Und wenn ich dann Matrix -> Euler -> Matrix berechne, kommt da nicht wieder die Ursprungsmatrix raus, sondern etwas ganz anderes. Es spielt ja auch irgendwie die RotationOrder eine Rolle.
Hat jemand zufällig fehlerfreie Routinen dafür?
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Matrix 2 Euler - Euler 2 Matrix

Beitrag von Krishty »

Eulerwinkel und Quaternions verbrauchen gleich viel Speicherplatz, nur dass Quaternions viel einfacher zu verarbeiten sind. Bleib lieber beim Quaternion.

Was du vielleicht noch nicht bemerkt hast, ist, dass Quaternions für 3D-Rotation immer normalisiert sind (also die vierte Komponente aus 1 - i² - j² - k² berechnet werden kann). Das geht auf den ersten Blick wegen dem Vorzeichen nicht; auf den zweiten dann aber schon, weil Q == -Q. Wenn die vierte Komponente also negativ ist, negier alle vier Komponenten und jetzt hast du die selbe Rotation, aber mit positiven Zahlen, und kannst eine Komponente wegschmeißen. Dürfte bei gleichem Speicherverbrauch *deutlich* schneller sein als Eulerwinkel.

Crytek hatte da vor Jahren mal ein Paper zu, wie sie Quaternions in ihren Texturen komprimieren.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Zudomon
Establishment
Beiträge: 2253
Registriert: 25.03.2009, 07:20
Kontaktdaten:

Re: Matrix 2 Euler - Euler 2 Matrix

Beitrag von Zudomon »

Das hatte ich auch schonmal gehört und wollte auch erst Quaternionen nehmen. Hab mir auch ein bisschen was durchgelesen und wieder mal so gar nichts verstanden. Und wenn ich mir dann Rotationsquaternionen angeschaut habe, hab ich da nicht gesehn, was man weg schmeißen kann, weil ich davon ausgegangen bin, dass dann einer der erste oder letzte wert irgendwie 1 oder 0 oder so ist.
Also dann nehme ich natürlich auch Quaternionen...
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Matrix 2 Euler - Euler 2 Matrix

Beitrag von Krishty »

Jau. Hier ist nochmal das Paper:
http://crytek.com/download/izfrey_siggraph2011.pdf
We can compress a Quaternion down to three elements by
making sure one of the them is greater than or equal to zero

    if (q.w < 0)
        q = -q


We can then rebuild the missing element with

    q.w = sqrt(1 – dot(q.xyz, q.xyz))
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4254
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Matrix 2 Euler - Euler 2 Matrix

Beitrag von Chromanoid »

Das ist alter Java-Code von mir, um eine Quaternion in ein 32bit-int zu packen (die gleichte Logik wie von Krishty beschrieben). Vielleicht kannst Du ja was damit anfangen. Ich hab das soweit ich mich erinnere aus Game Programming Gems 1... 10bit pro Dimension und 2 bit um anzugeben, welche Komponente wegfällt. Ziemlich wenig getestet...

Code: Alles auswählen

    SMALLEST_THREE(4) {
        private final float HALF_QUAT_RANGE = (float) (1f / Math.sqrt(2));

        @Override
        public void readRot(DataInput in, Quat4f outRot) throws IOException {
            int data = in.readInt();
            int biggestComponent = (data >>> 30) & 3;
            if (biggestComponent == 0) {
                outRot.y = unscale((data >>> 20) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.z = unscale((data >>> 10) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.w = unscale((data) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.x = (float) Math.sqrt(1 - outRot.y * outRot.y - outRot.z * outRot.z - outRot.w * outRot.w);
            } else if (biggestComponent == 1) {
                outRot.x = unscale((data >>> 20) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.z = unscale((data >>> 10) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.w = unscale((data) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.y = (float) Math.sqrt(1 - outRot.x * outRot.x - outRot.z * outRot.z - outRot.w * outRot.w);
            } else if (biggestComponent == 2) {
                outRot.x = unscale((data >>> 20) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.y = unscale((data >>> 10) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.w = unscale((data) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.z = (float) Math.sqrt(1 - outRot.x * outRot.x - outRot.y * outRot.y - outRot.w * outRot.w);
            } else if (biggestComponent == 3) {
                outRot.x = unscale((data >>> 20) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.y = unscale((data >>> 10) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.z = unscale((data) & 1023, HALF_QUAT_RANGE, 1023);
                outRot.w = (float) Math.sqrt(1 - outRot.x * outRot.x - outRot.y * outRot.y - outRot.z * outRot.z);
            }
            outRot.normalize();
        }

        @Override
        public void writeRot(DataOutput out, Quat4f inRot) throws IOException {
            float norm;
            float x, y, z, w;

            x = inRot.x;
            y = inRot.y;
            z = inRot.z;
            w = inRot.w;

            int data = 0;
            if (x >= y && x >= z && x >= w) {
                data |= scaleClamp(y, HALF_QUAT_RANGE, 1023) << 20;
                data |= scaleClamp(z, HALF_QUAT_RANGE, 1023) << 10;
                data |= scaleClamp(w, HALF_QUAT_RANGE, 1023);
            } else if (y >= x && y >= z && y >= w) {
                data |= 1 << 30;
                data |= scaleClamp(x, HALF_QUAT_RANGE, 1023) << 20;
                data |= scaleClamp(z, HALF_QUAT_RANGE, 1023) << 10;
                data |= scaleClamp(w, HALF_QUAT_RANGE, 1023);
            } else if (z >= x && z >= y && z >= w) {
                data |= 2 << 30;
                data |= scaleClamp(x, HALF_QUAT_RANGE, 1023) << 20;
                data |= scaleClamp(y, HALF_QUAT_RANGE, 1023) << 10;
                data |= scaleClamp(w, HALF_QUAT_RANGE, 1023);
            } else {
                data |= 3 << 30;
                data |= scaleClamp(x, HALF_QUAT_RANGE, 1023) << 20;
                data |= scaleClamp(y, HALF_QUAT_RANGE, 1023) << 10;
                data |= scaleClamp(z, HALF_QUAT_RANGE, 1023);
            }
            out.writeInt(data);
        }
    }

    protected final int scaleClamp(float value, float halfRange, int newRange) {
        float result = (value) / (2 * halfRange) + 0.5f;
        if (result < 0f) {
            return 0;
        }
        if (result > 1f) {
            return newRange;
        }
        return (int) (result * newRange);
    }

    protected final float unscale(int value, float halfRange, int oldRange) {
        return (value * halfRange * 2f / oldRange - halfRange);
    }
Benutzeravatar
Zudomon
Establishment
Beiträge: 2253
Registriert: 25.03.2009, 07:20
Kontaktdaten:

Re: Matrix 2 Euler - Euler 2 Matrix

Beitrag von Zudomon »

Danke euch beiden! Ich schau mal...
@Krishty, mist, hätte ich mal eher hier nochmal reingeschaut. Jetzt hatte ich es mir schon selbst "ersucht" :D
Ach ich bin so fauli... ist ja auch warm
Antworten