Aktuelle Zeit: 28.03.2024, 11:19

Alle Zeiten sind UTC + 1 Stunde




Ein neues Thema erstellen Auf das Thema antworten  [ 6 Beiträge ] 
Autor Nachricht
BeitragVerfasst: 06.03.2011, 08:51 
Offline

Registriert: 11.08.2010, 12:05
Beiträge: 20
Hallo auch ich habe folgendes Problem

Ich erstelle gerade ein 3d Game richtung Weltraum nachdem ich wegen Gimbal Lock problemen die Rotationsfunktionen gewechselt habe stehe ich nun vor einem anderen Problem.

Undzwar ist die Player Figur (das Raumschiff) immer auf 0.0.0 positioniert, Rotationen mittels Tasten sind kein Problem ich möchte jedoch das sich das Schiff automatisch nach einem ziel ausrichtet und gegen ende hin wieder in den Künstlichen Horizont neigt (also rotation der Z-Achse 0) das mit dem Künstlichen Horizonz bekomme ich auch soweit hin, allerdings das ausrichten sellt sich als ser schwierig dar, da mir die Irrlicht eigene quaternion klasse ja leider nicht immer eindeutige Eulersche Winkel liefert, beispielsweise bei einer ccw rotation der y achse wobei x = 0 bleibt (bleiben) sollte wird von bis -90 gezählt dann dier bis 0 runter, weil x=0 y= 180 wohl auch als x=180 y = 0 ausgedrückt werden kann wenn mittel matrix oder quertonian rotiert wird.

Das sowohl bei getRotation() als auch bei Quaternions toEuler sowie auch bei den Matrix Methoden. eine Slerp Rotation funktioniert zwar halbwegs aber landet nicht da wo sie landen sollte richtet sich also unterwegs irgendwo Richtung Wallachai aus.

Somit habe ich die einzige mir noch bekannte Möglichkeit ergriffen und quaternions rotationFromTo genommen und mir selbst was geschrieben das klappt auch soweit halbwegs, nur da ich beide achsen mit den funktionen pitch und turn(yaw) rotiere und selbst bei der rotation der achsen eine Z rotation endsteht (was matrix und quertonians multiplikationen wohl gemeinsam haben (leider)) stoppt eine vorzeitig , die andere richtet sich dann noch etwas aus aber der winkel stimmt dann nur halbwegs.

Weis jemand rat? weil ich bin wirklich drauf und dran zu ogre zu wechseln, da mir die vernünftige implementationen, api beschreibungen der funktionen oder beispiele irgendwie fehlen.

EDIT: code könnte ich zwar posten aber da er ohne gesammtproject etwas undirchsichtig ist und das projekt mehrere klassen und tausende zeilen hat die eh keiner durchschaut habe ich drauf verzichtet.


Nach oben
 Profil  
 
BeitragVerfasst: 06.03.2011, 11:03 
Offline
Benutzeravatar

Registriert: 17.04.2007, 08:42
Beiträge: 460
Wohnort: Willich, NRW
Hier wäre aber evtl Code recht nützlich. Evtl kommentieren und versionsverwaltung legen (git) und dann könntest du das iwo hosten (gitorious, github). Aber jedenfalls aus deinem Beitrag lese ich, dass es sich weniger um ein Problem mit Irrlicht sondern viel mehr um ein mathematisches Problem handelt. Denn ich vermute mal, dass die Irrlicht Matrixklassen ihre Arbeit soweit tun. Wichtig ist halt, wie du die zusammengeschustert hast um die Rotation bzw. Ausrichtung zum Ziel zu ermöglichen.

Ansonsten hast du das schon gesehen? http://www.irrlicht3d.de/forum/viewtopic.php?f=6&t=84 Möglicherweise zeig ich dir grade was, was du schon längst als nicht funktionierend herausgefunden hast.

_________________
Bild

Irrlicht - From Noob To Pro A Guideline

--

Sonstige Projekte, Blog : http://www.rpdev.net


