Home
Über JOGL
  Entstehung
  Eigenschaften
  Installation
Tutorial
  Lektion1
  Lektion2
  Lektion3
  Lektion4
  Lektion5  
JOGL vs.
   OpenGL

Links
Impressum

 

 Lektion 3

Grundlagen
Richtungslicht
Punktlicht
Spotlight
Beleuchtung Beispielszene

Zum Download des Quellcodes dieser Lektion: Auf das Bild klicken oder hier.

Grundlagen

In JOGL bestehen Lichter aus einem ambienten, einem diffusen und einem spiegelnden Anteil. Alle drei Anteile haben eine bestimmte Farbe. Diese wird im RGBA-Modell angegeben. Es werden mindestens acht Lichter (Light0 - Light7) unterstützt. Abhängig von der benutzten JOGL-Implementierung kann diese Zahl nach oben variieren. Allerdings sinkt mit der Anzahl der benutzten Lichter auch die Performance.

Der ambiente Anteil der Lichtquelle ist der Lichtanteil, der aus allen Richtungen zu kommen scheint, so daß der Standort des Lichtes nicht mehr auszumachen ist. Ambientes Licht ist deshalb ungerichtetes Licht. Mit rein ambienter Beleuchtung erscheinen Objekte zweidimensional da es in alle Richtungen gleichmässig gestreut wird, wenn es auf eine Oberfläche trifft.

Bei der diffusen Komponenten kommt das Licht aus einer bestimmten Richtung. Wenn es auf eine Oberfläche trifft, wird es in alle Richtungen gleichmässig gestreut. Dadurch erscheint es, unabhängig von der Position des Betrachters, immer gleichmäßig hell.

Der spiegelnde Lichtanteil kommt genau aus einer Richtung und wird in eine vorgegebene Richtung reflektiert. Je nach Beschaffenheit der Oberfläche ergeben die reflektierten Strahlen an einer bestimmten Stelle ein Glanzlicht (Highlight).

Damit JOGL die Beleuchtung berechnen kann, müssen Normalenvektoren angegeben werden, die die relative Position eines Objekts zur Lichtquelle bereitstellen. Wenn vorgefertigte Primitive von GLUT verwendet werden, müssen die Normalen nicht explizit angegeben werden; bei GLU-Primitiven werden die Normalen mit gluQuadricNormals(..) berechnet. Die Beleuchtungsmethoden greifen ausserdem nicht auf die mit glColor*() gesetzten Farben zurück. Stattdessen müssen mit glMaterial*() Materialien definiert werden. Dies wird im nächsten Abschnitt besprochen

Um Lichter in OpenGL benutzen zu können, muss zuerst glEnable(..) mit dem Parameter GL.GL_LIGHTING aufgerufen werden. Zudem ist es wichtig die Sichtbarkeit der Objekte zu bestimmen bzw. ihre relative Position zur Kamera, da ansonsten die Objekte in der Reihenfolge ihrer Erstellung einfach übereinander gezeichnet werden. Um dies zu verhindern, muss z-Buffering mit glEnable(..) und dem Parameter GL.GL_DEPTH_TEST aufgerufen werden. Zudem muss in der Methode glClear zusätzlich das GL.GL_DEPTH_BUFFER_BIT gesetzt werden. In JOGL könnte der Aufruf von glClear() wie folgt aussehen:

gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

Im Folgenden werden drei Arten von Lichtquellen besprochen: Richtungslicht, Punktlicht und Spotlight.

nach oben

Richtungslicht

Ein Richtungslicht beschreibt eine Lichtquelle, die unendlich weit entfernt ist und deren Licht in eine bestimmte Richtung strahlt (z.B. die Sonne). Um ein Richtungslicht zu erstellen, muss in float-Vektoren die Werte für die Position (in eye-Koordinaten) und für die Farbe der verschiedenen Lichtanteile angegeben werden. Standardmässig sind die Werte auf {0.0f, 0.0f, 0.0f, 1.0f} gesetzt. Nur das erste Licht (Light0) bildet eine Ausnahme. Da dort sowohl specular als auch diffuse auf {1.0f, 1.0f, 1.0f, 1.0f} gesetzt sind, muss der entsprechende RGBA-Wert auf {0.0f, 0.0f , 0.0f , 1.0f} gesetzt werden, wenn die Lichtanteile nicht benutzt werden sollen.

Mit der Methode glLight*(..) müssen die Werte an das verwendete Licht übergeben werden. Dabei werden als Parameter die verwendete Lichtquelle, die zu setzende Eigenschaft und der Vektor, in dem die Werte gespeichert werden, übergeben.
Folgendes Code-Beispiel erzeugt ein Richtungslicht mit blauem Ambient-Anteil, rotem Diffuse-Anteil und weissem Specular-Anteil:

float light0_pos[] = {0, -4, 5, 0};
float light0_color_am[] = {0, 0, 1, 1};
float light0_color_diff[] = {1, 0, 0, 1};
float light0_color_spec[] = {1, 1, 1, 1};

gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light0_pos);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, light0_color_am);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, light0_color_diff);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, light0_color_spec);

nach oben

Punktlicht

Im Gegensatz zum Richtungslicht beschreibt ein Punktlicht eine Lichtquelle innerhalb der Szene, die in alle Richtungen gleichmässig strahlt. Ein Beispiel für ein Punktlicht in der realen Welt ist eine Glühbirne.

