# Problem mit Kamera (glMultMatrix (OpenGL/ LWJGL)/ Quaternionen)



## mick1114 (21. Nov 2011)

Hallo Leute,
Ich versuche schon seit einer weile verzweifelt eine Kamera ohne gimbal lock zu schreiben, doch irgentwie klappt es nie. Vielleicht könnt ihr mir helfen.

Zur realisierung verwende ich die vorgefertigten classen Matrix4f, Vector4f und Quaternionen von LWJGL.

Mit folgendem Code berechne ich aus der Mausebewegung seit dem letzen Aufruf die Rotation.
Stimmt das soweit?

```
int DX = Mouse.getDX(); //delta Maus Bewegung
        int DY = Mouse.getDY();

        Vector4f axisY = new Vector4f();
            axisY.set(0, 1, 0,DY);
        Vector4f axisX = new Vector4f();
            axisX.set(1, 0, 0, DX);

        Quaternion q1 = new Quaternion();
            q1.setFromAxisAngle(axisX);
        Quaternion q2 = new Quaternion();
            q2.setFromAxisAngle(axisY);

        Quaternion.mul(q1, q2, q1);
        Quaternion.mul(camera,q1,camera);
```

Danach konvertiere ich das daraus resultierende Quaternion zu einer Matrix, mit folgendem Code:


```
public Matrix4f quatToMatrix(Quaternion q){
    double sqw = q.w*q.w;
    double sqx = q.x*q.x;
    double sqy = q.y*q.y;
    double sqz = q.z*q.z;

    Matrix4f m = new Matrix4f();
    // invs (inverse square length) is only required if quaternion is not already normalised
    double invs = 1 / (sqx + sqy + sqz + sqw);
    m.m00 = (float)(( sqx - sqy - sqz + sqw)*invs) ; // since sqw + sqx + sqy + sqz =1/invs*invs
    m.m11 = (float)((-sqx + sqy - sqz + sqw)*invs);
    m.m22 =(float) ((-sqx - sqy + sqz + sqw)*invs);

    double tmp1 = q.x*q.y;
    double tmp2 = q.z*q.w;
    m.m10 = (float) (2.0 * (tmp1 + tmp2)*invs);
    m.m01 = (float) (2.0 * (tmp1 - tmp2)*invs) ;

    tmp1 = q.x*q.z;
    tmp2 = q.y*q.w;
    m.m20 = (float)(2.0 * (tmp1 - tmp2)*invs) ;
    m.m02 = (float)(2.0 * (tmp1 + tmp2)*invs) ;
    tmp1 = q.y*q.z;
    tmp2 = q.x*q.w;
    m.m21 = (float)(2.0 * (tmp1 + tmp2)*invs) ;
    m.m12 = (float)(2.0 * (tmp1 - tmp2)*invs) ;      

    return m;
}
```

Wenn ich die Matrix ausgeben lasse, bekomme ich z.B. soetwas:


> -0.5191307 0.027321965 -0.85425806 0.0
> 0.048408303 -0.9969446 -0.061303165 0.0
> -0.8533229 -0.07317754 0.51622194 0.0
> 0.0 0.0 0.0 1.0



zum Schluss mutlipliziere ich die aktuelle viewMatrix mit der Matrix des Quaternion.

```
java.nio.FloatBuffer fb = BufferUtils.createFloatBuffer(32);
    quatToMatrix(camera).store(fb);
    GL11.glMultMatrix(fb);
```

Mit meinem Code bekomme ich leider nur ein Schwarzes Bild. Wo könnte der Fehler stecken?
Zu Beginn dachte ich, ich würde nur in eine Richtung schaun, in der nichts ist, aber ein Würfel welchen ich um den Nullpunkt gelegt habe und man eigentlich sehen müsste, sehe ich auch nicht (es geht erst wieder, wenn ich loadIdentity mache, aber des könnt ihr euch ja sicher denken^^).

Ich hoffe ihr könnt mir helfen, dieses Problem bringt mich noch zur Verzweiflung.

Danke schonmal!