Nach oben
 Profil  
 
BeitragVerfasst: 06.03.2011, 14:32 
Offline

Registriert: 11.08.2010, 12:05
Beiträge: 20
Ja getHorizzontalAngle hatte ich zuerst verwendet, klappt aber nicht(mehr) wegen der auf pitch roll, yaw umgestellten Rotation.

ok ich fasse mal hier etwas zusammen da ich wegen dem ganzen rumprobiere erst den source wieder aufräumen müsste.

"this" oder auch my_ShipObject beziehen sich auf eine Klasse welche ISceneNode erweitert

Zuerstmal brauche ich natürlich das quaternion welches die die Transformations des Schiffs beinhaltet dieses initiere ich im Constructor der shipObject Klasse

Code:
    irr::core::matrix4 myMat = this->getAbsoluteTransformation();
    myQuat = quaternion(myMat);


Nun meine aktuellen Funktionen:

Code:
// die ganzen set Rotation´s welche das Quaternione (neben der Tastatursteuerung) nutzen.
void shipObject::setQRotationX(f32 angle)
{
    myQuat = quaternion_fly_pitch(angle);
    this->setRotation(getEuler());

    rotatingSet = true;// wird benötigt wegen des künstlichen Horizontes
    zeroHorizonReached = false;// wird benötigt wegen des künstlichen Horizontes
}

void shipObject::setQRotationY(f32 angle)
{
    myQuat = quaternion_fly_turn(angle);
    this->setRotation(getEuler());

    rotatingSet = true;
    zeroHorizonReached = false;
}

void shipObject::setQRotationZ(f32 angle)
{
    myQuat = quaternion_fly_roll(angle);
    this->setRotation(getEuler());
}


Die entschprechenden Funktion welche ein Quaternion aus der vorgegebnen Rotations änderung basteln.
Code:
quaternion shipObject::quaternion_fly_pitch(f32 angle)//!angle in degree
{
    f32 ang;
    ang = core::degToRad(angle)/2;
    quaternion rotQuat;
    rotQuat.W = cosf(ang);
    rotQuat.X = sinf(ang);
    rotQuat.Y = 0;
    rotQuat.Z = 0;
    quaternion resultQuat;
    resultQuat = multiply_quaternion_right( myQuat, rotQuat);
    return resultQuat;
}

quaternion shipObject::quaternion_fly_roll(f32 angle)//!angle in degree
{
    f32 ang;
    ang = core::degToRad(angle)/2;
    quaternion rotQuat;
    rotQuat.W = cosf(ang);
    rotQuat.X = 0;
    rotQuat.Y = 0;
    rotQuat.Z = sinf(ang);
    quaternion resultQuat;
    resultQuat = multiply_quaternion_right( myQuat, rotQuat);
    return resultQuat;
}

quaternion shipObject::quaternion_fly_turn(f32 angle)//!angle in degree
{
    f32 ang;
    ang = core::degToRad(angle)/2;
    quaternion rotQuat;
    rotQuat.W = cosf(ang);
    rotQuat.X = 0;
    rotQuat.Y = sinf(ang);
    rotQuat.Z = 0;
    quaternion resultQuat;
    resultQuat = multiply_quaternion_right( myQuat, rotQuat);
    return resultQuat;
}


Nun der Quaternion Multiplikator:

Code:
quaternion shipObject::multiply_quaternion_right(quaternion quad1, quaternion quad2)//! rotates a quad, quad1 is the original quad quad 2 the multiplyer
{
    //!myQuad
    f32 qq0,qq1,qq2,qq3;

    qq0 = quad1.W;
    qq1 = quad1.X;
    qq2 = quad1.Y;
    qq3 = quad1.Z;

    //!angle arguments
    f32 argument0,argument1,argument2,argument3;

    argument0 = quad2.W;
    argument1 = quad2.X;
    argument2 = quad2.Y;
    argument3 = quad2.Z;

    quaternion resultQuat;

    resultQuat.W = qq0*argument0-qq1*argument1-qq2*argument2-qq3*argument3;
    resultQuat.X = qq0*argument1+qq1*argument0+qq2*argument3-qq3*argument2;
    resultQuat.Y = qq0*argument2+qq2*argument0+qq3*argument1-qq1*argument3;
    resultQuat.Z = qq0*argument3+qq3*argument0+qq1*argument2-qq2*argument1;

    return resultQuat;
}


