NeHe - Lektion 11 - Flaggen-Effekt (Wellenbewegung)

Lektion 11



Seid gegrüßt. Für die unter euch wissen wollen, was wir hier machen, schaut euch am Ende mein Demo/Hack an! Ich bin Bosco und ich werde mein bestes geben, euch Leuten beizubringen, wie man animierte sinus-Wellen Bilder macht. Dieses Tutorial basiert auf NeHe's Tutorial Nr. 6 und Sie sollten mindestens dieses Wissen intus haben. Sie sollten den Source herunterladen und das Bild, dass ich im Verzeichnis Data mitgeliefert habe, zu ihren Source Code kopieren. Oder benutzen Sie ihre eigene Textur, wenn Sie eine gültige Größe hat, um als Textur mit OpenGL verwendet zu werden.

Das wichtigste zuerst. Öffnen Sie Tutorial Nr. 6 in Visual C++ und fügen Sie folgende Include-Anweisung direkt hinter den anderen #include Anweisungen ein. Das folgende #include erlaubt es uns, komplexe Mathemetik, wie Sinus und Cosinus zu verwenden.

#include <math.h>                        // Für die Sin() Funktion

Wir werden das Array points benutzen, um die einzelnen x, y und z Koordinaten unseres Gitters zu speichern. Das Gitter ist 45 Punkte mal 45 Punkte groß, wodurch wir 44x44 Qudrate haben. wiggle_count wird benutzt werden, um abzuspeichern, wie schnell die Textur 'gewellt' wird. Jeder zweiter Frame sieht recht gut aus und die Variable hold wird eine Fließkommazahl speichern, um eine flüssige Wellenbewegung der Flagge zur erhalten. Diese Zeilen können am Anfang des Programms eingefügt werden, irgendwo unter der letzten #include-Zeile und bevor der GLuint texture[1] Zeile.

float points[ 45 ][ 45 ][3];                    // Das Array für die Punkte auf unserem Gitter von unserer "Welle"
int wiggle_count = 0;                        // Zähler der benutzt wird um die Geschwindigkeit der Welle zu kontrollieren
GLfloat hold;                            // enthält temporär einen Fließkommawert

Gehen Sie runter zur LoadGLTextures() Prozedur. Wir wollen die Textur namens Tim.bmp benutzen. Finden Sie LoadBMP("Data/NeHe.bmp") und ersetzen Sie es mit LoadBMP("Data/Tim.bmp").

    if (TextureImage[0]=LoadBMP("Data/Tim.bmp"))        // Lade das Bitmap

Nun fügen Sie folgenden Code am Ende der InitGL() Funktion ein, bevor TRUE zurückgegeben wird.

    glPolygonMode( GL_BACK, GL_FILL );            // hintere Seite ist ausgefüllt
    glPolygonMode( GL_FRONT, GL_LINE );            // vordere Seite wird mit Linien gezeichnet

Hier spezifizieren wir lediglich, dass wir die Polygone auf der Hinterseite komplett ausgefüllt haben wollen und die Vorderseitigen Polygine nur mit Linien dargestellt werden sollen. Das hängt haupsächlich vom eigenen Geschmack ab. Das hat was mit der Orientierung der Polygone oder der Richtung der Vertices zu tun. Schauen Sie sich das Red Book für mehr Informationen an. Wenn ich schon dabei bin, lassen Sie mich sagen, dass das Buch die treibende Kraft für mich war, als ich OpenGL gelernt habe, wobei NeHe's Seite nicht zu vergessen ist! Danke NeHe. Kaufen Sie sich 'The Programmer's Guide to OpenGL' von Addison-Wesley. Es ist eine unschätzbare Ressource, jedenfalls ist es das bisher für mich gewesen. Ok, zurück zum Tutorial. Direkt unter dem oberen Code und noch vor dem return TRUE, fügen Sie folgende Zeilen ein.

    // wiederhole für die X-Ebene
    for(int x=0; x// wiederhole für die Y-Ebene
        for(int y=0; y// 'Wende' die Welle auf unser Mesh an
            points[x][y][0]=float((x/5.0f)-4.5f);
            points[x][y][1]=float((y/5.0f)-4.5f);
            points[x][y][2]=float(sin((((x/5.0f)*40.0f)/360.0f)*3.141592654*2.0f));
        }
    }

