Irrlicht - from Noob to Pro: VideoDriver


Allgemeines

Bearbeiten

Der VideoDriver ist wohl einer der wichtigsten Klassen in Irrlicht, da er nicht nur die Renderroutinen steuert, sondern auch Lichtquellen, Texturen, den ViewPort und die Materialien verwaltet. Obendrein bietet er auch die Möglichkeit 2D-Objekte zu zeichnen, was nun hier näher vorgestellt werden soll. Vorher erzeugen wir uns einen gültigen IrrlichtDevice und speichern den VideoDriver in einer Variable.

IrrlichtDevice* device = createDevice(EDT_OPENGL, dimension2d<u32>(1024,768));

if(device)
{
  IVideoDriver* driver = device->getVideoDriver();
}

Nun können wir Anfangen unsere Objekte zu zeichnen.

Wichtig zu beachten ist dabei, dass alle draw-Befehle innerhalb von beginScene und endScene stehen.

2D Objekte zeichnen

Bearbeiten

Der VideoDriver kann natürlich 0-dimensionale Objekte wie Pixel darstellen. Dazu schauen wir uns folgende Signatur an

virtual void drawPixel(u32 x, u32 y, const SColor &color) = 0;

Dabei bedeuten die Parameter folgendes:

x: Die x-Koordinate des Pixels.

y: Die y-Koordinate des Pixels.

color: Die Farbe des zu zeichnenden Pixels.

Möglicher Aufruf der Funktion:

//schwarzer Pixel links oben
driver->drawPixel(0,0, SColor(255,0,0,0));
//roter Pixel an (100,100)
driver->drawPixel(100,100, SColor(255,255,0,0));

Eine Linie ist eine Verbindung zwischen zwei Punkten (Pixel) und wird in Irrlicht mit Hilfe der draw2DLine-Methode gezeichnet.

virtual void draw2DLine(const core::position2d< s32 > &start, const core::position2d< s32 > &end, SColor color=SColor(255, 255, 255, 255)) = 0;

Dabei bedeuten die Parameter folgendes:

start: Der Anfangspunkt der Linie.
end: Der Endpunkt der Linie.
color: Die Farbe der Linie.

Da die Farbe einen Defaultparameter übergibt, kann man diesen beim Aufruf auch weglassen. Die Linie würde dann weiß gezeichnet.

Möglicher Aufruf der Funktion:

//Linie in rot
driver->draw2DLine(position2d<s32>(0,0), position2d<s32>(100,100), SColor(255,255,0,0));
//gleiche Linie nur in weiß
driver->draw2DLine(position2d<s32>(0,0), position2d<s32>(100,100));

Rechteck

Bearbeiten

Hier bietet Irrlicht mehrere Möglichkeiten Rechtecke zu zeichnen. Schauen wir uns die Signaturen der Funktionen an.

//zeichnet ein Rechteck, bei der jede Ecke eine andere Farbe haben kann
virtual void draw2DRectangle(const core::rect< s32 > &pos, SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, const core::rect< s32 > *clip=0) = 0;

//zeichnet ein Rechteck mit einer Farbe
virtual void draw2DRectangle (SColor color, const core::rect< s32 > &pos, const core::rect< s32 > *clip=0) = 0;

//zeichnet nur den Umriss eines Rechteckes
virtual void draw2DRectangleOutline(const core::recti &pos, SColor color=SColor(255, 255, 255, 255)) = 0;

Die Parameter bedeuten dabei folgendes:

pos: Die Position des Rechteckes.
color: Die Farbe des Rechteckes.
colorLeftUp: Die Farbe der Ecke links oben.
color RightUp: Die Farbe der Ecke rechts oben.
colorLeftDown: Die Farbe der Ecke links unten.
color RightDown: Die Farbe der Ecke rechts unten.
clip: Das Rechteck gegen welches geclippt wird. Clipping heißt hierbei, dass von dem Rechteck, was mit pos angegeben wird, das Rechteck, welches mit clip referenziert wird abgezogen wird.

Möglicher Aufruf der Funktion:

driver->draw2DRectangle(SColor(255,0,0,0,), rect<s32>(0,0,640,480));
driver->draw2DRectangleOutline(rect<s32>(1,1,639,479), SColor(255,255,255,255));

Ein Polygon in Irrlicht ist ein symmetrisches n-eck. So ist ein Quadrat nicht weiter als ein Viereck. Das ist auch die einzige Möglichkeit in Irrlicht Kreise zu zeichnen. Men wählt ein entsprechend hohes n, sodass das Vieleck rund wirkt.

virtual void draw2DPolygon(core::position2d< s32 > center, f32 radius, video::SColor color=SColor(100, 255, 255, 255), s32 vertexCount=10) = 0;

Dabei bedeuten die Parameter folgendes:

center: Der Mittelpunkt des n-ecks.
radius: Die Entfernung einer Ecke bis zum Mittelpunkt.
color: Die Farbe des n-ecks.
vertexCount: Die Anzahl der Ecken.

Möglicher Aufruf der Funktion wäre:

//ein Fünfeck
driver->draw2DPolygon(position2d<s32>(250,250), 32.0f, SColor(255,0,0,0), 5);
//ein Polygon, was fast so rund ist wie ein Kreis ;)
driver->draw2DPolygon(position2d<s32>(300,300), 16.0f, SColor(255,255,0,0), 64);