Da das Schiff nach so einer Rotation wie bereits beschrieben der Längs-Achse(lokalen Z-Achse) gekippt im Raum steht gibts einen künstlichen horizont der das Schiff langsam wieder auf 0 dreht.

dafür brauchen wir im constructor ein paar variablen und flags, letztere werden ja oben in den setter für die rotation schon gezeigt.

Code:
    //! artifacial horizon
    rotating = false;
    minValue = 0.3f;
    maxValue = 100.0f;
    curChange = maxValue;
    myInertia = 1.025f;

    //!artifacialHorizon timer
    rotationTimer = timer -> getRealTime();
    rotationDelay = 350;
    rotationStartTimer = timer -> getRealTime();
    rotatingSet = false;


da wie am Timer zu erahnen ist der künstliche horizont erst nach der eigentlichen rotation aktiviert wird brauchen wir einen check in der mainloop mit diesem timer (da sonst ein ruckeln endstehen kann bei tastatureigabe oder auch falls die main loop schneller sein sollte als die berechnung der nächsten werte.

Code:
    //!artifacial horizon start
    if (rotatingSet == false)
    {
        rotationTimer = timer -> getRealTime();
    }

    if ((rotationTimer - rotationStartTimer) > rotationDelay)
    {
        rotating = false;
    }

    if (rotatingSet == true)
    {
        rotatingSet = false;
        rotating = true;
        rotationStartTimer = timer -> getRealTime();
        curChange = maxValue;
    }

    if (rotating == false)
    {
        artifacialHorizon();
    }
    //!artifacial horizon end


und natürlich die eigentlich Funktion des Künstlichen Horizontes
Code:
//!wir fügen noch eine normalisierung hier noch eine normalisierung ein die die Y Achse auf 0
//!normalisiert  wenn nicht rotiert wird

void shipObject::artifacialHorizon()
{
    if (rotating == false && zeroHorizonReached == false)
    {
        vector3df myGRot = this->getRotation();
        vector3df myRot;
        myQuat.toEuler(myRot);
        myRot = vector3df(core::radToDeg(myRot.X), core::radToDeg(myRot.Y), core::radToDeg(myRot.Z) );
        f32 curRoll = fmodf(myRot.Z, 360);

        if (myRot.Z != 0)
        {
            if (myRot.Z > 0)
            {
                if (curRoll < 90)
                {
                    if (curRoll < minValue)
                    {
                        this->setQRotationZ( - curRoll );
                        zeroHorizonReached = true;
                    }
                    else
                    {
                        this->setQRotationZ( - (curRoll / curChange) );
                        if (curRoll == 0) zeroHorizonReached = true;
                    }
                }
                if (curRoll >= 90)
                {
                    if (curRoll > (180 - minValue))
                    {
                        this->setQRotationZ(- (180  - curRoll) );
                        zeroHorizonReached = true;
                    }
                    else
                    {
                        this->setQRotationZ( - ( (180 - curRoll) / curChange) );
                        if (curRoll == 180) zeroHorizonReached = true;
                    }
                }

            }
            else if (myRot.Z < 0)
            {
                if (curRoll > -90)
                {
                    if (curRoll > (0 - minValue))
                    {
                        this->setQRotationZ( - curRoll );
                        zeroHorizonReached = true;
                    }
                    else
                    {
                        this->setQRotationZ( - (curRoll / curChange) );
                        if (curRoll == 0) zeroHorizonReached = true;
                    }
                }

                if (curRoll <= -90)
                {
                    if (curRoll < (-180 + minValue))
                    {
                        this->setQRotationZ( - (-180  - curRoll) );
                        zeroHorizonReached = true;
                    }
                    else
                    {
                        this->setQRotationZ(  - ( (-180 - curRoll) / curChange) );
                        if (-curRoll == 180) zeroHorizonReached = true;
                    }
                }

            }

        }

    }

}


weiter im Nächsten Beitrag...


Nach oben
 Profil  
 
BeitragVerfasst: 06.03.2011, 15:04 
Offline

Registriert: 11.08.2010, 12:05
Beiträge: 20
Das ganze funktioniert mit der Tastatureigabe Gimbal Lock frei, die Tastatureingabe sieht ungefähr so aus:
Code:
        if (receiver.keyPressed(KEY_UP) || receiver.keyDown(KEY_UP))
       {
          //!myShip_Node->setRotation( core::vector3df (myShip_Node->getRotation().X - rotSpeed, myShip_Node->getRotation().Y, myShip_Node->getRotation().Z));
          myShip_Node->setQRotationX(-rotSpeed);

       }
       if (receiver.keyPressed(KEY_DOWN) || receiver.keyDown(KEY_DOWN))
       {
           //!myShip_Node->setRotation( core::vector3df (myShip_Node->getRotation().X + rotSpeed, myShip_Node->getRotation().Y, myShip_Node->getRotation().Z));
           myShip_Node->setQRotationX(rotSpeed);

       }
       if (receiver.keyPressed(KEY_LEFT) || receiver.keyDown(KEY_LEFT))
       {
           //!myShip_Node->setRotation( core::vector3df (myShip_Node->getRotation().X, myShip_Node->getRotation().Y - rotSpeed, myShip_Node->getRotation().Z));
           myShip_Node->setQRotationY(-rotSpeed);
       }
       if (receiver.keyPressed(KEY_RIGHT) || receiver.keyDown(KEY_RIGHT))
       {
           //!myShip_Node->setRotation( core::vector3df (myShip_Node->getRotation().X, myShip_Node->getRotation().Y + rotSpeed, myShip_Node->getRotation().Z));
           myShip_Node->setQRotationY(rotSpeed);
       }


das auskommentierte war der vorherige zustand welcher erst gar keine Probleme mittels Z-Rotation zuliess aber zu einem Gimbal Lock führte.

EDIT: ganz vergessen... das ewige toEuler rumgegurke mit der deg/rad umwandlung war mir zu dumm darum gibts auch noch die funktion hier welche oben ja verwendet wird

Code:
//! returns the Eulers
vector3df shipObject::getEuler()
{
    vector3df myRot;
    myQuat.toEuler(myRot);
    myRot = vector3df(core::radToDeg(myRot.X), core::radToDeg(myRot.Y), core::radToDeg(myRot.Z) );
    return myRot;
}


EDIT ende


die jetzte verwendete rotation ist zu vergleichen mit dieser hier aus dem englischen forum http://irrlicht.sourceforge.net/phpBB2/ ... highlight= welche aber auch zu Gimbal locks führen kann.

die Quaternionfunktionen habe ich übrigens von diesen hier übernommen und lediglich in c++ gecoded:
http://www.boristheengineer.co.uk/gamem ... rnions.gml

wie gesagt das ganze funktioniert auch mit einer tastatureingabe.

Mein aktueller Versuch das ganze zu automatisieren sieht so aus:

Code:
bool shipObject::trackToAnimator()
{
    f32 rotSpeed = 0.25;

    if( trackSeeker() && trackToAngleReached == false) //!trackToAngleReachedX and trackToAngleReachedY needs to be done here
    {

    trackTargetPos = trackTargetNode->getAbsolutePosition();
    quaternion rotQuat;
    vector3df fromVect = emptyZ->getAbsolutePosition();
    rotQuat.rotationFromTo(fromVect, trackTargetPos);
    vector3df qte;
    rotQuat.toEuler(qte);
    eulerToTarget = vector3df(radToDeg(qte.X), radToDeg(qte.Y), radToDeg(qte.Z));

    f32 tx = radToDeg(qte.X);
    f32 ty = radToDeg(qte.Y);
    f32 tz = radToDeg(qte.Z);

    f32 rsX;
    f32 rsY;

    f32 ttx = sqrtf(tx * tx);
    f32 tty = sqrtf(ty * ty);

    if ( ttx > tty )
        {
            rsX = rotSpeed;
            rsY = rotSpeed;// / ttx * tty;
        }
        else
        {
            rsX = rotSpeed;// / tty * ttx;
            rsY = rotSpeed;
        }

        f32 myRotX;
        f32 myRotY;

//!x
    if ( tx > 0 && trackToAngleReachedX == false )
    {
        if (tx - rsX < 0)
        {
            myRotX = tx;
            trackToAngleReachedX = true;
        }
        else
        {
            myRotX = rsX;;
        }
    }

    if ( tx < 0 && trackToAngleReachedX == false )
    {
        if (tx + rsX > 0)
        {
            myRotX = -tx;
            trackToAngleReachedX = true;
        }
        else
        {
            myRotX = -rsX;
        }
    }

//!y

    if ( ty > 0 && trackToAngleReachedY == false )
    {
        if (ty - rsY < 0)
        {
            myRotY = ty;
            trackToAngleReachedY = true;
        }
        else
        {
            myRotY = rsY;
        }
    }

    if ( ty < 0 && trackToAngleReachedY == false )
    {
        if (ty + rsY > 0)
        {
            myRotY = -ty;
            trackToAngleReachedY = true;
        }
        else
        {
            myRotY = -rsY;
        }
    }

    animateQRotationXY(myRotX, myRotY);

//!setting the vars for Artifacial Horizon
        rotatingSet = true;
        zeroHorizonReached = false;

        if (trackToAngleReachedX == true && trackToAngleReachedY == true)
        {
            trackToAngleReached = true;
        }
        else
        {
            trackToAngleReached = false;
        }
    }

}





Code:
bool shipObject::trackSeeker()//!returns true if trackTargetNode still Exists
{
return true;//just for testreasons
}


Code:
void shipObject::trackTo(shipObject* targetNode)
{
    trackTargetNode = targetNode;
    trackToAngleReached = false;
    trackToAngleReachedX = false;
    trackToAngleReachedY = false;
}


Code:
quaternion shipObject::quaternion_fly_anim(f32 angleX, f32 angleY)//!angle in degree
{
    std::cout << "\n angle x " << angleY;
    f32 angX;
    angX = core::degToRad(angleX)/2;
    quaternion rotQuatX;
    rotQuatX.W = cosf(angX);
    rotQuatX.X = sinf(angX);
    rotQuatX.Y = 0;
    rotQuatX.Z = 0;

    f32 angY;
    angY = core::degToRad(angleY)/2;
    quaternion rotQuatY;
    rotQuatY.W = cosf(angY);
    rotQuatY.X = 0;
    rotQuatY.Y = sinf(angY);
    rotQuatY.Z = 0;

    quaternion resultQuat;
    resultQuat = multiply_quaternion_right( myQuat, rotQuatX);
    resultQuat = multiply_quaternion_right( resultQuat, rotQuatY);
    return resultQuat;
}


Code:
void shipObject::animateQRotationXY(f32 angleX, f32 angleY)
{

    myQuat = quaternion_fly_anim(angleX, angleY);
    this->setRotation(getEuler());

    rotatingSet = true;
    zeroHorizonReached = false;

}


die Tausend versuche dazwischen lasse ich mal aussenvor...

dazwischen gabs natürlich noch die SLERP vaariante:

Code:
    trackTargetPos = trackTargetNode->getAbsolutePosition();
    quaternion rotQuat;
    vector3df fromVect = emptyZ->getAbsolutePosition();
    rotQuat.rotationFromTo(fromVect, trackTargetPos);
    vector3df qte;
    rotQuat.toEuler(qte);
    vector3df qta;
    myQuat.toEuler(qta);
    eulerToTarget = vector3df(radToDeg(qte.X), radToDeg(qte.Y), radToDeg(qte.Z));
    eulerFrom = vector3df(radToDeg(qta.X), radToDeg(qta.Y), radToDeg(qta.Z));


    quaternion resultQuat;
    resultQuat.slerp (eulerFrom, eulerToTarget, 1);
    vector3df qtr;
    resultQuat.toEuler(qtr);
    vector3df resultVect = vector3df(radToDeg(qtr.X), radToDeg(qtr.Y), radToDeg(qtr.Z));
this->setRotation(resultVect);
 


das ganze natürlich auch als langsam animiert aber so oder so bleibt die animation irgendwo mittendrin stehen weil 1 erreicht wird und auch hier bei 1 leibts mitten drin stecken.

emptyZ ist übrigens ein Empty Node der ein child von myShip ist und an position 0.0.1 positioniert ist also in forward richtung des schiffes und sich mit dreht und somit einen aushilfsvector darstellt.

:)