Dank an Graham Gibbons für den Vorschlag eine Integer Schleife zu benutzen um den Fehler in der Welle auszumerzen.

Die beiden oberen Schleifen initialisieren die Punkte auf unsrem Gitter. Ich initialisiere Variablen in meiner Schleife um Sie in meinem Gedächtnis nur als Schleifen-Variablen zu lokalisieren. Keine Ahnung, ob das Kosher ist. Wir benutzen Interger-Schleifen, um einen eigenartigen Grafikfehler zu vermeiden, der sonst bei der Fließkommaberechnung auftritt. Wir dividieren die X und Y Variablen durch 5 ( z.B. 45 / 9 = 5 ) und subtrahieren 4.5 davon um die "Welle" zu zentrieren. Der selbe Effekt könnte mit einem translate erreicht werden, aber ich bevorzuge diese Methode.

Der endgültige Wert points[x][y][2] Statement ist unser Sinus Wert. Die sin() Funktion erfordert Radians. Wie nehmen unseren Grad-Wert, welcher unser float_x ist und multiplizieren ihn mit 40.0f. Nachdemwir das gemacht haben, müssen wir, um in Radians zu konvertieren, den Grad Wert nehmen, ihn durch 360.0f dividieren, ihn mit Pi multiplizieren (oder einer Näherung) und ihn dann mit 2.0f multiplizieren.

Ich werde die DrawGLScene-Funktion komplett neu schreiben und durch folgenden Code ersetzen.

