Irrlicht - Simple Kamera



  • Huhu,

    ich habe nun mit Irrlicht angefangen, da ich es schon ein bisschen kenne. Ich habe mir ein paar Tutorials auf deren HP angesehen und wollte mir eine Welt mit zufälligen Objekten machen, durch die man sich mit WASD bewegen kann. W und S funktioniert, solange man nicht A und D drückt. Bei A und D dreht sich meine Kamera seltsamerweise. Wenn man nichts macht und nur W drückt, geht meine Kamera vorwärts, bis sie sich irgendwann ganz plötzlich komplett umdreht.

    Die Bewegung mache ich so:

    if(receiver.isKeyDown(irr::KEY_KEY_W))
                                    pos.Z += camspeed * delta;
    
                            if(receiver.isKeyDown(irr::KEY_KEY_S))
                                    pos.Z -= camspeed * delta;
    
                            if(receiver.isKeyDown(irr::KEY_KEY_A))
                                    pos.X -= camspeed * delta;
    
                            if(receiver.isKeyDown(irr::KEY_KEY_D))
                                    pos.X += camspeed * delta;
    
                            camera->setPosition(pos);
    

    Ich verändere doch nur meine Position, wie kann sich da die Kamera drehen?! Suche nun seit 1 Stunde den Fehler 😞

    Hier noch der ganze Code (KeyboardListener ist fast identsich mit dem aus dem Tutorial): http://ideone.com/kYDxp

    Grüße,
    PI



  • Guck dir mal scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS an.



  • Ich will aber nicht so eine Kamera, ich will eine Kamera, die sich mit WASD bewegen und später mit Pfeiltasten drehen lässt.



  • Zu deinem Problem:
    Deine Kamera hat eine Position und einen Punkt auf den sie schaut. Jetzt überleg mal was passiert, wenn du nur die Position änderst. 🙂



  • Okay, an das Target hab ich überhaupt nicht gedacht. Danke, das hat mein Problem gelöst 🙂

    Gibts vielleicht eine Kamera ohne Target?



  • 314159265358979 schrieb:

    Gibts vielleicht eine Kamera ohne Target?

    Wie stellst du dir das vor, wo soll die denn hingucken? Eine Kamera die das Target irgendwie automatisch mitbewegt hat Irrlicht glaube ich nicht. Sollte aber nicht schwer zu implementieren sein, wenn du dich einmal frei im Raum bewegen kannst. Denn so wie du das jetzt machst funktioniert das nicht, du musst über das Target das aktuelle "Vorne" bestimmen, wenn du W drückst.



  • Dass ich da noch den Winkel berücksichtigen muss, weiß ich schon. Eine Kamera ohne Target, wo ich einfach die Drehwinkel angebe...



  • 314159265358979 schrieb:

    Dass ich da noch den Winkel berücksichtigen muss, weiß ich schon. Eine Kamera ohne Target, wo ich einfach die Drehwinkel angebe...

    Wie gesagt ich glaube nicht, dass Irrlicht so etwas kennt. Bewege das Target halt einfach mit der Kamera mit.



  • So, ich habe mich nun mithilfe eines Blatt Papiers gespielt, die Drehung der Kamera und die Steuerung in den Richtigen Winkeln hinzubekommen. Auf dem Papier funktionierts, aber im Code dann doch irgendwie nicht. Und zwar funktioniert das nach oben sehen nicht so, wie ichs gerne hätte.

    if(receiver.isKeyDown(irr::KEY_KEY_W))
                                    campos += camspeed * delta * camtarget;
    
                            if(receiver.isKeyDown(irr::KEY_KEY_S))
                                    campos -= camspeed * delta * camtarget;
    
                            if(receiver.isKeyDown(irr::KEY_KEY_A))
                                    campos.X -= camspeed * delta; // todo : winkel einbauen
    
                            if(receiver.isKeyDown(irr::KEY_KEY_D))
                                    campos.X += camspeed * delta; // todo : winkel einbauen
    
                            if(receiver.isKeyDown(irr::KEY_LEFT))
                            {       
                                    rothor -= rotspeed * delta;
    
                                    camtarget.X = sin(rothor);
                                    camtarget.Z = cos(rothor);
                            }
    
                            if(receiver.isKeyDown(irr::KEY_RIGHT))
                            {
                                    rothor += rotspeed * delta;
    
                                    camtarget.X = sin(rothor);
                                    camtarget.Z = cos(rothor);
                            }
    
                            if(receiver.isKeyDown(irr::KEY_UP))
                            {
                                    rotvert += rotspeed * delta;
    
                                    camtarget.Y = sin(rotvert);
                            }
    
                            if(receiver.isKeyDown(irr::KEY_DOWN))
                            {
                                    rotvert -= rotspeed * delta;
    
                                    camtarget.Y = sin(rotvert);
                            }
    

    Die Kamera dreht sich nach oben, jedoch kehrt sie nach 45° wieder um, was ja auch nicht verwunderlich ist, da sinus. Ich will aber, dass man mit meiner Kamera bis ganz hinauf und ganz hinunter sehen kann, auch darüber hinaus wäre nett. Wie macht man das?



  • Mach's doch einfach wie bei der Drehung in der x1x3-Ebene, nur halt in der x1x2-Ebene. Und deine Y-Koordinate sollte der Kosinus sein, nicht der Sinus, denke ich.
    Funktioniert übrigens alles nur wenn du von den Einheitsvektoren ausgehst.



  • ntrnt schrieb:

    Mach's doch einfach wie bei der Drehung in der x1x3-Ebene, nur halt in der x1x2-Ebene.

    Was ist denn das? 😞

    ntrnt schrieb:

    Und deine Y-Koordinate sollte der Kosinus sein, nicht der Sinus, denke ich.

    Also auf meinem Papier kommt da der Sinus raus.

    ntrnt schrieb:

    Funktioniert übrigens alles nur wenn du von den Einheitsvektoren ausgehst.

    Schon klar, camtarget hat immer die Länge 1.



  • Entschuldige, ich dachte das wäre geläufig, aus der Oberstufe o.ä. Wenn du dort noch nicht warst (was mich wundern würde), oder ihr das anders eingeführt habt, dann heißt das wohl: x1 = X, x2 = Y, x3 = Z.
    Die x1x3-Ebene ist also die XZ-Ebene (also die, die von der X- und der Z-Achse aufgespannt wird), für die x1x2-Ebene verhält es sich analog.

    In der Horizontalen (also in der x1x3-Ebene, XZ-Ebene oder wie auch immer du sie nennen willst) berechnest du die neue X-Koordinate wie bekannt mit dem Sinus, die neue Z-Koordinate mit dem Kosinus (http://upload.wikimedia.org/wikipedia/commons/e/e3/Einheitskreis_Ani.gif). Sobald du in die Vertikale gehst, machst du es anders. Du vergisst, dass camtarget ja um dich herum rotieren soll, und dein camtarget bewegt sich einfach nur periodisch auf und ab, wie du schreibst. Aber es soll sich ebenso periodisch von vorne nach hinten bewegen. Und dann haben wir einen Kreis, genau wie in der Horizontalen.

    Ich weiß übrigens nicht wie dein Papier aussieht, eventuell reden wir auch gerade aneinander vorbei. Ich weiß auch nicht, wie das mit Irrlicht funktioniert, aber wenn dein Code nur ansatzweise so funktioniert wie ich das von ihm denke, dann sollte da auch der Fehler liegen.



  • Mit 3D Grafik haben wir uns in der Schule nicht beschäftigt, werden wir wahrscheinlich auch nicht. (Als nächstes kommen Folge+Reihen/Differentialrechnung/Integralrechnung) Ja, die Achson sind mir als XYZ und die Ebenen XY, XZ und YZ geläufig, danke 🙂

    Im nächsten Absatz kann ich dir leider nicht mehr folgen. Ich möchte kein periodisches Verhalten. Wenn sich die Kamera immer weiter raufdreht, soll es kein Ende geben, man soll sich einfach einmal rumdrehen können (bzw auch mehrmals). Bei der Drehung auf der Horizontalen klappt das ja schon wunderbar.

    Aber ich glaube, ich habe nun die Idee - dank deiner Grafik. Ich muss den XZ Vector mit cos(rotvert) multiplizieren, denke ich.



  • Okay, alles Mist, nochmal von vorne. Mir ist bewusst geworden, dass das, was ich möchte, eigentlich eine relative Drehung ist. Soll heißen, wenn sich das Raumschiff nach oben dreht, sind Drehungen an den Achsen falsch, da sich alle Richtungen ändern. Das heißt, ich muss dan "Target-Vector" der Kamera auch relativ drehen. Wie kann ich sowas machen?



  • Naja, Computergrafik ist ja sehr eng mit analytischer Geometrie (so haben wir es damals genannt, Vektorrechnung einfach) verwoben. Aber egal.

    Doch, du möchtest periodisches Verhalten. Wenn du dich einmal drehst, dann möchtest du dich ja nochmal drehen können. Und nochmal. Und nochmal...klingelt's? 🙂

    Ich weiß nicht genau was du willst, aber so wie ich das sehe ist das ist alles nicht ganz so trivial. Prinzipiell würde ich mir mal http://de.wikipedia.org/wiki/Drehmatrix#Drehmatrizen_des_Raumes_R.C2.B3 ansehen, insbesondere den letzten Abschnitt. Sobald aber Eulerwinkel ins Spiel kommen, kommt auch das Gimbal Lock ins Spiel.
    Um das zu umgehen, siehe http://de.wikipedia.org/wiki/Quaternion

    Viel Spaß damit 🙂

    PS: Ich rate dir nochmal: Kauf dir ein Mathebuch.



  • 314159265358979 schrieb:

    Okay, alles Mist, nochmal von vorne. Mir ist bewusst geworden, dass das, was ich möchte, eigentlich eine relative Drehung ist. Soll heißen, wenn sich das Raumschiff nach oben dreht, sind Drehungen an den Achsen falsch, da sich alle Richtungen ändern. Das heißt, ich muss dan "Target-Vector" der Kamera auch relativ drehen. Wie kann ich sowas machen?

    Mit Matrizen.

    EDIT: OK, hat ja ntrnt schon geschrieben. /EDIT



  • Du musst beachten, dass du die Rotation wahrscheinlich in Grad vorliegen hast, sin/cos wollen aber Radianten. Hier ein Beispiel (ohne Matrixklasse oder solche Scherze, aber gut zu lesen.)

    const long double pi = 3.1415926535897932384626433832795;
    const float pidiv180 = static_cast<float>(pi / 180.0);
    
      Vec3f transformToLocalSystem(const Vec3f& direction) // Hat jemand eine Idee für einen guten Funktionsnamen? :)
      {
        Vec3f vec = direction;
        float a = vec.y, b = vec.z; // Um X-Achse rotieren
        vec.y = a * cos(pidiv180 * rotation_.x) - b * sin(pidiv180 * rotation_.x);
        vec.z = a * sin(pidiv180 * rotation_.x) + b * cos(pidiv180 * rotation_.x);
        a = vec.x, b = vec.z; // Um Y-Achse rotieren
        vec.x = a * cos(pidiv180 * rotation_.y) + b * sin(pidiv180 * rotation_.y);
        vec.z = -a * sin(pidiv180 * rotation_.y) + b * cos(pidiv180 * rotation_.y);
        a = vec.x, b = vec.y; // Um Z-Achse rotieren
        vec.x = a * cos(pidiv180 * rotation_.z) - b * sin(pidiv180 * rotation_.z);
        vec.y = a * sin(pidiv180 * rotation_.z) + b * cos(pidiv180 * rotation_.z);
        return vec;
      }
    


  • Hallo,

    Ja, heute Nacht wurde mir vieles klar, als ich nochmal im Scherfgen geblättert habe. Dass ich hier eine Rotationsmatrix verwenden muss, ist mir nun auch klar. Im Scherfgen findet sich auch eine schöne Funktion tbMatrixRotationAxis(vector, angle), die einen Vector um eine beliebige Achse rotiert. Genau das, was ich brauche 🙂

    Scherfgen schreibt aber auch, dass man bei einem Richtungsvektor eine transponierte invertierte Rotationsmatrix verwenden soll, allerdings ohne Grund. Muss ich diese verwenden, oder reicht eine gewöhnliche Rotationsmatrix?

    Auch habe ich ein kleines Unverständnis, was den Zusammenhang mit dem Up-Vector und dem Richtungsvector des Raumschiffs angeht. Stimmt es, dass der Up Vector im rechten Winkel auf das Target steht (stehen muss)? Wenn ja, wie kann ich diesen dann ausrechnen? Und außerdem müsste doch die relative X-Achse dann das Kreuzprodukt aus dem Targetvector und dem Upvector sein, oder?

    Mit cooky's Funktion kann ich leider gerade nichts anfangen...



  • 314159265358979 schrieb:

    Mit cooky's Funktion kann ich leider gerade nichts anfangen...

    Die Funktion transformiert einen Vektor des globalen Koordinatensystems in das lokale Koordinatensystem der Kamera. Ist beispielsweise die Z-Achse im globalen Koordinatensystem "vorne" und die Kamera schaut vom Ursprung aus nach (0, 0, -1), wird aus dem Vektor (0, 1, 0) der Vektor (0, -1, 0). Anwendung z.B.:

    void move(const Vec3f& direction)
      {
        position_ += transformToLocalSystem(direction);
      }
    

    Allerdings rate ich dir dringen zu Quaternionen als Rotationsdarstellung, sonst gibt's schnell mal einen Gimbal Lock. Das ist aber leider noch mal eine andere Geschichte.. 🙂



  • So, ich habe die Rotationen ganz alleine hinbekommen 🙂
    Habe es nun über Rotationsmatrizen gelöst, ist tatsächlich ziemlich einfach. Die Bewegung habe ich noch nicht, dürfte aber über Translationsmatrizen nicht besonders schwer sein.

    cooky, lebst du noch? Wieso reagierst du im IRC nicht mehr? Arbeitest du noch immer an der Lösung? 😃


Anmelden zum Antworten