Irrlicht - from Noob to Pro: Texturen
Über Texturen
[Bearbeiten]Gute Texturen sind in der Spielewelt neben dem Gameplay das Salz in der Suppe. Mittlerweile besteht eine texturierte Oberfläche nicht mehr nur aus einer Grafikdatei, sondern es können sogar mehrere sein, um den Detailreichtum einer Oberfläche noch zusätzlich zu erhöhen. Bei neueren Grafikkarten müssen Texturen nicht mehr zwingend das n² - Format (256 x 256, 512 x 512, 1024 x 1024 Pixel usw.) einhalten, sondern sind frei definierbar. Sehen wir uns doch mal die verschiedenen Arten von Texturen an ...
Die Diffuse-Map
[Bearbeiten]Die Diffuse Map (auch engl. Color Map) ist die eigentliche Textur eines Objekts, welche mittels Farbwerten die Bildinformationen der Oberfläche speichert. Es ist pro Objekt auch möglich, mehrere Diffuse Maps zu verwenden, um unterschiedliche Bereiche des Objekts darzustellen. Eine Diffuse-Map speichert die Daten in Rot-, Grün-, Blau- und Alpha-Werten.
Die Alpha-Map
[Bearbeiten]Eine Alpha-Map bestimmt, welcher Teil der Textur durchsichtig ist und welcher nicht. Wenn Sie z.B. einen Maschendrahtzaun erstellen wollen, dann benötigen Sie eine Alpha-Map, welche vorgibt, wo die Öffnungen der Maschen sind. Es gibt 2 Möglichkeiten, wie Alpha-Maps erstellt werden :
Die color-keyed Alpha-Map
[Bearbeiten]Die Color-Keyed Alpha-Map wird während der Laufzeit des Programms generiert. In diesem Fall wird Irrlicht mitgeteilt, welcher Farbwert als "transparent" zu setzen ist. Meist ist das der Pixel in der linken oberen Ecke einer Bilddatei. Dies kann jedoch definiert werden. Dies geschieht durch den Aufruf
driver->makeColorKeyTexture(textur1, core::position2d<s32>(0,0));
Alternativ kann auch der Farbwert direkt angegeben werden :
driver->makeColorKeyTexture(textur1, video::SColor(255,255,0,255));
Die Image-based Alpha-Map
[Bearbeiten]Diese Alpha-Map wird entweder in einer Datei als Anhang gespeichert (ist z.B. bei Targa-Dateien (*.tga) oder Portable Networks-Grafiken (*.png) der Fall), oder man speichert die Alpha-Map als zweite Bilddatei ab und kombinert diese dann mit dem Bild, welches die Textur enthält.
Bild und Alpha-Map | |
---|---|
Die Displacement-Map
[Bearbeiten]Die Displacement Map ist eine Grafikdatei, welche eine 256 Farben Graustufenpalette verwendet, um Höheninformationen einer Oberfläche zu speichern. Im Englischen wird meist der Begriff "Height Map" verwendet, was aber wiederum auch die Technik zur Erstellung von Landschaften aus Height Maps (ebenfalls Graustufenbilder) benennt. Diese beiden werden gerne verwechselt. Generell gilt, dass die hellen Stellen einer Displacement-Map höher aus der Oberfläche herausragen als dunkle Stellen. Da der Alphawert die Helligkeit vorgibt (mehr Alpha = mehr Helligkeit), wird meist dieser als Multiplikator für die Berechnung der Höhe verwendet. Beim Displacement-Mapping wird im Gegensatz zu anderen Verfahren die Geometrie einer Oberfläche verändert, wodurch auch bei näherer Betrachtung aus einem flachen Winkel die Oberfläche ihre Struktur behält. Deshalb nennt man Displacement auch das "wirkliche" Bump-Mapping, da man reale Oberflächen damit erzeugt. Der Nachteil liegt darin, dass diese Methode sehr rechenintensiv ist, wenn viel Flächen damit dargestellt werden.
Die Normal-Map
[Bearbeiten]Die Normal-Map dient der Darstellung der Flächennormalen, welches Richtungsvektoren sind, die den rechten Winkel einer Fläche beschreiben. Dies ist besonders bei der Beleuchtung der Oberfläche interessant, da dadurch die Lichtberechnung, der Schatten sowie das Abstrahlverhalten beeinflusst wird. Dadurch wird eine unebene Oberfläche simuliert, obwohl diese eigentlich flach ist. Die drei Werte der Flächennormale sind in den Farbwerten der Normal-Map versteckt. In fast allen Fällen beschreibt der rote Farbwert die X-Achse, der grüne Farbwert die Y-Achse und der blaue Farbwert die Z-Achse. Wegen der Verwendung der 3 Achsen wird diese Technik auch Dot3 Bump-Mapping bezeichnet.
Parallax-Mapping
[Bearbeiten]Parallax Mapping verwendet wie Displacement-Mapping ein Graustufenbild zur Errechnung von Höheninformationen. Im Gegensatz zum Displacement-Mapping wird allerdings die Geometrie der Fläche nicht verändert, um Rechenzeit einzusparen. Das Parallax-Mapping verwendet den Winkel, aus dem der Benutzer eine Fläche betrachtet und errechnet daraus den Schatten, den diese Fläche wirft, wenn Sie uneben ist. Somit wird also die Beleuchtungsberechnung direkt beeinflusst.
Texturkoordinaten
[Bearbeiten]Um festzulegen, wie Texturen über 3-dimensionale Objekte gelegt werden, verwendet man Texturkoordinaten. Diese bestehen aus 3 Koordinaten :
- die U-Koordinate, welche die horizontale Ausbreitung einer Textur bestimmt,
- die V-Koordinate, welche die vertikale Ausbreitung einer Textur bestimmt und
- die W-Koordinate, welche die Stärke einer oberflächenverändernden Prozedur (Displacement-Mapping, Parallax-Mapping usw.) bestimmt. Dies wird in diesem Buch später unter dem Thema Bump-Mapping noch weiter behandelt.
Man spricht deshalb auch von UVW-Mapping.
Der Koordinatenursprung liegt bei Irrlicht in der oberen linken Ecke der zu texturierenden Fläche. Die UV-Koordinaten geben an, wie oft eine Textur in welcher Richtung auf einer Fläche wiederholt wird.
Da es sich in bei den Koordinaten um Start- und End-Koordinaten handelt, ist es auch möglich, nur einen bestimmten Ausschnitt einer Bilddatei als Textur anzugeben :
Koordinaten und Ergebnisse | |||
---|---|---|---|
Die Angabe der Texturkoordinaten
[Bearbeiten]Die Texturkoordinaten sind in der Struktur S3DVertex als die letzten 2 Parameter deklariert :
core::vector2d<f32> irr::video::S3DVertex::TCoords
Im Beispielcode (siehe unten) sind die Texturkoordinaten also ebenfalls die letzten 2 Parameter in der Definition des Arrays für das Viereck (erster Parameter U, zweiter Parameter V):
vaVertices[0] = S3DVertex(-0.3f,-0.3f, z_vorne,0,0,0,SColor(255,255,255,255),0,1); //Punkt A (l.u.)
vaVertices[1] = S3DVertex(-0.3f, 0.3f, z_vorne,0,0,0,SColor(255,255,255,255),0,0); //Punkt B (l.o.)
vaVertices[2] = S3DVertex( 0.3f,-0.3f, z_vorne,0,0,0,SColor(255,255,255,255),1,1); //Punkt C (r.u.)
vaVertices[3] = S3DVertex( 0.3f, 0.3f, z_vorne,0,0,0,SColor(255,255,255,255),1,0); //Punkt D (r.o.)
Ein Beispielcode
[Bearbeiten]Ich habe Ihnen hier ein kleines Beispiel programmiert, welches zeigen soll, wie man einen Color-Key erstellt und wie man eine Alpha-Map aus einer Bilddatei verwendet.
Wenn Sie die Variable bVerwendeColorKey auf true setzen, so wird der linke obere Pixel der Bilddatei verwendet, um einen Color-Key zu erstellen. Ist bVerwendeColorKey auf false, so wird die Alpha-Map aus der Bilddatei verwendet (falls vorhanden).
//Einbinden der Header-Datei von Irrlicht
#include <irrlicht.h>
//Einbinden der Namespaces
using namespace irr;
using namespace core;
using namespace video;
//Die Hauptprozedur main()
int main()
{
//Unser Irrlicht-Device erstellen und initialisieren
IrrlichtDevice *device =
createDevice( video::EDT_OPENGL, dimension2d<u32>(640, 480), 32,
false, false, false, 0);
//Konnte das Device erstellt werden ?
if (!device)
return 1; //Falls nicht, Fehlercode zurückgeben und Programm abbrechen
//Den Text des Hauptfensters festlegen
device->setWindowCaption(L"Texturen darstellen mit Irrlicht !");
//Den Videotreiber erstellen und Zeiger aus dem Device abholen
IVideoDriver* driver = device->getVideoDriver();
//Ein Material deklarieren
video::SMaterial material;
//Das Material nimmt kein Licht an
material.Lighting = false;
//Das Material soll voll gezeichnet werden
material.Wireframe = false;
//Die Textur aus der Bilddatei laden
material.setTexture(0,driver->getTexture("Datei.png"));
bool bVerwendeColorKey = false; //Soll ein Color-Key verwendet werden ?
if (bVerwendeColorKey) //Ja
{
//Verwende Color-Key
material.MaterialType = EMT_TRANSPARENT_ALPHA_CHANNEL; //Materialeigenschaft umstellen
//Linker oberer Pixel legt den Color-Key fest
driver->makeColorKeyTexture(material.getTexture(0),position2d<s32>(0,0));
} else //Nein
//Verwende Alpha-Map in der Bilddatei
material.MaterialType = EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
//Z-Position
const irr::f32 z_vorne = -0.3f; //Vorderseite
//Definieren der Vertices
video::S3DVertex vaVertices[4]; //Das Array vom Typ S3DVertex
vaVertices[0] = S3DVertex(-0.3f,-0.3f, z_vorne,0,0,0,SColor(255,255,255,255),0,1); //Punkt A (l.u.)
vaVertices[1] = S3DVertex(-0.3f, 0.3f, z_vorne,0,0,0,SColor(255,255,255,255),0,0); //Punkt B (l.o.)
vaVertices[2] = S3DVertex( 0.3f,-0.3f, z_vorne,0,0,0,SColor(255,255,255,255),1,1); //Punkt C (r.u.)
vaVertices[3] = S3DVertex( 0.3f, 0.3f, z_vorne,0,0,0,SColor(255,255,255,255),1,0); //Punkt D (r.o.)
//Definieren der Indicies
u16 uiIndicies[6] = {0, 1, 2, //A->B->C=Dreieck1 (Vorderseite)
2, 1, 3}; //C->B->D=Dreieck2 (Vorderseite)
//Während das Device aktiv ist ...
while(device->run())
{
//Szene beginnen
driver->beginScene(true, true, SColor(3,150,203,255));
//Material festlegen
driver->setMaterial(material);
//Zeichnen des Vierecks
driver->drawIndexedTriangleList(
&vaVertices[0], //Zeiger auf das erste Element im Vertices-Array
4, //Anzahl der Elemente im Vertices-Array
&uiIndicies[0], //Zeiger auf das erste Element in Indicies-Array
2); //Anzahl der zu zeichnenden Dreiecke
//Szene beenden
driver->endScene();
}
//Das Device freigeben
device->drop();
//Keinen Fehler zurückgeben
return 0;
}
|