Die Überschrift spricht für sich selbst. Man kann in Irrlicht mit Hilfe des VideoDrivers Bilder zeichnen lassen.

//Zeichnet ein mitunter skaliertes Bild mit einem Alphakanal mit Clipping und Blendingoptionen
virtual void draw2DImage (const video::ITexture *texture, const core::rect< s32 > &destRect, const core::rect< s32 > &sourceRect, const core::rect< s32 > *clipRect=0, const video::SColor *const colors=0, bool useAlphaChannelOfTexture=false) = 0;

//Zeichnet ein Bild mit einem Alphakanal mit Clipping und Blendingoptionen
virtual void draw2DImage (const video::ITexture *texture, const core::position2d< s32 > &destPos, const core::rect< s32 > &sourceRect, const core::rect< s32 > *clipRect=0, SColor color=SColor(255, 255, 255, 255), bool useAlphaChannelOfTexture=false) = 0;

//Zeichnet ein Bild
virtual void draw2DImage (const video::ITexture *texture, const core::position2d< s32 > &destPos) = 0;

Dabei bedeuten die Parameter folgendes:

texture: Das Bild.
destRect: Das Rechteck, in welches das Bild gezeichnet werden soll.
destPos: Die Position an der das Bild gezeichnet werden soll. Dabei wird die Dimension der Texture verwendet, um diese zu zeichnen.
sourceRect: Der Ausschnitt des Bildes, der gezeichnet werden soll.
clipRect: Das Rechteck, gegen das das Bild geclippt werden soll.
color: Die Farbe mit der Das Bild geblendet werden soll.
useAlphaChannelOfTexture: Gibt an ob der Alphakanal berücksichtigt werden soll.

Möglicher Aufruf der Funktion:

//zeigt das Buchcover ohne Transparenz
driver->draw2DImage(driver->getTexture("buchcover.png"), position2d<s32>(0,0));

//zeigt das Buchcover mit Transparenz und blau verfärbt
driver->draw2DImage(driver->getTexture("buchcover.png"), position2d<s32>(0,0), rect<s32>(position2d<s32>(0,0), driver->getTexture("buchcover.png")->getSize()), 0, SColor(255, 0, 0, 255), true);

//zeigt das Buchcover als Thumbnail
driver->draw2DImage(driver->getTexture("buchcover.png"), rect<s32>(0,0,78,100), rect<s32>(position2d<s32>(0,0), driver->getTexture("buchcover.png")->getSize()), 0, 0, true);

3D Objekte zeichnen

Bearbeiten

Irrlicht bietet auch die Möglichkeit 3D-Objekte mit Hilfe des VideoDrivers dazustellen. Somit ist es möglich Linien, Dreiecke, Dreicksverbünde und Quader bzw. Würfel im Raum darzustellen. Man übergibt anstelle eines 2-dimensionalen Vektors einen 3-dimensionalen. Es ist davon abzuraten solche Objekte mit dem VideoDriver zu zeichnen. Man sollte lieber die Variante über den SceneManager vorziehen.

Hinweise

Bearbeiten

Drawbefehle in der Zeichenschleife

Bearbeiten

Wie oben bereits erwähnt müssen alle draw-Methodenaufrufe innerhalb des Rendervorgangs stattfinden, da sie sonst ignoriert werden. Das wird zu Anfang meist falsch gemacht, da es im Tutorial auch nicht so explizit herausgehoben wird. Natürlich sollte man das Wissen schon mitbringen, gerade wenn man sich vorher mit OpenGL beschäftigt hat, dennoch gibt es viele, die gleichzeitig mit Irrlicht auch C++ und OpenGL/Direct3D anfangen zu lernen.

Dieser Code zeigt uns folgerichtig ein Rechteck auf dem Bildschirm an:

while(device->run())
{
  driver->beginScene(true, true, SColor(255,255,255,255));
			
    driver->draw2DImage(driver->getTexture("bild.png"), rect<s32>(0,0,100,100), rect<s32>(0,0,100,100), 0, 0, true);

  driver->endScene();
}

Wohingegen mit diesem Codeausschnitt nichts angezeigt wird:

while(device->run())
{
  driver->draw2DImage(driver->getTexture("bild.png"), rect<s32>(0,0,100,100), rect<s32>(0,0,100,100), 0, 0, true);
  
  driver->beginScene(true, true, SColor(255,255,255,255));

  driver->endScene();
}

So wenig Drawbefehle wie möglich

Bearbeiten

Ein zweites Problem ist, dass draw-Befehle enorm viel Overhead nach sich ziehen. Daher sollte man so wenig wie möglich dieser Befehle verwenden. Für ein 2D-Spiel sind sie kaum zu vermeiden. Für 3D-Spiele aber sollte man stets den SceneManager benutzen anstelle des VideoDrivers. Ein kleines Benchmarktool hat mal die Frames per Second (FPS) anhand der Anzahl der draw-Befehle gemessen, was die ganze Angelegenheit deutlich macht:

Anzahl der draw-Befehle Frames per Second
0 932
1 914
2 820
3 710
4 628
5 561
6 508
7 463
8 425
9 392
10 365
15 270
20 215
50 96
100 50
250 26
500 16

Leistungsdaten:

  • CPU: AMD Sempron, 1800 MHz
  • RAM: 768 MP (PC3200 DDR SDRAM)
  • Grafikkarte: GeForce 8400 GS (512 MB)
  • OS: MS Windows XP Home Edition SP2 32Bit