FPS - Kameraproblem (OpenGL)



  • Hallo Leute,
    ich versuche zurzeit einen kleinen Shooter mit OpenGl in Java, mit der LWJGL-Bibliotek zu programmieren.
    Momentan scheitert es leider an der Kamera, aber ich bin mir nicht bewusst, was ich falschmache.

    GL11.glRotatef(berechneRotation(Mouse.getX()),  0, 1, 0); 
    GL11.glTranslatef(0, 0, posZ);
    

    Ich habe mir bei dem Code eigentlich gedacht, dass sich die Kamera um die X-Achse dreht und dann basierend auf dieser Drehung sich die Kamera in die Blickrichtung bewegt.
    Aber gegen meine erwartungen, bewegt die Kamera sich auf einer Geraden und die Blickrichtung bewegt sich je nachdem wo man hinsiet.
    Also zusammengefasst: ich kann mich umschauen, doch ich laufe nicht in die Richtung, in die ich sehe.
    Im nehe Tutorial wurde es auch so gelöst wie bei mir, darum verstehe ich nicht, was ich falsch mache.

    Ich hoffe ihr könnt mir helfen, sonst werde ich noch wahnsinnig^^
    Vielen Dank schonmal.

    Mfg,
    Mick



  • Vertausch mal die Rotate/Translate Reihenfolge.



  • Das bringt leider auch nichts, dann ist der Blick nämlich immer ins Zentrum zentriert.

    ich hatte den Code für das laufen als erstes so:

    player.posZ(player.posZ()-speed);
    

    dass hatte nichts gebracht.

    player.posX(player.posX()-speed*(float)Math.sin(Math.toRadians(player.yrot())));
    player.posZ(player.posZ()-speed*(float)Math.sin(Math.toRadians(player.yrot())));
    

    Wenn ich es so mache dann bewege ich mich irgentwie Schwräg, aber nicht in Blickrichtung.

    EDIT:
    ich habe den Fehler jetz gefunden, es sollte so heisen:

    player.posX(player.posX()-speed*(float)Math.sin(Math.toRadians(player.yrot())));
    player.posZ(player.posZ()+speed*(float)Math.cos(Math.toRadians(player.yrot())));
    

    ich habe bei dem oberen Beispiel ausversehen zwei mal Sinus.



  • player.posX(player.posX()-speed*(float)Math.sin(Math.toRadians(player.yrot())));
    player.posZ(player.posZ()+speed*(float)Math.cos(Math.toRadians(player.yrot())));

    Sicher, dass das so stimmt? Du ziehst hier von [m] etwas in [m/s] ab - macht eigentlich keinen Sinn.



  • es funktioniert so wie ich das möchte, von daher nehme ich mal an, dass es stimmt^^



  • Hallo,
    ich melde mich nochmal wegen einem kleine Problem mit der Kamera.^^
    ich hab nämlich jetz versucht sie um eine weitere Dimension auszubauen (ich will ein kleines Weltraumspiel machen).

    Das Problem jetz ist, dass wenn ich um 180 Grad auf X-achste drehe (also auf dem Kopfstehe), dann ist die Steuerung für links und rechts invertiert, ebenso wie das vorwärts und rückwärts laufen.

    Wenn ich mich um 90 Grad um die X-achse drehe (also direkt nach oben schaue) und dann versuche mich nach rechts un links zu drehen, dann drehe ich mich lediglich um einen Punkt und nicht nach links oder rechts.^^

    Ich hoffe ihr versteht was ich meine.

    Hier ist mein Code zum Bewegen (Tastatur - vorwärts und rückwärts):

    if(W){
    		    player.posX(player.posX() - (float)Math.sin(player.yrot() / 180 * 3.141592654f)) ;
    		    player.posZ(player.posZ() + (float)Math.cos(player.yrot() / 180 * 3.141592654f)) ;
    		    player.posY(player.posY() + (float)Math.sin(-(player.xrot() / 180 * 3.141592654f))) ;	
    		}
    		if(S){
    		    player.posX(player.posX() + (float)Math.sin(player.yrot() / 180 * 3.141592654f)) ;
    		    player.posZ(player.posZ() - (float)Math.cos(player.yrot() / 180 * 3.141592654f)) ;
    		    player.posY(player.posY() - (float)Math.sin(-(player.xrot() / 180 * 3.141592654f))) ;
    		}
    

    Und hier der Code für die drehung (Maus - yaw und pitch):

    //drehung um die X-Achse
    				player.xrot(player.xrot()+(pMouseX*pSensX));		
    				if(player.xrot()>360) player.xrot(0);
    				if(player.xrot()<-360) player.xrot(0);		
    
    			// drehung um die Y-Achse:
    				player.yrot(player.yrot()+pMouse>*pSensY);
    				if(player.yrot()>360) player.yrot(0);
    				if(player.yrot()<-360) player.yrot(0);
    

    pMouse ist die Diverenz der letzen Maus Bewegung.
    pSenseist die empfindlichkeit der Maus

    Habt ihr irgentwelche Ideen wie ich das Problem lösen kann?
    Vielen Dank schonmal.

    Mfg,
    Mick



  • mick1114 schrieb:

    Wenn ich mich um 90 Grad um die X-achse drehe (also direkt nach oben schaue) und dann versuche mich nach rechts un links zu drehen, dann drehe ich mich lediglich um einen Punkt und nicht nach links oder rechts.^^

    Das liegt daran, dass du eine Achse nicht mitrotierst. Das macht man üblicherweise auch nicht, damit unten immer unten und oben immer oben bleibt. Wenn du im Weltraum bist und das nicht möchtest (z.B. weil es eh kein unten und kein oben gibt), musst du um die lokale Achse (also die deiner Kamera, bzw. deines Objekts) rotieren.



  • kanst du mir sagen wie ich das mache?
    momentan sieht es bei mir so aus

    GL11.glRotatef(rotY, -1, 0, 0); 
    GL11.glRotatef(rotX,  0, 1, 0);
    GL11.glRotatef(rotZ,0, 0, 1);
    GL11.glTranslatef(playerX,playerY,playerZ);
    

    Wie meinst du das mit "eine Achse nicht mitrotiert" ? Meinst du das bezogen auf die Z-achse? Die war ja in dem Code oben nicht berücksichtigt (diese wird bei mir mit Q und E veränder um eine Rollen mit dem Schiff zu machen^^)



  • kann mir das jemand nochmal ein bisschen erklären? oder mir einen vernünftigen Suchbegriff geben? Mit "opengl camera" oder "opengl fps camera" komm ich vom Wissen her nur auf den gleichen Stand, wie ich jetz bin.



  • Na, du musst halt die Z-Achse mitrotieren. (Oder die Y-Achse, je nach dem, welche Achse du jetzt nicht mitrotierst.)
    Sagen wir mal (0, 1, 0) ist oben. Wenn du jetzt im 90° Winkel nach oben schaust, und die Y-Achse nicht mitrotierst, dann bleibt oben (0, 1, 0). Wenn du jetzt zur Seite schauen möchtest, rotierst du um die Y-Achse. Wenn diese aber deiner Blickrichtung entspricht (da du ja nach oben, also entlang der Y-Achse schaust), rotierst du quasi um die lokale Z-Achse. (Z sei vorne.)
    Deshalb: Du musst alle Achsen mitrotieren.



  • Danke für die Info. Muss ich das dann irgentwie mit Matrizen realisieren? bzw eine andere Möglichkeit gibt es ja nicht oder?



  • mick1114 schrieb:

    Danke für die Info. Muss ich das dann irgentwie mit Matrizen realisieren? bzw eine andere Möglichkeit gibt es ja nicht oder?

    Na ja, schon. Du musst dir halt überlegen, wie du die Rotation der Kamera speicherst. Prinzipiell gibt's da wohl 4 Möglichkeiten:
    1. Rotation um x, y, z Achsen speichern.
    2. Vorne und oben Vektor speichern. (Zwei Vektoren reichen da, den dritten bekommst du über das Kreuz bzw. Vektorprodukt.)
    3. Matrix. Wobei das eigentlich auch nur Vektoren sind, aber du kannst halt hübsche Rotationsmatritzen bauen.
    4. Quaternionen. Meine Empfehlung. Sehr einfach, sobald man das einmal halbwegs verstanden hat und gleichzeitig spaarsam im Speicherverbrauch (4 float) und schnell in der Ausführung. (.. klingt wie ein Werbespruch. :D)

    http://db-in.com/blog/2011/04/cameras-on-opengl-es-2-x/



  • Vielen Dank!
    Ich melde mich wieder, wenn es geklappt hat^^



  • Ich hab es jetz mal probiert es mit Hilfe deines Links zu programmieren, doch irgenwie will es noch nicht ganz. Ich mach irgentwie wenn ich die Maus bewege eine Kurve.

    Hier ist mal mein Probecode (ich programmiere in Java)

    public class Camera {
    
    	private float[] matrixX=new float[16];
    	private float[] matrixY=new float[16];
    	private float[] matrixZ=new float[16];
    	private float[] result=new float[16];
    
    	public float rot(int pIndex){
    		float rot = 0;
    
    		if(pIndex==0) rot=result[0];
    		if(pIndex==1) rot=result[5];
    		if(pIndex==2) rot=result[10];
    
    		return rot;
    	}
    	public float degreesToRadians(float pDegrees){
    		return pDegrees * 3.14159265f / 180 ;
    	}
    
    	public void matrixIdentity(float[] matrix)
    	{
    	    matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f;
    	    matrix[1] = matrix[2] = matrix[3] = matrix[4] = 0.0f;
    	    matrix[6] = matrix[7] = matrix[8] = matrix[9] = 0.0f;
    	    matrix[11] = matrix[12] = matrix[13] = matrix[14] = 0.0f;
    	}
    
    	public void matrixRotateX(float degrees)
    	{
    	    float radians = degreesToRadians(degrees);
    	    matrixIdentity(matrixX);
    
    	    matrixX[5] = (float)Math.cos(radians);
    	    matrixX[6] = (float)-Math.sin(radians);
    	    matrixX[9] = -matrixX[6];
    	    matrixX[10] = matrixX[5];
    	}
    
    	public void matrixRotateY(float degrees)
    	{
    	    float radians = degreesToRadians(degrees);
    
    	    matrixIdentity(matrixY);
    
    	    matrixY[0] = (float)Math.cos(radians);
    	    matrixY[2] = (float)Math.sin(radians);
    	    matrixY[8] = -matrixY[2];
    	    matrixY[10] = matrixY[0];
    	}
    
    	public void matrixRotateZ(float degrees)
    	{
    	    float radians = degreesToRadians(degrees);
    
    	    matrixIdentity(matrixZ);
    
    	    matrixZ[0] = (float)Math.cos(radians);
    	    matrixZ[1] = (float)Math.sin(radians);
    	    matrixZ[4] = -matrixZ[1];
    	    matrixZ[5] = matrixZ[0];
    	}
    
    	public void cam(){
    		matrixMultiply(matrixX, matrixY);
    		matrixMultiply(result, matrixZ);
    	}
    	public void matrixMultiply(float[] m1, float[] m2)
    	{
    
    	    result[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
    	    result[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
    	    result[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
    	    result[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
    
    	    result[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
    	    result[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
    	    result[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
    	    result[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
    
    	    result[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
    	    result[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
    	    result[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
    	    result[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
    
    	    result[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
    	    result[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
    	    result[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
    	    result[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
    	}
    }
    

    Ich gehe so vor:
    als erstes rufe ich die "matrixRotation" Methoden auf und als Parameter den aktuellen Winkel (zwischen 0 und 360), danch rufe ich die Methode "cam" auf und über gebe die werte an meine Zeichen-Klasse mit der Methode "rot". Danach zeichne ich so:

    GL11.glRotatef(stg.cam(0)*360, 1, 0, 0);
    GL11.glRotatef(stg.cam(1)*360, 0, 1, 0);
    GL11.glRotatef(stg.cam(2)*360, 0, 0, 1);
    

    Bin ich auf dem richtigen Weg? Oder schieße ich total am Ziel vorbei?

    Danke schonmal!
    Gruß,
    Mick



  • Ich habe jetz mit diesen Quaternionen angefangen, also vergesst meinen letzen Post. ^^

    Ich möchte mal nachfragen, ob diese Vorgehensweise richtig ist:

    Ich nehme meine Spieler-Blickrichtung (x,y,z) und wandele dieses in ein Quaternion um, danach wandele ich die Delta-Mausbewegung ebenfalls in ein Quaternion um und Rotiere die Blickrichtung mit um die Delta-Bewegung.
    Das Ergebnis-Quaternion wandle ich wieder zurück in Eulersche Winkel, speichere sie als neue Blickrichtung ab und zeichne die Szene.

    Stimmt das so? Ich habe das nämlich so versucht, habe aber leider immernoch einen gimbal lock. ^^

    Mfg,
    Mick



  • Hey,
    Ich bin langsam am verzweifeln, ich habe gefühlte 1000 Foren und Webseiten durchsucht, aber ich bekomm es immernoch nicht hin eine Kamera ohne Gimbal Lock zu erzeugen.
    Worin könnte nur mein Fehler liegen?

    Ich berechne die Rotation so:

    Quaternion rot = new Quaternion();
    rot.set(DY,DX);
    quat.setIdentity();
    Quaternion.mul(quat, rot, quat);
    

    Das Quaternion quat erzeug ich zu Beginn des Programmes.
    DX und DY sind die Delta Bewegung der Maus.
    Als Quaternion-Klasse verwende ich eine vorgefertigte Klasse. ( http://lwjgl.org/javadoc/org/lwjgl/util/vector/Quaternion.html )

    Danach Zeichne ich die Szene so:

    GL11.glLoadIdentity();
    GL11.glRotatef(quat.x,1, 0, 0);
    GL11.glRotatef(quat.y, 0, 1, 0);
    GL11.glRotatef(quat.z, 0, 0, 1);
    

    Ich habe schon viel rumprobiert, bekomme aber die Kardanische Blockade nicht weg und ich habe keine Ahnung, was ich jetz noch tun soll. Was mach ich falsch?

    Mfg,
    Mick


Anmelden zum Antworten