Gruß,
Mick


----------



## mick1114 (21. Nov 2011)

irgentwie kann ich meinen Post nicht mehr editieren, darum hab ich einfach einen neuen gmacht.

ich habe jetz mal ein bisschen weiter recherchiert und mache mit folgendem code die konvertierung:

```
public Matrix4f getRotationMatrix(){
                Matrix4f ret = new Matrix4f();
               
                float xx      = x * x;
                float xy      = x * y;
                float xz      = x * z;
                float xw      = x * w;
                float yy      = y * y;
                float yz      = y * z;
                float yw      = y * w;
                  float  zz      = z * z;
                float    zw      = z * w;

                ret.m00  = 1 - 2 * ( yy + zz );
                ret.m01  =     2 * ( xy - zw );
                ret.m02  =     2 * ( xz + yw );
                ret.m10  =     2 * ( xy + zw );
                ret.m11  = 1 - 2 * ( xx + zz );
                ret.m12  =     2 * ( yz - xw );
                ret.m20  =     2 * ( xz - yw );
                ret.m21  =     2 * ( yz + xw );
                ret.m22 = 1 - 2 * ( xx + yy );
                ret.m03  = ret.m13 = ret.m23 = ret.m30 = ret.m31 = ret.m32 = 0;
            ret.m33 = 1;
           
            return ret;
        }

}
```

Aber mein Code für die Rotation hat wohl leider doch nicht mein Gimbal Lock Problem gelöst. Ich weis nicht mehr was ich tun soll. Könnt ihr mir irgentwie helfen? Was fehlt, um den Gimbal Lock zu verhindern?

Gruß,
Mick


----------



## Marco13 (21. Nov 2011)

In Zeile 11 müßte es nicht
[c]m.m11 = (float)((-sqx + sqy - sqz + sqw)*invs);[/c]
heißen, sondern
[c]m.m11 = (float)((-sqx + sqz - sqz + sqw)*invs);[/c]

...


...


...


:joke:

Mal im Ernst: Es ist schwer, daran etwas zu erkennen, oder "DEN" Fehler ausfindig zu machen. Es würde vielleicht helfen, wenn du genauer beschreiben würdest, wie sich der Fehler äußert (abgesehen vom schwarzen Bild) d.h. wie du das anwenden willst und welcher Effekt erreicht werden soll....


----------



## mick1114 (21. Nov 2011)

Das mit dem "schwarzen Bild" hat sich nun erledigt, es zeigt nun alles so an wie es soll, doch leider habe ich einen Gimbal Lock. Wenn ich nach untenschaue und die Maus nach rechts bewege rotiert die Kamera um die Y-Achse, ich dachte mein Code würde dies verhindern, tut er leider nicht.

Ziel ist es eine freie Kamera für ein kleines Weltraumspiel zu machen. Was mach ich falsch?


----------



## Marco13 (21. Nov 2011)

Der Gimbal Lock tritt eigentlich nur auf, wenn man eine Rotation z.B. in Eulerwinkeln angibt, und damit für bestimmte Fälle einen Freiheitsgrad verliert. Wenn es um so eine "ganz normale" Kamerasteuerung geht, ist das Problem vermutlich (!) ein anderes. Da braucht man üblicherweise auch nicht so viel mit Quaternionen und Konvertierungen rumzuhantieren. Man hat eine aktuelle Rotation (meintewegen als Matrix). Wenn man die Maus in x-Richtung bewegt, wird diese Rotation (d.h um die y-Achse (!)) von links (!) an die aktuelle Rotationsmatrix dranmultipliziert (y analog dazu). Da gab's schon ein paar Threads dazu. Vielleicht würde ein KSKB helfen.


----------



## mick1114 (23. Nov 2011)

Danke für die Hilfe, die Threads hatte ich schon gesehn, hatte mir aber in dem Moment nicht so viel gebracht. 
Es scheint das es wohl doch mit meinem Code von oben funktioniert, hatte nur in dem Moment die Multiplikationen in einer falschen Reihenfolge.


----------