Die Erzeugung eines Punktlichtes erfolgt ähnlich der Erstellung eines Richtungslichtes, mit der einzigen Ausnahme, dass die w-Koordinate der Position ungleich 0 sein muß.
Folgender Code demonstriert die Implementierung eines Punktlichtes:

float light1_pos[] = {0, -4, 5, 1};
float light1_color_am[] = {0, 0, 1, 1};
float light1_color_diff[] = {1, 0, 0, 1};
float light1_color_spec[] = {1, 1, 1, 1};

gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, light1_pos);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, light1_color_am);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, light1_color_diff);
gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, light1_color_spec);

Desweiteren kann bei einem Punktlicht die Intensität des Lichtes eingestellt werden. Dies geschieht über die Konstanten GL.GL_CONSTANT_ATTENUATION, GL.GL_LINEAR_ATTENUATION und GL.GL_QUADRATIC_ATTENUATION. Diese ergeben zusammen den Abschwächungsfaktor für die Lichtquelle:

Abschwächungsfaktor =
wobei

d = die Distanz zwischen der Position der Lichtquelle und dem Vertex
kc = GL_CONSTANT_ATTENUATION
kl = GL_LINEAR_ATTENUATION
kq = GL_QUADRATIC_ATTENUATION

Je höher der Wert für die Konstanten gewählt wird, desto höher ist der Abschwächungsfaktor. Um den Konstanten Werte zuzuordnen, wird der Befehl glLight(..) mit drei Parametern benötigt. Der erste Parameter bezeichnet die Lichtquelle, für die der Abschwächungsfaktor gesetzt werden soll, der zweite Parameter gibt die zu setzende Konstante an und der dritte enthält den Wert, der der Konstanten zugeordnet werden soll.

Folgender Codeausschnitt setzt für die zweite Lichtquelle die Konstanten auf ihre Defaultwerte:

gl.glLightf(GL.GL_LIGHT1, GL.GL_CONSTANT_ATTENUATION, 1.0f);
gl.glLightf(GL.GL_LIGHT1, GL.GL_LINEAR_ATTENUATION, 0.0f);
gl.glLightf(GL.GL_LIGHT1, GL.GL_QUADRATIC_ATTENUATION, 0.0f);

 

nach oben

Spotlight

Spotlights sind prinzipiell Punktlichter, deren Lichtkegel eingeschränkt sind. Dabei wird eine Gerade vom Mittelpunkt der Lichtquelle zu einem in der Konstanten GL.GL_SPOT_DIRECTION gesetzten Punkt gezogen. Dann wird mit GL.GL_SPOT_CUTOFF der Winkel zwischen dieser Geraden und dem Rand des Lichtkegels definiert. Der Wert für GL.GL_SPOT_CUTOFF sollte kleiner als 180° sein, da bei 180° das Spotlight einem Punktlicht entsprechen würde.

Das folgende Beispiel zeigt, wie ein Spotlight implementiert werden könnte:

float light2_pos[] = {0, -4, 5, 1};
float light2_color_am[] = {0, 0, 1, 1};
float light2_color_diff[] = {1, 0, 0, 0};
float light2_color_spec[] = {1, 1, 1, 1};
float light2_spot_dir[] = {0, 5, -5};

gl.glLightfv(GL.GL_LIGHT2, GL.GL_POSITION, light2_pos);
gl.glLightfv(GL.GL_LIGHT2, GL.GL_AMBIENT, light2_color_am);
gl.glLightfv(GL.GL_LIGHT2, GL.GL_DIFFUSE, light2_color_diff);
gl.glLightfv(GL.GL_LIGHT2, GL.GL_SPECULAR, light2_color_spec);

gl.glLightfv(GL.GL_LIGHT2, GL.GL_SPOT_DIRECTION, light2_spot_dir);
gl.glLightf(GL.GL_LIGHT2, GL.GL_SPOT_CUTOFF, 15);

 

nach oben

Beleuchtung Beispielszene

Für das Spiel benötigen wir natürlich auch eine Lichtquelle. Diese setzen wir in der Methode setLight(..), die in der init-Methode aufgerufen werden soll. Für unser Spiel haben wir dabei ein Richtungslicht gewählt, das um zwei Einheiten nach oben und um fünf in positiver z-Richtung verschoben wurde und die Szene mit einem weißen Licht ausleuchtet.

Die Methode setLight() sieht wie folgt aus:

private void setLight(GL gl)
{
    float light_pos[] = {0, 2, 5, 0};
    float light_color_am[] = {1, 1, 1, 1};
    float light_color_diff[] = {1, 1, 1, 1};
    float light_color_spec[] = {1, 1, 1, 1};

    gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, light_pos);
    gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, light_color_am);
    gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, light_color_diff);
    gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, light_color_spec);
    gl.glEnable(GL.GL_LIGHTING);
    gl.glEnable(GL.GL_LIGHT0);
    gl.glEnable(GL.GL_DEPTH_TEST);
    gl.glEnable(GL.GL_SMOOTH);
}

Bei eingeschaltetem Licht hat die Funktion glColor*(..) keine Auswirkungen mehr. Um den Spielfiguren trotzdem Farbe zu verleihen benötigen wir nun Materialien.

nach oben