Open Source im professionellen Einsatz

© photocase.com

Ob Bühnenbild oder 3D-Modell, erst Anstrich und Licht sorgen für die perfekte Illusion

Im Rampenlicht

Ein überzeugendes Bühnenbild sorgt für die passende Atmosphäre im Theater. Auch am Computer machen Anstrich und Beleuchtung die Illusion von 3D-Modellen perfekt. Selbst einfache Skripte zaubern dank OpenGL mit Hilfe von Bitmaps und Beleuchtung Überraschendes auf den Schirm.

Wie ein geometrisches 3D-Modell mit ein paar Farben auf den Schirm kommt, hat kürzlich ein Artikel [1] zu Tcl3D [2] beschrieben. Doch OpenGL kann bedeutend mehr. Um bei Flugzeugen oder Menschen alle Details wie Augen, Bekleidung oder Beschriftung nachzubilden, wären Millionen von Dreiecken notwendig. Viel einfacher ist es, auf eine grobe Form ansprechende Bitmaps wie ein Abziehbild zu kleben. Bei 3D-Modellen heißt dieses Verfahren Textur. Aktuelle Grafikkarten unterstützen es durch riesige Speicher für Texturen.

Fürs letzte Finish des virtuellen Bühnenbilds sorgt die Beleuchtung. Das Standardlicht aus OpenGL hat den abstoßenden Charme von Neonlicht - doch es gibt angenehmere Lichtquellen, deren Verhalten der Bühnenbauer bis ins Feinste beschreiben darf.

Die hier gezeigten Beispiele setzen auf denen im ersten Artikel auf [1], daher sind die Geometrien und Ansichten bereits definiert. Die gedruckten Listings enthalten den jeweils relevanten Ausschnitt; der komplette Code steht wie immer auf dem FTP-Server des Linux-Magazins [3]. Die Skripte sind wieder für Paul Obermeiers Tcl-Erweiterung Tcl3D [2] geschrieben. Die Beispiele lassen sich aber auch gut auf OpenGL unter C oder Java anwenden, da die Befehle überall den gleichen Namen tragen.

Abziehbild

3D-Modelle bestehen meist aus Dreiecken, die sind simpel und schnell zu erzeugen. Selbst einfache Modelle mit wenigen Dreiecken können realistisch aussehen, wenn sie eine passende Textur erhalten (Abbildungen 1a bis 1c). Damit OpenGL die Bitmaps passend auf die Geometrie montiert, benötigt es jedoch genaue Anweisungen, wohin welche Stelle des Abziehbildes gehört.

Abbildung 1a: Am Anfang steht ein Netz aus Dreiecken, die ein kugelförmiges Modell bilden.

Abbildung 1a: Am Anfang steht ein Netz aus Dreiecken, die ein kugelförmiges Modell bilden.

Abbildung 1b: Eine Hülle lässt Objekte wie eine Kugel erscheinen und verdeckt die unsichtbaren Kanten.

Abbildung 1b: Eine Hülle lässt Objekte wie eine Kugel erscheinen und verdeckt die unsichtbaren Kanten.

Abbildung 1c: Eine passende Textur gibt dem Oberflächennetz das Aussehen eines Steins.

Abbildung 1c: Eine passende Textur gibt dem Oberflächennetz das Aussehen eines Steins.

Dabei treffen zwei Welten aufeinander: das dreidimensionale X-Y-Z-Koordinatensystem des Dreiecks und das zweidimensionale S-T-Koordinatensystem der Textur. Der Befehl »glTexCoord2f« sagt OpenGL, welche Stelle der Textur (S, T) auf den nächsten definierten Geometriepunkt (X, Y, Z) kommt. Abbildung 2 zeigt das Verfahren mit drei Dreiecken und einer kleinen Bitmap.

Abbildung 2: Die OpenGL-Funktion »glTexCoord2f« bildet die Bitmap auf die Geometrie ab. Dabei legt der Programmierer fest, welcher Punkt des Bildes wo auf der Oberfläche landet.

Abbildung 2: Die OpenGL-Funktion »glTexCoord2f« bildet die Bitmap auf die Geometrie ab. Dabei legt der Programmierer fest, welcher Punkt des Bildes wo auf der Oberfläche landet.

Das abgedruckte Listing 1 zeigt die wesentlichen Ausschnitte des kompletten Quelltextes [3]. Das Hauptprogramm setzt die Funktion »tclCreateFunc« als »-createproc« ins OpenGL-Widget ein. Damit ruft die Library diese Funktion auf, um den Inhalt des Widget zu erzeugen. Die Funktion lädt die Texturen und erzeugt die Geometrie.

Listing 1: Texturen

