[OpenGL] "Textur" dreht sich ungewollt



  • Hallo,

    bei dem versuch, einen Würfel mit unterschiedlichen Flächenfarben zu rotieren(Rotatef) und gleichzeitig zu bewegen (Translatef) komme ich einfach nicht weiter, denn folgendes Problem tritt immer wieder auf (ich habe es inzwischen mit drei unterschiedlichen Ansätzen versucht und immer war es ähnlich):
    In diesem Fall drehen sich die Texturen bei Achsenwechsel, d.h. ich drehen zunächst den Würfel nur um die x-Achse. Wenn ich dann ihn aber um die z-Achse bewege, dann rotieren die Farben, bzw. der Würfel macht eine ziemlich komische Bewegung, die eigentlich nicht vorgesehen ist (die Texturen können sich ja nicht bewegen, da sie nie verändert werden). Dann sind solche Merkwürdigen sachen wie "der würfel dreht sich nach einer eigentlich schon beendeten aktion auf die vorherige rotation -nicht position- zurück und dreht sich zusätzlich noch einmal um die y-achse um 90° gegen den Uhrzeigersinn gedreht.
    In DrawGLScene wird die Rotation wie folgt beschrieben:

    glRotatef((float) zRoll, xaxis, 0.0f, zaxis);
         glRotatef((float) xRoll, xaxis, 0.0f, zaxis);
    

    xRoll und zRoll sind sich während der Rotation erhöhende Werte, die den Winkel beinhalten. Anschließend wird der Würfel gezeichnet mit den Farben.
    Bei der Tastatureingabe wird zunächst die achse, um die gedreht werden soll, festgelegt. Anschließend wird der Rotationswinkel und die Bewegung errechnet.
    zB. für eine Vorwärtsbewegung:

    if(RollWay.up) {  xaxis=1; zaxis=0;
                                                         zRoll-=Inc;
                                                         zmove-=Inc*(2.0f/f)/90.0f; }
                                       if(zRoll%90==0) { RollWay.up=false;}
    

    Rollway.up ist dabei ein boolwert. natürlich gibt es ähnlichen code für runter,links,rechts mit den entspechenden änderungen der xaxis und zaxis-werte (bei links und rechts) und das minus von der zRoll und zmove-Gleichung wird durch ein plus ersetzt (bei runter und rechts).

    Abschließend die Frage (bzw. das Problem wurde oben schon erwähnt):
    Warum dreht sich der Würfel bei einem wechsel von der x auf die z- Achse (und anders herum). (der Würfel dreht sich so schnell um die y-Achse, dass man nur den Sprung der texturen bemerkt. Anschließend wird die Drehung ganz normal ausgeführt, nur eben mit gedrehten texturen.

    Danke schonmal im voraus!



  • Du rotierst Deinen Würfel zweimal um die selbe Achse da sich ja xaxis und zaxis zwischen den Aufrufen an glRotate nicht ändern.
    Richtig wäre:

    glRotatef((float) xRoll, 1.0f, 0.0f, 0.0f);
        glRotatef((float) zRoll, 0.0f, 0.0f, 1.0f);
    


  • Bleibt sich eigentlich gleich (nur das es kürzer ist), es hängt ja davon ab, ob xRoll und zRoll inkrementiet/ dekrementiert werden oder nicht.



  • Hast du's denn mal ausprobiert? Ich würd ja einen Besen essen wenn das wirklich das gleiche wäre. Egal was nun in x- oder zaxis steht: Du rotierst zweimal hintereinander um die selbe Achse!! Einmal mit dem Winkel xRoll und noch einmal mit zRoll. Was auch die 'mysteriöse' 90° Drehung erklärt.



  • Ja, es ist das gleiche. Ich kontrolliere ja noch durch xRoll und zRoll ob überhaupt gedreht werden soll - und es ist ja immer nur eins von beidem aktiv. Daher ist es das selbe (nur wie schon gesagt etwas kürzer, deswegen hab ichs auch schon geändert, aber generll hat sich am fehler nichts getan).



  • Wenn beide wirklich so hintereinander stünden wie du das in Deinem ersten post darstellst, wäre es auch nicht das gleiche. Ich nehme mal an, da liegt evtl. das Missverständniss!?

    Nehmen wir doch mal an, zaxis wäre 1 und xaxis 0, dannn entstünde nach Deinem code von oben folgendes:

    glRotatef((float) xRoll, 0.0f, 0.0f, 1); 
        glRotatef((float) zRoll, 0.0f, 0.0f, 1);
    


  • Hä? wenn ich mir von xRoll und zRoll das verspreche was ich denke, dann wird bei jedem aufruf von glRotatef jedesmal das Objekt um xRoll/zRoll Grad gedreht, unzwar um die Achse (1,0,0) oder (0,0,1) - d.h. entweder x oder z Achse.
    bzw. wiki sagt dazu:

    glRotatef(angle: TGLdouble; x: TGLdouble; y: TGLdouble; z: TGLdouble);

    (ist das bei c++ anders, da es sich hierbei um Delphi handelt? eigentlich dürften sich die ogl funktionen intern nicht verändern....oder ist genau hier der Fehler?)



  • Sag mal, kommst du vllt. mit den Bezeichnungen durcheinander? 😕

    Die nächste Code-Zeile ist neu. glRotatef(Angle,Xvector,Yvector,Zvector) ist verantwortlich, um ein Objekt um eine Achse rotieren zu lassen. Sie werden diesen Befehl ziemlich häufig verwenden. Angle (=Winkel) ist eine Zahl (in der Regel in einer Variable gespeichert), die repräsentiert, wie weit das Objekt gedreht werden soll. Die Parameter Xvector, Yvector und Zvector präsentieren zusammen den Vektor um welchen die Rotation statt findet. Wenn Sie die Werte (1,0,0) verwenden, beschreiben Sie einen Vektor, der sich 1 Einheit entlängs der X-Achse nach rechts bewegt. Die Werte (-1,0,0) beschreiben einen Vektor der in die Richtung einer Einheit entlängs der X-Achse bewegt, aber diesmal nach links.

    D. Michael Traub: hat die obige Erklärung der Xvector, Yvector und Zvector Parameter geliefert.

    Um X, Y und Z-Rotation besser zu verstehen, werde ich sie anhand von Beispielen erklären...

    X-Achse - Sie arbeiten an einer Kreissäge. Der Stab der direkt durch die Mitte des Sägeblatts geht, verläuft von links nach rechts (wie die X-Achse in OpenGl). Die scharfen Zähne rotieren um die X-Achse (den Stabe, der durch die Mitte des Sägeblatts verläuft) und scheint sich auf Sie zu oder weg von Ihnen zu bewegen, je nachdem in welche Richtung das Sägeblatt rotiert. Wenn Sie etwas in OpenGL auf der X-Achse rotieren lassen, wird es genauso rotieren.

    Y-Achse - Stellen Sie sich vor, dass Sie inmitten eines Feldes stehen. Ein gewaltiger Tornado kommt direkt auf Sie zu. Das Zentrum des Tornados verläuft vom Himmel zum Boden (rauf und runter, genauso wie die Y-Achse in OpenGL). Der Schmutz und alles andere in dem Tornado rotiert um die Y-Achse (das Zentrum des Tornados) von links nach rechts oder von Rechts nach links. Wenn Sie etwas in OpenGL auf der Y-Achse rotieren lassen, wird es genauso rotieren.

    Z-Achse - Sie schauen direkt auf einen Fächer. Der Mittelpunkt des Fächers zeigt auf Sie und weg von Ihnen (wie die z-Achse in OpenGL). Die einzelnen Fächer des Fächers rotieren um die Z-Achse (Zentrum des Fächers) im Uhrzeigersinn oder gegen den Uhrzeigersinn. Wenn Sie etwas in OpenGL auf der Z-Achse rotieren lassen, wird es genauso rotieren.

    Demnach würde die folgende Code-Zeile, wenn rtri gleich 7 ist, eine Rotation um 7 auf der Y-Achse (links nach recht) tätigen. Sie können ein wenig mit dem Code herum experimentieren. Ändern Sie die 0.0f in 1.0f und die 1.0f in 0.0f um das Dreieck auf der X und Y Achse zur selben Zeit rotieren zu lassen.

    Es ist wichtig zu beachten, dass die Rotation in Grad vorgenommen wird. Wenn rtri einen Wert von 10 hat, würden wir um 10 Grad auf der Y-Achse rotieren.

    http://www.joachimrohde.com/cms/xoops/modules/articles/article.php?id=8



  • Stier X schrieb:

    Hä? wenn ich mir von xRoll und zRoll das verspreche was ich denke, dann wird bei jedem aufruf von glRotatef jedesmal das Objekt um xRoll/zRoll Grad gedreht, unzwar um die Achse (1,0,0) oder (0,0,1) - d.h. entweder x oder z Achse.

    Naja weiss nicht ob ich das richtig verstehe. Hier nochmal ein Ausschnitt aus dem Zitat von langeweile:

    glRotatef(Angle,Xvector,Yvector,Zvector) ist verantwortlich, um ein Objekt um eine Achse rotieren zu lassen. [..] Angle (=Winkel) ist eine Zahl (in der Regel in einer Variable gespeichert), die repräsentiert, wie weit das Objekt gedreht werden soll. Die Parameter Xvector, Yvector und Zvector präsentieren zusammen den Vektor um welchen die Rotation statt findet.

    Und jetzt versuchs doch einfach mal so:

    if(xaxis)
        glRotatef((float) xRoll, 1.0f, 0.0f, 0.0f);
    if(zaxis)
        glRotatef((float) zRoll, 0.0f, 0.0f, 1.0f);
    


  • Ich habe es jetzt so ausprobiert, konnte das Problem dadurch aber leider nicht beheben.
    Also die Bezeichnungen sind ja gleich. Der erste Parameter bestimmt den Drehwinkel. Der Bleibt solange auf 5 (oder wie schnell auch immer gedreht werden soll), bis xRoll oder zRoll % 90 == 0, d.h. der Würfel hat sich um 90 Grad letztedndlich gedreht. Da es sich hier um eine Funktion handelt, die immer wiederholt wird, wird der Zähler in xRoll z.B immer um 5 erhöht, wenn w oder s gedrücht wurden, bis eben xRoll%90 == 0 gilt. Dann wird xRoll wieder 0, so dass alles so bleibt, bis wieder eine Taste gedrückt wird.

    (xRoll beschreibt die Drehungen auf der z-Achse ; zRoll die Drehungen entlang der x Achse).

    Abgesehen davon dürfte xRoll (wenn =0) keine Auswirkung auf

    glRotatef((float) zRoll, 0.0f, 0.0f, 1);
    

    nehmen, da und anders herum dürfte zRoll keine Auswirkung auf

    glRotatef((float) xRoll, 1.0f, 0.0f, 0.0f);
    

    nehmen. Insofern dreht sich der Würfel immer nur um eine Achse, da xRoll oder zRoll immer nur solange auf 5 gesetzt werden, wie auch für die Drehung nötig ist, d.h. bei 90/5 = 18 bleibt xRoll z.B 18 mal auf 5, dann gilt xRoll%90 == 0 und xRoll wird auf 0 gesetzt.
    D.h. letztendlich wieder, dass ich eigentlich nicht auf xRoll oder zRoll überprüfen muss... aber wo kann dann der Fehler liegen. 😕 😕 (Es ist ja nicht so, dass ich nicht schon seit ein paar Stunden vor dem Problem sitze 😃 )



  • Dann versteh ich dein Problem i-wie nicht...



  • also ich hab das problem folgendermaßen verstanden:

    der würfel wird um 90° gedreht, je nach eingabe entweder um die z-Achse oder die x-Achse.
    Dabei ist wohl das Problem, dass sich die Achsen mitdrehen. D.h. dass bei der nächsten drehung die Achsen vertauscht sind.

    Nehmen wir an, wir drehen den Würfel um 90° im Uhrzeigersinn. Dann bleibt die Z-Achse gleich, aber die X- und die Y-Achse vertauschen sich. Solange man nur rechts und links drehen würde, wäre das ja kein problem.
    Nun will unser Stier aber auch nach vorne und nach hinten rotieren, was jetzt aber schwierig wird, da die Achsen ja vertauscht sind.

    glRotatef((float) zRoll, xaxis, 0.0f, zaxis); 
    glRotatef((float) xRoll, xaxis, 0.0f, zaxis);
    

    Anhand von xaxis und zaxis nehme ich an, dass du schon versucht hast, den Würfel jeweils relativ zu den Achsen zu drehen. Evtl. kannst du mal den code dafür posten...

    Ich glaube was hier gebraucht wird ist irgendwas, was die Mitrotation der Achsen verhindert.

    Ich selber hab da leider nich so viel ahnung von...

    .eraemaajaervi



  • Ja, da hab ich ja schon mehrere versionen ausprobiert. z.b. die nachfolgende:

    int RollCorrect(int zRoll)                             // fixing, around which axis the cube shall rotate
    {
        //signed int sign=zRoll / abs(zRoll);               // when pressen left or right (makes problems, needs to be fixed)
        if(abs(zRoll)== 360) 
        {
                             //zRoll=0; //1*(zRoll%360); 
        }
        if(zRoll >= 0) 
        {
             if(zRoll%270==0) setRollAxis(0,-1,0);  // needs to be negative when degree is negative
             if(zRoll%270!=0 && zRoll%180==0) setRollAxis(0,0,-1);
             if(zRoll%270!=0 && zRoll%180!=0 && zRoll%90==0) setRollAxis(0,1,0); // needs to be negative when degree is positive
             if(zRoll==0) setRollAxis(0,0,1); 
        }
        else 
        {
             if(zRoll%270==0) setRollAxis(0,1,0);  // needs to be negative when degree is negative
             if(zRoll%270!=0 && zRoll%180==0) setRollAxis(0,0, -1);
             if(zRoll%270!=0 && zRoll%180!=0 && zRoll%90==0) setRollAxis(0,-1,0); // needs to be negative when degree is positive
             if(zRoll%360==0 || zRoll==0) setRollAxis(0,0,1); 
        } 
        return 0; 
    }
    

    Der ganze Code prüft eigentlich nur, um welche Achse letztendlich gedreht werden soll, da sich die lokalen achsen ja mitdrehen und so eine drehung nur um x und z achse zu definieren zu rotationsfehlern führen müsste.
    Es gibt noch einen ähnlichen code (etwas ausführlicher), aber der funktioniert genauso wenig.



  • Guck dir mal glPop/PushMatrix an... 😕



  • Oder du versuchst absolut zu drehen und machst vor dem Rendern ein GLLoadIdentity().



  • Mach mal ein Video per Screencapturing, dass man sich auch vorstellen kann, was du meinst 😉



  • leider funktioniert das mit screen capturing unter vista nicht richtig, daher hab ich mal 3 screenshots gemacht, die sollten ausreichen:
    Bild_1
    Bild_2
    Bild_3

    Wie man sieht dreht die textur sich einfach so zurück als wenn nichts passiert ist (die verschiebung bleibt bestehen). und es ist ja auch nicht so, dass ich den winkel, um den gedreht wurde, zurücksetzte...



  • Um es mal etwas konkreter zu machen:
    Download

    Das Problem will einfach nicht weg. Verstehen tu ich das schon lang nicht mehr 😡. An den Variablen kanns nicht mehr liegen, habe jede einzeld überprüft...war ne menge Arbeit. Ich hoffe, jemnad weis noch eine Lösung.

    edit:

    q: runter
    w: vorwärts
    e: rauf
    a: links
    s: zurück
    d: rechts

    VK_UP: Würfel vorwärts
    VK_LEFT: Würfel links
    VK_DOWN: Würfel zurück
    VK_RIGHT: Würfel rechts



  • Stier X schrieb:

    VK_UP: Würfel vorwärts
    VK_LEFT: Würfel links
    VK_DOWN: Würfel zurück
    VK_RIGHT: Würfel rechts

    Liegt vllt in diesen Codestücken der Hund begraben?



  • glaub ich kaum. dennoch:

    if (keys[VK_UP] && keyup[VK_UP] && !RollWay.down && !RollWay.left && !RollWay.right) {
                            RollWay.up = true;
                            }
    keyup[VK_UP]=!keys[VK_UP];
    

    RollWay ist bool und sagt, ob und in welche richtung gedreht wird.
    Analog zu links, runter, rechts.

    if (RollWay.up==true){
                                  Cubeanglex -= IncCube;
                                  }
    

    Cubeanglex beschreibt die Drehung um die x-Achse. IncCube muss ein ganzzahliger Faktor von 90 sein.
    Analog zu links, runter, rechts - bei links und rechts wird mit Cubeanglez gearbeitet.

    if (Cubeanglex%90 == 0 && Cubeanglez%90 == 0 && (RollWay.up || RollWay.down || RollWay.left || RollWay.right)){
                                  RollWay.up = false;
                                  RollWay.down = false;
                                  RollWay.right = false;
                                  RollWay.left = false;
                                  if(Cubeanglex == 360 || Cubeanglex ==-360) Cubeanglex = 0;
                                  if(Cubeanglez == 360 || Cubeanglez ==-360) Cubeanglez = 0;
    

    Setzt alles zurück, wenn die Drehung beendet ist.

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		glLoadIdentity(); // ist dieses das LoadIdentity aus connans Beitrag?
                                // wenn ichs weg mache, ist alles schwarz...
    	glTranslatef(Camera.posx,Camera.posy,Camera.posz);	
           glTranslatef( 0.0f+xmove, 0.0f+ymove,-5.0f+zmove);
        if(RollWay.up || RollWay.down) {glRotatef(Cubeanglex, 1.0f, 0.0f, 0.0f);}
        if(RollWay.left || RollWay.right) {glRotatef(Cubeanglez, 0.0f, 0.0f, 1.0f);}
        DrawCube();
    	return TRUE;					
    }
    

Anmelden zum Antworten