int DrawGLScene(GLvoid)                        // Zeichne unsere GL Szene
{
    int x, y;                        // Schleifen Variablen
    float float_x, float_y, float_xb, float_yb;        // wird benutzt um die Flagge in kleine Quadrate zu unterteilen

Verschiedene Variablen, um die Schleife zu kontrollieren. Schauen Sie sich den Code unten an, aber die meisten haben keine "spezielle" Bedeutung als die Schleifen zu kontrollieren und Werte temporär zu speichern.

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    // lösche den Bildschirm und den Depth-Buffer    
    glLoadIdentity();                    // Resette die aktuelle Matrix

    glTranslatef(0.0f,0.0f,-12.0f);                // gehe 12 Einheiten in den Bildschirm hinein

    glRotatef(xrot,1.0f,0.0f,0.0f);                // Rotiere auf der X-Achse
    glRotatef(yrot,0.0f,1.0f,0.0f);                // Rotiere auf der Y-Achse
    glRotatef(zrot,0.0f,0.0f,1.0f);                // Rotiere auf der Z-Achse

    glBindTexture(GL_TEXTURE_2D, texture[0]);        // Wähle unsere Textur aus

Sie habe das alles bereits gesehen. Genauso wie in Tutorial Nr. 6, nur dass ich meine Szene etwas weiter weg von der Kamera bewege.

    glBegin(GL_QUADS);                    // fange an unsere Quadrate zu zeichnen
    for( x = 0; x <44; x++ )                // gehe durch die X-Ebene (44 Punkte)
    {
        for( y = 0; y <44; y++ )            // gehe durch die Y-Ebene (44 Punkte)
        {

Starte die Schleife um unsere Polygone zu zeichnen. Ich benutze hier Integers, um die int()-Funktion zu vermeiden, wie ich es vorher getan habe, um die Array-Referenz als Integer zurückgeliefert zu bekommmen.

            float_x = float(x)/44.0f;        // erzeuge einen Fließkomma X Wert 
            float_y = float(y)/44.0f;        // erzeuge einen Fließkomma Y Wert
            float_xb = float(x+1)/44.0f;        // erzeuge einen Fließkomma X Wert+0.0227f
            float_yb = float(y+1)/44.0f;        // erzeuge einen Fließkomma Y Wert+0.0227f

Wir benutzen oben vier Variablen für die Textur-Koordianten. Jedes Polygon (Quadrat im Gitter) hat eine 1/44 x 1/44 große Sektion der Textur die darauf gemapped ist. Die Schleifen spezifizieren den unteren linken Vertex und von da aus addieren wir nur, um an die anderen drei zu kommen ( z.B. x+1 oder y+1 ).

            glTexCoord2f( float_x, float_y);    // erste Textur Koordinate (unten links) 
            glVertex3f( points[x][y][0], points[x][y][1], points[x][y][2] );

            glTexCoord2f( float_x, float_yb );    // zweite Textur Koordinate (oben links)
            glVertex3f( points[x][y+1][0], points[x][y+1][1], points[x][y+1][2] );

            glTexCoord2f( float_xb, float_yb );    // dritte Textur Koordinate (oben rechts)
            glVertex3f( points[x+1][y+1][0], points[x+1][y+1][1], points[x+1][y+1][2] );

            glTexCoord2f( float_xb, float_y );    // vierte Textur Koordinate (unten rechts)
            glVertex3f( points[x+1][y][0], points[x+1][y][1], points[x+1][y][2] );
        }
    }
    glEnd();                        // fertig mit zeichnen der Quadrate

Die obigen Zeilen rufen bloß die OpenGL Funktionen auf, um die Daten zu übergeben, über die wir gesprochen haben. Vier separate Aufrufe für jedes glTexCoord2f() und glVertex3f(). Machen Sie mit folgendem weiter. Beachten Sie, dass die Quadrate im Uhrzeigersinn gezeichnet werden. Das bedeutet, die Seite die Sie sehen werden, ist automatisch die Rückseite. Die Rückseite ist ausgefüllt. Die Vorderseite besteht aus Linien.

Wenn Sie gegen den Uhrzeigersinn zeichnen, würden Sie automatisch die Vorderseite sehen, was bedeuten würde, dass Sie das Gitter mit Textur sehen würden, anstatt die ausgefüllte Seite.

    if( wiggle_count == 2 )                    // wird benutzt um die Welle langsamer zu machen (wird nur jeden 2ten Frame ausgeführt)
    {

Wenn wir zwei Szenen gezeichnet haben, zirkulieren wir unsere Sinus-Werte, damit 'Bewegung' in die Sache kommt.

        for( y = 0; y <45; y++ )            // wiederhole für die Y-Ebene
        {
            hold=points[0][y][2];            // speichere aktuellen Wert links neben der Welle
            for( x = 0; x <44; x++)        // wiederhole für die X-Ebene
            {
                // aktueller Wellen-Wert ist gleich dem Wert rechts
                points[x][y][2] = points[x+1][y][2];
            }
            points[44][y][2]=hold;            // letzter Wert wird der am weitesten Links gespeicherte Wert
        }
        wiggle_count = 0;                // Setze den Zähler zurück auf Null
    }
    wiggle_count++;                        // Inkrementiere den Zähler

Hier speichern wir die ersten Werte jeder Zeile, bewegen die Welle dann um eins nach links, was die Wellenbewegung des Bildes erzeugt. Der gespeicherte Wert wird dann am Ende aufaddiert um eine endlose Welle über die Texturoberfläche zu erzeugen. Dann resetten wir den Zähler wiggle_count, damit unsere Animation fortläuft.

Der obige Code wurde von NeHe modifziert (Feb 2000), um einen Fehler in der Wellenbeweung zu beheben. Die Wellenbewegung läuft nun flüssig.

    xrot+=0.3f;                        // erhöhe die X Rotations Variable
    yrot+=0.2f;                        // erhöhe die Y Rotations Variable
    zrot+=0.4f;                        // erhöhe die Z Rotations Variable

    return TRUE;                        // Springe zurück
}

Standard NeHe Rotation Werte. :) Und das war's. Kompilieren und Sie sollten eine nette rotierende bitmapped 'Welle' haben. Ich weiß nicht, was ich noch sage soll, außer, hui. Das war LANG! Aber ich hoffe Sie konnten mir folgen/etwas mitnehmen. Bei irgendwelchen Fragen, wenn ich noch etwas erklären soll oder Sie mir mitteilen wollen wie Gott-gleich, lol, ich programmiere, sendet mir eine kurze Nachricht.

Das war zwar nicht viel, aber sehr Energie/Zeit-Aufwendig. Dadurch schätze ich nun das Bemühen von NeHe WESENTLICH mehr. Danke allen.

Bosco (bosco4@home.com)

Jeff Molofee (NeHe)

* DOWNLOAD Visual C++ Code für diese Lektion.

* DOWNLOAD Borland C++ Builder 6 Code für diese Lektion. ( Conversion by Christian Kindahl )
* DOWNLOAD C# Code für diese Lektion. ( Conversion by Brian Holley )
* DOWNLOAD Code Warrior 5.3 Code für diese Lektion. ( Conversion by Scott Lupton )
* DOWNLOAD Cygwin Code für diese Lektion. ( Conversion by Stephan Ferraro )
* DOWNLOAD Delphi Code für diese Lektion. ( Conversion by Michal Tucek )
* DOWNLOAD Dev C++ Code für diese Lektion. ( Conversion by Dan )
* DOWNLOAD Euphoria Code für diese Lektion. ( Conversion by Evan Marshall )
* DOWNLOAD Game GLUT Code für diese Lektion. ( Conversion by Milikas Anastasios )
* DOWNLOAD Irix Code für diese Lektion. ( Conversion by Rob Fletcher )
* DOWNLOAD Java Code für diese Lektion. ( Conversion by Jeff Kirby )
* DOWNLOAD Jedi-SDL Code für diese Lektion. ( Conversion by Dominique Louis )
* DOWNLOAD JoGL Code für diese Lektion. ( Conversion by Pepijn Van Eeckhoudt )
* DOWNLOAD LCC Win32 Code für diese Lektion. ( Conversion by Robert Wishlaw )
* DOWNLOAD Linux Code für diese Lektion. ( Conversion by Richard Campbell )
* DOWNLOAD Linux/GLX Code für diese Lektion. ( Conversion by Mihael Vrbanec )
* DOWNLOAD Linux/SDL Code für diese Lektion. ( Conversion by Ti Leggett )
* DOWNLOAD LWJGL Code für diese Lektion. ( Conversion by Mark Bernard )
* DOWNLOAD Mac OS Code für diese Lektion. ( Conversion by Anthony Parker )
* DOWNLOAD Mac OS X/Cocoa Code für diese Lektion. ( Conversion by Bryan Blackburn )
* DOWNLOAD MASM Code für diese Lektion. ( Conversion by Nico (Scalp) )
* DOWNLOAD Visual C++ / OpenIL Code für diese Lektion. ( Conversion by Denton Woods )
* DOWNLOAD Power Basic Code für diese Lektion. ( Conversion by Angus Law )
* DOWNLOAD Pelles C Code für diese Lektion. ( Conversion by Pelle Orinius )
* DOWNLOAD Visual Basic Code für diese Lektion. ( Conversion by Ross Dawson )
* DOWNLOAD Visual Studio .NET Code für diese Lektion. ( Conversion by Grant James )



Deutsche Übersetzung: Joachim Rohde
Der original Text ist hier zu finden.
Die original OpenGL Tutorials stammen von NeHe's Seite.