Irrlicht - from Noob to Pro: Einfache Texturmanipulationen
Vorwort
BearbeitenIm vorhergehenden Abschnitt haben wir uns mit der Translation ,Rotation und Skalierung von Objekten beschäftigt.
In diesem Abschnitt will ich auf die Rotation, Translation und Skalierung der Texturen eines Objekts anhand eines kurzen Beispiels eingehen und aufzeigen, wie man dies bewerkstelligt.
Die Funktionen
BearbeitenFür die Translation, Rotation und Skalierung der Texturen verwenden wir in diesem Beispiel 3 Prozeduren von Irrlicht, welche die entsprechende Berechnung der Texturmatrix für uns vornehmen.
Im Gegensatz zum vorherigen Quellcodebeispiel müssen wir hier berücksichtigen, dass wir den Rotationswinkel der Textur nun in Radiant angeben müssen, um den entsprechenden Winkel zu erhalten. Da ein Rotationswinkel von 180 Grad nun 1 x π, ergibt, kann man das Verhältnis von Radiant zu Grad durch Teilung der beiden erreichen (180 ° : π = 57,29577951 Grad), was uns Irrlicht in der Header-Datei irrMath.h als Konstante bereistellt :
//! 32bit constant for converting from radians to degrees (formally known as GRAD_PI)
const f32 RADTODEG = 180.0f / PI;
Somit gilt für die Umrechnung von Radiant nach Grad also Radiant * RADTODEG = Gradzahl
Rotation
BearbeitenWir haben für die Rotation einer Textur 2 Funktionen zur Verfügung. Die erste ist
setTextureRotationCenter( f32 rotateRad )
und dreht uns unsere Textur grundsätzich um die Texturkoordinaten (UV) 0.5, 0,5, was den Mittelpunkt einer Textur mit einer Spannweite von (UV) 1.0, 1.0 entspricht. Sollte sich hier die Spannweite über 1.0 erhöhen, so muss die Textur durch Translation in mittige Lage gebracht werden. Diese Funktion verwendet die Einheit Radiant zur Angabe des Winkels.
Die zweite Funktion ist
setRotationDegrees( const vector3d<T>& rotation )
und verwendet die Einheit Grad zur Angabe des Rotationswinkels der Textur. Diese Funktion erwartet eine Variable vom Typ core::vector3d zur Übergabe des Winkels, wobei hier die Textur über die linke obere Ecke rotiert wird, was den UV-Koordinaten 0.0, 0.0 entspricht.
Translation
BearbeitenDie Tranlation der Textur erfolgt über die Angabe des Betrags, um welchen die Textur auf den UV-Koordinaten verschoben werden soll. Dies erfolgt über den Aufruf von
setTextureTranslate ( f32 x, f32 y )
Hier stellt die X-Achse den horizontalen Wert (U-Koordinate) und die Y-Achse den vertikalen Wert (V-Koordinate) dar.
Skalierung
BearbeitenBei der Skalierung der Textur ist zu beachten, dass die Textur ab einer Skalierung von größer +1.0 oder kleiner -1.0 wiederholt wird, was bei der z.B. der Darstellung langer Mauern zum Einsatz kommt. Anwenden lässt sich die Skalierung mit
setTextureScale ( f32 sx, f32 sy )
wobei die X-Koordinate die horizontale Skalierung (U-Koordinate) und die Y-Koordinate die vertikale Skalierung (V-Koordinate) darstellt.
Beispielcode zur Anwendung
BearbeitenIn diesem Beispiel werden zuerst drei Würfel erstellt und jeweils um 45 Grad gedreht, um die Textur besser sehen zu können. Danach wird jedem Würfel dieselbe Textur zugewiesen und bei dem linken Würfel zentrisch rotiert, beim rechten Würfel translationiert und beim oberen Würfel skaliert.
Hierzu der Quellcode :
//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"Rotation,Translation u. Skalierung einer Textur !");
//Den Videotreiber erstellen und Zeiger aus dem Device abholen
IVideoDriver* driver = device->getVideoDriver();
//Einen Szene-Manager erstellen und Zeiger aus dem Device abholen
scene::ISceneManager* smgr = device->getSceneManager();
//Erstellen der SceneNodes
scene::ISceneNode * Linker_Wuerfel = smgr->addCubeSceneNode(2.0f);
scene::ISceneNode * Rechter_Wuerfel = smgr->addCubeSceneNode(2.0f);
scene::ISceneNode * Oberer_Wuerfel = smgr->addCubeSceneNode(2.0f);
//Zuweisen des Materials
Linker_Wuerfel->setMaterialTexture(0, driver->getTexture("IntP_Brick.png"));
Rechter_Wuerfel->setMaterialTexture(0, Linker_Wuerfel->getMaterial(0).getTexture(0));
Oberer_Wuerfel->setMaterialTexture(0, Linker_Wuerfel->getMaterial(0).getTexture(0));
//Keine Lichtberechnung
Linker_Wuerfel->setMaterialFlag(EMF_LIGHTING, false);
Rechter_Wuerfel->setMaterialFlag(EMF_LIGHTING, false);
Oberer_Wuerfel->setMaterialFlag(EMF_LIGHTING, false);
//Position korrigieren
Linker_Wuerfel->setPosition(core::vector3df(-2, -1, 3));
Rechter_Wuerfel->setPosition(core::vector3df(2, -1, 3));
Oberer_Wuerfel->setPosition(core::vector3df(0, 1.5, 3));
//Um 45 Grad in Schräglage drehen
Linker_Wuerfel->setRotation(core::vector3df(45.0f, 45.0f, 0));
Rechter_Wuerfel->setRotation(core::vector3df(45.0f, -45.0f, 0));
Oberer_Wuerfel->setRotation(core::vector3df(-45.0f, 45.0f, 0));
//Eine Integer-Variable zum Speichern der letzten FPS
int lastFPS = -1;
//Unser 32Bit-Float zum Speichern des Texturwinkels in Radiant
f32 fWinkel = 0.0;
//Unsere Variablen zur Zeitsteuerung
u32 uiZuletztGestoppt = device->getTimer()->getTime(); //Aktuelle Zeit stoppen
const u32 uiDeltaTime = 50; //Textur alle 50ms drehen
//Einen GUI_Manager erstellen und Zeiger aus dem Device abholen
gui::IGUIEnvironment* guienv = device->getGUIEnvironment();
//Ein Text-Element definieren und an den GUI-Manager übergeben
gui::IGUIStaticText* GUI_debug_text = guienv->addStaticText
(L"",rect<s32>(5, 5, 300, 300),false,true,0,-1,false);
//Eine Kamera erstellen
smgr->addCameraSceneNode(0, core::vector3df(0,0,-2), core::vector3df(0,0,0));
//Während das Device aktiv ist ...
while(device->run())
{
//Szene beginnen
driver->beginScene(true, true, SColor(3,150,203,255));
//Nach Ablauf von Delta Time
if (device->getTimer()->getTime() > (uiZuletztGestoppt + uiDeltaTime))
{
//Neuen Zeitpunkt merken
uiZuletztGestoppt = device->getTimer()->getTime();
//Winkel erhöhen
fWinkel += 0.01f;
//Nicht über 360 Grad (=6.3 Radians) drehen
if (fWinkel > 6.3f) fWinkel =0.01f;
}
//Die Textur des linken Würfels drehen
Linker_Wuerfel->getMaterial(0).getTextureMatrix(0).setTextureRotationCenter(fWinkel);
//Alternativ kann auch mit folgender Zeile über die linke obere Ecke gedreht werden
/*Linker_Wuerfel->getMaterial(0).getTextureMatrix(0).setRotationDegrees(
core::vector3d<f32>(0.0f, 0.0f, fWinkel * RADTODEG)
);*/
//Die Textur des rechten Würfels verschieben
Rechter_Wuerfel->getMaterial(0).getTextureMatrix(0).setTextureTranslate((2 * sin(fWinkel)),0.0f);
//Die Textur des oberen Würfels skalieren
Oberer_Wuerfel->getMaterial(0).getTextureMatrix(0).setTextureScale(sin(fWinkel),1.0f);
//Dem Szenemanager sagen, dass er alle Nodes zeichnen soll
smgr->drawAll();
//String erstellen
core::stringw tmp(L"Rotation,Translation u. Skalierung einer Textur in Irrlicht\nTreiber : ");
tmp += driver->getName();
tmp += L"\n FPS: ["; tmp += driver->getFPS();
tmp += "]\nDreiecke gezeichnet : ";
tmp += driver->getPrimitiveCountDrawn();;
tmp += "\nGrafikkarte ist von : ";
tmp += driver->getVendorInfo();
tmp += "\nLetzter Zeitstopp : ";
tmp += uiZuletztGestoppt;
tmp += "\nTexturwinkel (Grad): ";
tmp += (fWinkel * RADTODEG);
tmp += "\nTexturwinkel (Rad): ";
tmp += fWinkel;
tmp += "\nTranslation der Textur (U-Achse): ";
tmp += (2 * sin(fWinkel));
tmp += "\nSkalierung der Textur (U-Achse): ";
tmp += sin(fWinkel);
//String anzeigen
GUI_debug_text->setText(tmp.c_str());
//Dem GUI-Manager sagen, dass er alle GUIs zeichnen soll
guienv->drawAll();
//Szene beenden
driver->endScene();
}
//Das Device freigeben
device->drop();
//Keinen Fehler zurückgeben
return 0;
}
|