Tutorial:Scenegraph2
aus ZFXCE, der freien Wissensdatenbank
Inhaltsverzeichnis |
Basisidee der ZFXCE-Resourcen-Verwaltung
Daten wie zum Beispiel Leveldaten werden in der ZFX-Community-Engine durch einen Resourcenmanager angesprochen. Dieser verwaltet zum einen die Resourcen, kann sie von der Festplatte laden, bei Bedarf entladen und nicht benötigte Resourcen wieder freigeben. Liegt z.B. ein Quake3-Level in einem Quake3-Archiv, kann der Resourcemanager die Daten direkt aus dem Archiv laden (Quake3-Archive sind im eigentlichen Sinne nur Zip-Archive, die die ZFX-Community-Engine auslesen kann). Der Resourcemanager gibt dem Anwender nach dem Laden und Bearbeiten die Daten in einer speziellen Resource-Klasse wie zum Beispiel einem ceMesh zurück. Mittels dieser Resource kann man nun weiter mit den Daten arbeiten.
Vorbereitungen
//Erzeugen eines Szenegraphen ceSceneGraph *pSG = ceMainApp::CreateSceneGraph(); // Erzeugen eines Rendermodules pSG->SetRenderSystem((Render::ceRenderSystem*) CreateSystemFromDynLib(DynLib::CE_RENDER_OGL)); // Erzeugen einer Rendersurface pSG->CreateRenderSurface(ce_string("Apptest"), 0,0, SceneGraph::CE_1024_768, false, 4, 24, 24, 0, ceColorRGBA(1.0f, 1.0f, 1.0f, 0.0f));
Um sich in dem Quake3-Level bewegen zu können, braucht man noch eine First-Person-Kamera. Auch diese erhält man durch den Szenegraphen:
m_pCamera = pSG->CreateCamera("default", ceVec3f(0.0f, 0.0f, 0.0f), ceVec3f(1.0f, 1.0f, 0.0f), NULL);
Nun ist man soweit und kann den Scenegraphen zum Einsatz fertig machen, in dem man ihn initialisiert:
pSG->InitSystem();
Laden einer Resource
Wie im Erste-Schritte-Beispiel zu sehen war, kann man aus der Mainapplikation den Resourcenmanager anfordern. In diesem Fall weisen wir den Resourcemanager an, ein Mesh aus einem Q3-Archiv zu laden.
vector<ce_string> vParam; ceMesh *pMesh = (ceMesh*) ceMainApp::GetResourceServer()->CreateResource("test1.mesh", "maps/cht3.bsp", vParam);
Der Resourcemanager sieht durch die Extention:
*.mesh
dass er eine Resource vom Typ ceMesh generieren soll. Der Name ist in diesem Fall test1. Spezielle Parameter wollen wir nicht übergeben, so dass wir den Parameterarray leer lassen können. Konnte die Datei nicht in den vorhandenen Archiven gefunden werden, wird NULL zurückgegeben. Das Eingabefile wird durch die Extention:
*.bsp
erkannt. Alle im Arbeitsverzeichnis vorliegenden Files werden nun durchsucht. Handelt es sich um ein gezipptes Archiv, durchsucht das VFS der ZFXCE dieses ebenfalls nach dem angegebenen File (Hinweis: Q3-Level werden als komplettes Zip-Archiv angelegt, in dem man die Levelgeometrie unter maps ablegt).
Erstellen eines Scenenodes
Das geladene Mesh kann nun mittels eines Scenenodes in den Scenegraphen eingehängt werden:
ceSceneNode *pNode = pSG->CreateSceneNode(std::string("testnode1"), pMesh, ceVec3f(1.0f, 1.0f, 1.0f), NULL);
Der neu kreierte Scenenode wird nun direkt ins Wurzelverzeichnis des Szenegraphen eingehängt:
Root +->pNode1
Beim Aktualisieren wird dieser Node nun vom Scenegraph mit abtraversiert und gerendert. Scenenodes stellen die einfachste Form eines Scenegraph-Nodes dar. Die Grafik-Informationen werden direkt gerendert. Es finden keine Cullingstrategien der Renderdaten im Scenenode Anwendung. Nun kann man das Quake3-Level rendern lassen.
Bewegen im Level
Man braucht nun noch einige Eventlistener, die das Steuern der First-Person-Kamera übernehmen: Als erstes binden wir im Init-Teil die Eventlistener an das Eventdevice
// Füge Eventlistener für Taste gedrückt, Taste losgelassen und Maus bewegt hinzu GetInputDevice()->AddEventListener(Input::ceKeyboardButtonDownEvent, ceEventFunctor::Make(this, &MeshLoader::OnKeyPressed)); GetInputDevice()->AddEventListener(Input::ceKeyboardButtonUpEvent, ceEventFunctor::Make(this, &MeshLoader::OnKeyUp)); GetInputDevice()->AddEventListener(Input::ceMouseMoveEvent, ceEventFunctor::Make(this, &MeshLoader::OnMouseMove));
Diese müssen nun noch implementiert werden. Die ZFXCE-First-Person-Kamera verwaltert Bewegungsstates. Durch Setzen dieser Flags kann man die Kamera entsprechend per Tastatur bewegen. Der Einfachheit halber zeige ich hier einen Weg, um die aus Egoshootern allseits bekannte Tastaturkonfiguration zu kopieren. Zunächst müssen wir bei den Tastendrücken die entsprechenden States setzen:
void MeshLoader::OnKeyPressed(const ceEvent& ev, const ceEventData* data) { // Extrahiere Keyboardinfo aus dem Event const Input::ceKeyboardButtonEventData* key = (Input::ceKeyboardButtonEventData*)data; switch(key->m_Key) { // Beende Programm case Input::CE_KEY_ESCAPE: exit(0); break; // Rückwärts case Input::CE_KEY_s: m_pCamera->MoveBackward(true); break; // Vorwärts case Input::CE_KEY_w: m_pCamera->MoveForward(true); break; // Seitlich links case Input::CE_KEY_a: m_pCamera->StrafeLeft(true); break; // Seitlich rechts case Input::CE_KEY_d: m_pCamera->StrafeRight(true); break; } }
Nun müssen wir noch die Beweguns-Flags nach den Loslassen der Tasten wieder zurücksetzten:
void MeshLoader::OnKeyUp(const ceEvent& ev, const ceEventData* data) { // Get keybord event data Input::ceKeyboardButtonEventData* key = (Input::ceKeyboardButtonEventData*)data; switch(key->m_Key) { // Vorwärts gehen case Input::CE_KEY_w: m_pCamera->MoveForward(false); break; // Rückwarts gehen case Input::CE_KEY_s: m_pCamera->MoveBackward(false); break; // Seitlich links fertig case Input::CE_KEY_a: m_pCamera->StrafeLeft(false); break; // Seitlich rechts fertig case Input::CE_KEY_d: m_pCamera->StrafeRight(false); break; } }
Abschliessend setzen wir nun noch die Richtung der Kamera:
void MeshLoader::OnMouseMove(const ceEvent& ev, const ceEventData* data) { // Get mouse event data const Input::ceMouseMoveEventData* mouse = (Input::ceMouseMoveEventData*)data; // Set new view by mouse m_pCamera->SetViewByMouse(mouse->m_RelX, mouse->m_RelY); }
Abschliessende Worte
Den kompletten Code kann man sich in der ZFXCE unter:
ZFXC-Engine/demos/MeshLoader
ansehen
ZFXC-Engine