01 # Wird ein Mal aufgerufen
02 proc tclCreateFunc {toglwin} {
03   # ein paar Einstellungen
04   glEnable GL_TEXTURE_2D
05   glEnable GL_DEPTH_TEST
06   glPolygonMode GL_FRONT_AND_BACK GL_FILL
07 
08   # Bild in Tcl laden
09   if [catch {image create photo -file "worked_stone_8180226.JPG"} phImg] {
10     error "Fehler beim Laden: $phImg"
11   }
12 
13   # OpenGL-Vektor mit Bitmap aus Tcl-Image erzeugen
14   set w [image width     $phImg]
15   set h [image height    $phImg]
16   set n [tcl3dPhotoChans $phImg]
17   set pTextureImage [tcl3dVector GLubyte [expr {$w * $h * $n}]]
18   tcl3dPhoto2Vector $phImg $pTextureImage
19   image delete $phImg ;# Bild aus Tcl löschen
20 
21   # Interpolation angeben
22   glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER $::GL_LINEAR
23   glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER $::GL_LINEAR
24 
25   # Textur aus OpenGL-Vektor mit Bitmap erzeugen
26   set ::g_textureID [tcl3dVector GLuint 1]
27   glGenTextures 1 $::g_textureID
28   glBindTexture GL_TEXTURE_2D [$::g_textureID get 0]
29 
30   if {$n == 3} {set type $::GL_RGB
31   } else {      set type $::GL_RGBA}
32   glTexImage2D GL_TEXTURE_2D 0 $n $w $h 0 $type GL_UNSIGNED_BYTE $pTextureImage
33 
34   # OpenGL-Vektor mit Bitmap löschen
35   $pTextureImage delete
36 
37   # Display-Liste erzeugen...
38   set ::g_sphereDList [glGenLists 1]
39   glNewList $::g_sphereDList GL_COMPILE
40   # ...und mit Geometrie und Textur füllen
41   renderSphere 0.0 0.0 0.0 1.5 $::aufloesung
42   glEndList
43 }
44 
45 # Kugel aus Dreiecken mit Textur erzeugen
46 proc renderSphere {r p} {
47   [...]
48   # Normalenvektor berechnen
49   set normalX [expr {cos($theta2) * cos($theta3)}]
50   set normalY [expr {sin($theta2)}]
51   set normalZ [expr {cos($theta2) * sin($theta3)}]
52   glNormal3f $normalX $normalY $normalZ
53 
54   # Einfache Zylinderprojektion der Textur
55   glTexCoord2f [expr {-1.0 * ($j/double($p))}] 
56                [expr { 2.0 * ($i+1)/double($p)}]
57 
58   # Position der Knotenpunkte berechnen
59   set posX [expr {$r * $normalX}]
60   set posY [expr {$r * $normalY}]
61   set posZ [expr {$r * $normalZ}]
62   glVertex3f $posX $posY $posZ
63   [...]
64 }

Bitmaps für Texturen liegen üblicherweise auf der Festplatte, insbesondere für realistische Darstellungen sind es meist Fotos der gewünschten Oberflächen. Solche Texturen finden sich zum Beispiel bei Mayang [4] oder speziell für Holz bei [5]. Als Textur eignet sich eine beliebige Bitmap, allerdings sollte die Kantenlänge eine Potenz von 2 sein, zum Beispiel 256 mal 512. Damit es an den Kanten zu keinen sichtbaren Stößen kommt, kann ein Gimp-Filter die Bilder in nahtlose Muster verwandeln (»Filter | Abbilden | Nahtlos machen«).

Auf Umwegen

Es gibt leider keine Funktion, die Bitmaps direkt von der Festplatte in OpenGL lädt. Daher sind drei Schritte nötig. Zuerst holt das Skript, wie bei Tk üblich, die Bitmaps mit »image create photo -file Dateiname«. Gewöhnlich laden Tk-Programme damit Bitmaps für Buttons. Die If-catch-Konstruktion in den Zeilen 9 bis 11 sorgt für eine Fehlermeldung, falls das Skript die Datei nicht laden kann.

Danach wandert die Bitmap aus Tk zu OpenGL. Hierfür hat Tcl3D bequemerweise eine Funktion, die Tk-Images in einen OpenGL-Vektor lädt. Zuerst erzeugt in Zeile 17 »tcl3dVector« einen Vektor, seine Größe bestimmt sich aus Länge und Breite des Image multipliziert mit der Anzahl der Kanäle. Normale Bilder haben je einen Kanal für Rot, Grün und Blau, einige noch einen weiteren für die Transparenz. Die Funktion »tcl3dPhoto2Vector« kopiert in Zeile 18 den Bildinhalt in den Vektor. Nun liegt das Bild doppelt vor, als OpenGL-Vektor und als Tk-Bild. Letzteres löscht Zeile 19, um Speicher zu sparen.

Klar ist, dass OpenGL die Bitmap in den meisten Fällen verzerrt, um sie auf die Geometrie zu legen. Dazu interpoliert es die Zwischenpunkte, der Befehl »glTexParameteri« sorgt in den Zeilen 22 und 23 für eine einfache lineare Interpolation. Als Nächstes erzeugt »glBindTexture« aus dem vorhandenen Vektor ein Texturobjekt (Zeile 28).

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 4,5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook