mario::konrad
programming / C++ / sailing / nerd stuff
OpenGL: Tutorial 2 - Tiefentests / Double Buffering
© 2004 / Mario Konrad

Beschreibung

Double-Buffering und vor allem die korrekte Darstellung bei überlappenden und einander verdeckenden Objekten.

Platformen:

Download

Die auf dieser Seite aufgeführten Sourcecodes dürfen uneingeschränkt verwendet, kopiert, verändert und publiziert werden. Jegliche Haftung wird abgelehnt, die Verwendung des hier publizierten Materials geschieht auf eigenes Risiko.

Source: tutorial02.cpp

Paket: tutorial02.tgz

Build und Start

Linux:

$ tar -xzf tutorial02.tgz
$ cd tutorial02
$ make -f Makefile.linux
$ ./tutorial02

Windows/Cygwin:

$ tar -xzf tutorial02.tgz
$ cd tutorial02
$ make -f Makefile.cygwin
$ ./tutorial02

Das Demo

Dieses Demo zeigt im Weselntlichen drei Dinge: Tiefentests (überlappende Objekte), double-buffering und wie man die Seitenverhältnisse bewahren kann auch wenn die Grösse des Fensters ändert. Obwohl dieses Demo noch keine Animationen enthält kann das double-buffering gezeigt werden und auch Vorteile bringen. So wird bei einer komplexen Szene das gesamte Rendering im Hintergrund erledigt und dann alles auf einmal gezeigt. Würde man hier kein double-buffering verwenden könnte man die Szene förmlich entstehen sehen.

Gezeigt wird ein kleines Fenster das vier übereinanderlappende Dreiecke beinhaltet.

Das Programm

Dieses Program ist im wesentlichen gleich dem Tutorial 1. Die kleinen Unterschiede werden hier jedoch erklärt.

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

void display(void)
{

Sobald wir Tiefentests wünschen, müssen wir nicht nur die Farbe löschen, sondern auch die Tiefeninformation. Erreicht wird dies durch die zusätzliche Angabe von GL_DEPTH_BUFFER_BIT.

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Die Polygon-Füll-Definitionen sind gleich, ebenso die Beobachtertransformation.

    glPolygonMode(GL_FRONT, GL_FILL);
    glPolygonMode(GL_BACK, GL_LINE);
    glLoadIdentity();
    gluLookAt(
            0.0,  0.0,  6.0,
            0.0,  0.0,  0.0,
            0.0,  1.0,  0.0);

An Stelle von Striche und Kugeln, zeichnen wir nun Dreiecke. Eine kleine Zugabe: jede Ecke eines Dreiecks hat eine andere Farbe. Den schon oben gezeigten Farbverlauf übernimmt OpenGL, dazu aber weiter unten.

    glBegin(GL_TRIANGLES);
        // triangle 1
        glColor4f(1.0, 0.0, 0.0, 1.0);  glVertex3f(-2.0, -1.0,  0.5);
        glColor4f(0.0, 1.0, 0.0, 1.0);  glVertex3f( 2.0, -1.5, -0.5);
        glColor4f(0.0, 0.0, 1.0, 1.0);  glVertex3f( 2.0, -0.5, -0.5);
        // triangle 2
        glColor4f(1.0, 0.0, 0.0, 1.0);  glVertex3f( 1.0, -2.0,  0.5);
        glColor4f(0.0, 1.0, 0.0, 1.0);  glVertex3f( 1.5,  2.0, -0.5);
        glColor4f(0.0, 0.0, 1.0, 1.0);  glVertex3f( 0.5,  2.0, -0.5);
        // triangle 3
        glColor4f(1.0, 0.0, 0.0, 1.0);  glVertex3f( 2.0,  1.0,  0.5);
        glColor4f(0.0, 1.0, 0.0, 1.0);  glVertex3f(-2.0,  1.5, -0.5);
        glColor4f(0.0, 0.0, 1.0, 1.0);  glVertex3f(-2.0,  0.5, -0.5);
        // triangle 4
        glColor4f(1.0, 0.0, 0.0, 1.0);  glVertex3f(-1.0,  2.0,  0.5);
        glColor4f(0.0, 1.0, 0.0, 1.0);  glVertex3f(-1.5, -2.0, -0.5);
        glColor4f(0.0, 0.0, 1.0, 1.0);  glVertex3f(-0.5, -2.0, -0.5);
    glEnd();

Der kleine Unterschied zu Tutorial 1 ist das double-buffering. Wir müssen nun nach dem glFlush die Buffer tauschen mit glutSwapBuffers. Das ist praktisch schon die ganze Hexerei.

    glFlush();
    glutSwapBuffers();
}

Da wir trotz des sich verändernden Fensters die Seitenverhältnisse behalten wollen, kopieren wir den Code aus der Funktion main in eine eigene Funktion reshape. Ausser dem viewport und der Berechnung des aspect ratio: (GLfloat)w/(GLfloat)h bleibt sich alles gleich.

void reshape(int w, int h)
{
    // define viewport
    glViewport(0, 0, w, h);

    // configuration of projection matrix
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 1.0, 100.0);

    // configuration of model view matrix
    glMatrixMode(GL_MODELVIEW);
}

Die Funktion main ist im Wesentlichen gleich geblieben. Bitte die Zeile 57 beachten, in der wir einige Angaben zur Darstellung an GLUT übergeben. Nicht ganz unwichtig ist auch Zeile 62 in der wir unsere reshape Funktion registrieren.

int main(int argc, char ** argv)
{
    // general initialisation
    glutInit(&argc, argv);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(0, 0);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_ALPHA);
    glutCreateWindow("OpenGL Demo 2");
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);

Bei der Konfiguration brauchen wir nur noch ein Bit zu setzen: GL_DEPTH_TEST und schon ist OpenGL bereit die Objekte richtig darzustellen, ganz gleich in welcher Reihenfolge sie gezeichnet werden. Als kleinen Test könnten Sie die Zeile 66 auskommentieren und dann die Dreiecke vergleichen.

    // configuration
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);

    // go
    glutMainLoop();
    return 0;
}