Dazwischen gabs so gefühlte tausend andere versionen die ich zwar ausbuddeln und regenerieren könnte aber naja.


Nach oben
 Profil  
 
BeitragVerfasst: 08.03.2011, 12:04 
Offline
Benutzeravatar

Registriert: 17.04.2007, 08:42
Beiträge: 460
Wohnort: Willich, NRW
Ich hab deinen Post gelesen, bin aber noch nicht zum Antworten gekommen. Nicht dass du hier denkst, es kümmert sich keiner ;) Weiß aber auch nicht, ob ichs im Laufe des Tages heute noch schaffe ~_~"

_________________
Bild

Irrlicht - From Noob To Pro A Guideline

--

Sonstige Projekte, Blog : http://www.rpdev.net


Nach oben
 Profil  
 
BeitragVerfasst: 09.03.2011, 19:47 
Offline

Registriert: 11.08.2010, 12:05
Beiträge: 20
Mach dir nichts draus ich arbeite momentan (obwohl ich eigentlich gerne quaternions nutzen würde und auch gerne Slerp genutzt hätte) wieder mit Funktionen welche mir garantiert nicht die Z-Achse rotieren, also Roll Pitch Yaw wieder gecanceld, das klappt auch soweit ganz gut solange man nicht mit matrizen, quaternions oder irgenwelchen Z rotationen anfängt.
Die Rotationen des Schiffs sehen dann zwar aus wie ein Kühlschrank den man die Treppe raufträgt aber was solls, sobald ich bei Ogre an dem Punkt bin werd ich sehen wie ich es dort löse und ggf. mal ein paar Tage mit dem umbauen der Quaternionsklasse in Irrlicht verbringen.

Du kannst aber gerne mal wenn du möchstest versuchen die Rotation eines PfeilMeshes via SLERP zu lösen, ist mir nicht gelungen, mein pfeil zeigt dann immer nicht aufs Ziel bei -170, 9, irgendwas rotation zum ziel bleibt mein Pfeil bei -35,120, irgendwas stehen, also so bei 2/3tel des Weges, für einzelne achesn mag Slerp ja gehen aber alle drei gleichzeitig versagt bei mir zumindest(oder ich bin zu dumm dafür).

Wie gesagt arbeite ich mich auch in Ogre rein und muss mal ganz klar loswerden das der Umfang von Ogre überwältigend aber das Design ist nicht so schön wie das von Irrlicht (mein Standpunkt), die Community iss auch nicht so das wahre, ich denke ich werde beide Sachen mal nebeneinander entwickeln, dauert halt etwas länger und ist eine riesige Umstellung im Denken.

Danke trotzdem für deine Mühe.


Nach oben
 Profil  
 
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 6 Beiträge ] 

Alle Zeiten sind UTC + 1 Stunde


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de