Ogre3d tutorial: drugi deo

   Dakle sada sve radi kako treba i spremni ste da uskočite u naš kod? Pa ako niste dovoljno upoznati sa Ogre-om, strpite se još malo. Možete pokušati sa čitanjem komentara, ali će vam stvari biti mnogo jasnije kad shvatite kako Ogre radi.

Ogre: prvi koraci

    Pa ja neću da se bavim copy-paste-om i uputiću vas na Setting up an application, a ovde ću istaći samo najbitnije stvari. Najčešće stvari zakažu kada stvari nisu na pravom mestu. Ako ste stigli dovde, verovatno ste nabavili Ogre. Sledeća česta greška je da se OgreMain.dll ne nalazi u istom folderu kao izvršni fajl. Postarajte se da je tako. Za ostale .dll-ove ćete ukačiti polako. Sledeći bitan fajl je plugins.cfg. Po defaultu Ogre ga draži u istom direktorijumu kao izvršna, ali se to može promeniti u kodu. Plugins.cfg govori Ogre-u gde se nalaze razni pluginovi koje Ogre treba da loaduje. Skoro pa morate da uključite bar neki rendering plugin. Najprostiji plugins.cfg izgleda ovako:

# Defines plugins to load

Plugin=RenderSystem_Direct3D9_d

Plugin=RenderSystem_GL_d

    Pluginovi (*.dll fajovi) se moraju nalaziti na pravom mestu, u ovom slučaju u istom direktorijumu kao i izvršni fajl.

    Zatim ide resources.cfg, koji može da se zove i drugačije i on pokazuje Ogre-u gde se nalaze svi resursi koji mogu da se učitaju (modeli, teksture, skripte...). Možete da dodajete cele direktorijume, ili zip fajlove. Moguće je učitavati kolekcije resursa i iz custom paketa, ako napravite loader. Na početku ćete verovatno hteti ključne resusre Ogre-a, radi primera. To bi moglo da izgleda ovako:

# Resource locations to be added to the 'boostrap' path

# This also contains the minimum you need to use the Ogre example framework

[Bootstrap]

Zip=../../Media/packs/OgreCore.zip

# Resource locations to be added to the default path

[General]

FileSystem=../../Media

...

    Pazite da putanje moraju biti tačne, ove će raditi u slučaju da vam je radni direktorijum u Ogre_source/Samples/Common/bin/Debug direktorijumu (u tom slučaju ćete imati već definisane konfiguracione fajlove i sve *.dll-ove na mestu, ali vi želite da vaš projekat stoji u folderu nezavisnom od Ogre-a. Možete iskopirati OgreCore.zip negde u vaš projekat).

    Uostalom više o svemu piše na onom linku gore. Pa onda na sledeće korake!

Ogre: sledeći koraci

    Sledeći koraci su češljanje tutorijala na Ogre wikiju. Oni nisu teški, ali mogu oduzeti dosta vremena pošto je Ogre prilično velik. Primeri koji su tamo, koriste Example Framework, klasu iz koje izvedete novu i spremni ste da kucate manje primere. To je adekvatno kada učite, ali nije adekvatno ako hoćete da započnete vaš projekat, pa ću ja probati da dam nekoliko instrukcija za pokretanje Ogre-a from scrap, takođe relevantnih za ETF Pong. Znači sada ćemo da pokušamo da napravimo "Hello World" projekat koristeći Ogre i MSVC9.

    Napravite novi prazan projekat za win32 konzolu. U Debug folder iskopirajte OgreMain_d.dll, RenderSystem_Direct3D9_d.dll i RenderSystem_GL_d.dll. Napravite fajlove plugins.cfg i resources.cfg u istom folderu. Plugins.cfg bi trebalo da sadrži isti tekst kao gore. Resources.cfg bi trebalo da izgleda ovako:

[Bootstrap]

Zip=../Media/OgreCore.zip

[General]

FileSystem=../Media

    Što bi značilo da morate da napravite Media folder, u root-u projekta i u njega iskopirate OgreCore.zip i sve ostale resurse koji vam padnu na pamet. OgreCore.zip nađite pretraživanjem Ogre-ovog home direktorijuma (kao i ove *.dll-ove uostalom). Sada u Visual studiu idite desnim klikom na vaš projekat, pa properties i izvršite sledeća podešavanja:

    Prve tri stavke su najvažnije i gotovo uvek se koriste kada se dodaje nova biblioteka u projekat, to bi trebalo da bude poznato. Sledeće u projekat dodajte nove fajlove main.cpp, ExampleApp.h, i ExampleApp.cpp. Evo kako izgleda ExampleApp.h:

#ifndef EXAMPLE_APP_H

#define EXAMPLE_APP_H

#include <Ogre.h>

class ExampleApp

{

public:

    ExampleApp();

    ~ExampleApp();

    // Ovde će se obaviti inicijalizacija endžina i svega ostalog što je potrebno da iscrtamo jednu lepu scenu

    void Initialize();

    // Ovim se započinje iscrtavanje

    void Go();

    // Ovim se gasi motor

    void Shutdown();

private:

    Ogre::Root *mOgreRoot;

};

#endif

 

   Ovo je goli minimum. Sada sledi main.cpp, koji se uopšte neće menjati:

#include "ExampleApp.h"

int main(int argc, char *argv[])

{

    ExampleApp app;

    app.Initialize();

    app.Go();

    app.Shutdown();

    return 0;

}

    Sada ide prva implementacija ExampleApp.cpp:

#include "ExampleApp.h"

ExampleApp::ExampleApp() : mOgreRoot(0)

{

   

}

ExampleApp::~ExampleApp()

{

}

void ExampleApp::Initialize()

{

    // Ogre::Root je glavni objekat celog endžina. On se ovim pozivom inicijalizuje sa default parametrima.

    // Primetite da umesto new stoji OGRE_NEW, to je zato što Ogre koristi napredniji menadžment memorije

    // i ovim se poziva optimizovana verzija new operatora. I to je sve što vam treba da upalite motor

    mOgreRoot = OGRE_NEW Ogre::Root();

    // Ovim pozivom se stvara onaj dijalog u gde korisnik bira konfiguracione opcije.

    // Vraća true ako korisnik nastavi, a ako otkaže false

    if(mOgreRoot->showConfigDialog())

        // Motor je već upaljen, ovim se inicijalizuje prozor.

        // Pri parametar mu kaže autocreate window, drugi je ime tog prozora

        mOgreRoot->initialise(true, "Abrakadabra");

    else

        exit(1);

}

void ExampleApp::Go()

{

   

}

void ExampleApp::Shutdown()

{

    if (mOgreRoot)

    {

        // OGRE_NEW ima svoj parnjak OGRE_DELETE

        OGRE_DELETE mOgreRoot;

        mOgreRoot = 0;

    }

}

 

    Ovo bi moglo da se nazove Ogre "Hello World" programom, ali to nije ono po šta ste došli. Program koji stvori prozor koji trepne i ispiše gomilu teksta nije baš zanimljiv. Ali ne brinite ima još! Samo par napomena prvo kada pravite program nikada nemojte da ga pokrećete u full screenu. I konzola može da se ukloni, ali je pogodna za debug. Ako vas zanima prekopirajte main.cpp iz ETF Ponga, on je napisan tako da pokreće konzolu samo u debug verziji.

    Sada da bi obogatili aplikaciju treba nam malo sadržaja. OgreCore.zip je dosadan, sad mi je na pamet palo nešto bolje. Prekopirajte dragon.zip, koji se nalazi u istom direktorijumu kao i OgreCore.zip i stavite ga u naš Media folder. Promenite resources.cfg tako da sada izgleda ovako:

[Bootstrap]

Zip=../Media/OgreCore.zip

[General]

FileSystem=../Media

Zip=../Media/dragon.zip

    OK od sada crvena slova označavaju dodat tekst. Sada su svi resursi na mestu samo treba da ih učitamo, sledi novi ExampleApp.h:

#ifndef EXAMPLE_APP_H

#define EXAMPLE_APP_H

#include <Ogre.h>

class ExampleApp

{

public:

    ExampleApp();

    ~ExampleApp();

    void Initialize();

    void Go();

    void Shutdown();

private:

        // Odvojićemo učitavanje resursa u novu metodu koju ćemo pozvati iz glavne inicijalizacije

    void InitializeResources();

    Ogre::Root *mOgreRoot;

};

#endif

    I ExampleApp.cpp:

#include "ExampleApp.h"

...

void ExampleApp::Initialize()

{

    ...

        InitializeResources();

}

...

// Ova metoda ne izgleda toliko jednostavno i ne morate se udubljivati u nju za sada. Ono što zapravo radi je da

// učitava fajl resources.cfg, parsira ga pomoću raznih pomoćnih objekata koji su deo Ogre biblioteke a zaduženi su

// za parsiranje konfiguracionih fajlova

void ExampleApp::InitializeResources()

{

    Ogre::String sec_name, type_name, arch_name;

    Ogre::ConfigFile cf;

    cf.load("resources.cfg");

    Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

    while (seci.hasMoreElements())

    {

        sec_name = seci.peekNextKey();

        Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();

        Ogre::ConfigFile::SettingsMultiMap::iterator i;

        for (i = settings->begin(); i != settings->end(); ++i)

        {

            type_name = i->first;

            arch_name = i->second;

            // Ovo je metoda koju bi pozivali ručno sa hard-kodovanim informacijama o lokacijama koje sadrže resurse

            Ogre::ResourceGroupManager::getSingletonPtr()->addResourceLocation(arch_name, type_name, sec_name);

        }

    }

    // Ova metoda obično stoji odvojeno od samog čitanja konfiguracionog fajla zato što ona zapravo vrši

    // inicjalizaciju svih resursa

    Ogre::ResourceGroupManager::getSingletonPtr()->initialiseAllResourceGroups();

}

    Sada su svi resursi spremni i čekaju da budu iskorišćeni. Metodu InitializeResources() smo mogli da realizujemo samo pomoću dva poziva (funkcija addResourceLocation() i initialiseAllResourceGroups()), ali ovim smo dobili pouzdan čitač resources.cfg fajla.

    Naša aplikacija je spremna da koristi resurse, ali i dalje trepće i sada ćemo to da rešimo. ExampleApp.h:

#ifndef EXAMPLE_APP_H

#define EXAMPLE_APP_H

#include <Ogre.h>

// Našu klasu izvodimo iz Ogre::FrameListener. Skoro svaka klasa može postati listener. Listeneri nam daju 3 metode

// koje možemo da overridujemo i koje se Ogre poziva pri svakom frejmu

class ExampleApp : public Ogre::FrameListener

{

public:

    ExampleApp();

    ~ExampleApp();

    void Initialize();

    void Go();

    void Shutdown();

private:

    void InitializeResources();

    // Ova metoda se poziva pri svakom frejmu kada je grafički procesor zauzet, ali CPU slobodan, pa je zato

    // i najoptimizovanija. FrameListener još sadrži frameStarted i ended metode koje se pozivaju na samom

    // početku, odnosno kraju, iscrtavanja. Ogre::FrameEvent je struktura pomoću koje nam se prosleđuje vreme

    // proteklo od prošlog frejma i poziva iste funkcije. Kada neka od ovih metoda vrati false prekida se ceo

    // unutrašnji rendering ciklus

    bool frameRenderingQueued(const Ogre::FrameEvent& evt);

    Ogre::Root *mOgreRoot;

};

#endif

    I u fajlu ExampleApp.cpp samo mala izmena:

...

void ExampleApp::Initialize()

{

    ...

    InitializeResources();

       

        // Root koji je glavni mora da registruje frame listener i da ga doda u red, to se ovim postiže

    mOgreRoot->addFrameListener(this);

}

...

void ExampleApp::Go()

{

    // Ovim se započinje rendering loop, koji se završava kada neka od metoda nekog od listenera vrati false

    mOgreRoot->startRendering();

 

...

    Super sada imamo prozor koji više ne trepne jednom pa nestane. Ali sada imamo novi problem, prozor sada stoji neumorno, jer je rendering loop postao beskonačna petlja. Ne brinite to ćemo srediti kada implementiramo frameRenderingQueued(), a sada ćemo se fokusirati na glavni deo, da iscrtamo nešto na taj crni prozor. ExampleApp.h sada sledi u svojoj finalnoj verziji:

#ifndef EXAMPLE_APP_H

#define EXAMPLE_APP_H

#include <Ogre.h>

class ExampleApp : public Ogre::FrameListener

{

public:

    ExampleApp();

    ~ExampleApp();

    void Initialize();

    void Go();

    void Shutdown();

private:

    void InitializeResources();

        // Metoda koja će stvoriti scenu koju ćemo da iscrtamo

    void InitializeScene();

    bool frameRenderingQueued(const Ogre::FrameEvent& evt);

    Ogre::Root *mOgreRoot;

    // Menadžer scene, kamera i viewport, 3 stvari bez kojih nijedna 3d aplikacija ne može

    Ogre::SceneManager *mSceneManager;

    Ogre::Camera *mCamera;

    Ogre::Viewport *mViewport;

};

#endif

    I izmene ExampleApp.cpp:

ExampleApp::ExampleApp() : mOgreRoot(0), mCamera(0), mSceneManager(0), mViewport(0)

{

   

}

...

void ExampleApp::Initialize()

{

    ...

    InitializeResources();

    // Ne zaboravimo da pozovemo inicijalizaciju scene

    InitializeScene();

    mOgreRoot->addFrameListener(this);

}

...

// Ovde se zapravo inicijalizuje scena, a zatim se i kreira, to su mogle biti (i trebalo bi da budu) dve odvojene 

// metode

void ExampleApp::InitializeScene()

{

    // Menadžer scene je najveći prijatelj scene, više o tome ovde. Scena je jedan skup podataka potreban za

    // iscrtavanje nekog prikaza, a menadžer scene te podatke objedinjuje u optimizovanu kolekciju, zavisno

    // od toga šta treba da se iscrta (scena u zatvorenom ili otvorenom prostoru itd...)

    mSceneManager = mOgreRoot->createSceneManager(Ogre::ST_GENERIC);

        // Kamera je oko u virtuelnom svetu

    mCamera = mSceneManager->createCamera("Kamera");

        // Viewport je prozor kroz koji se gleda (ne prozor u koji se gleda). To je površina na koju će finalna

    // scena biti iscrtana. Jedan rendering window može imati više viewportova, kao u split-screen igrama.

        // Lako stižemo do rendering windowa, jer smo ga kreirali automatski. Moramo povezati kameru (oko) sa viewportom

    // pa je stoga viewport ono što spaja kameru sa prozorom.

    mViewport = mOgreRoot->getAutoCreatedWindow()->addViewport(mCamera);

        // Moramo podesiti aspect ratio. Ovo je najpravilniji način, ali bi trebalo da se poziva svaki put kada se

    // prozor re-sizeuje.

    mCamera->setAspectRatio(

        static_cast<Ogre::Real>(mViewport->getActualWidth())/static_cast<Ogre::Real>(mViewport->getActualHeight()));

       

        // *Odavde kreće pravo kreiranje scene, deo iznad se retko menja, dok se deo ispod često menja*

        // Default boja jeste crna, ali sam ostavio ovo iz demonstracionih razloga

    mViewport->setBackgroundColour(Ogre::ColourValue::Black);

        // Postavimo kameru na željeno mesto i uperimo je 

    mCamera->setPosition(0,0,200);

    mCamera->lookAt(0,0,0);

        // Postavimo ambijetalno svetlo na sivkastu boju. Ambijetalno svetlo je svetlo koje se nalazi svuda po sceni

    // svuda ima isti intenzitet i nema pravac. To je kao glavno svetlo i postoji samo jedno po sceni. Postoji još

    // vrsta svetla (spotlight, point light...)

    mSceneManager->setAmbientLight( Ogre::ColourValue( 0.75, 0.75, 0.75 ) );

        // Entitet možemo nazvati i mesh ili model. Entitetu možemo pridružiti materijal, animaciju i sl.

    // Prvi parametar kod kreiranja entiteta je jedinstveno ime (mora biti jedinstveno!), a drugi je ime fajla

    Ogre::Entity* entity = mSceneManager->createEntity("Zmaj", "dragon.mesh");

        // Scene node, važan koncept kod Ogre-ovog scene managementa. Scene manager se ponaša kao graf. Scene manager

    // objekat sadrži pokazivač na root čvor, odakle možete dalje stvarati nove grane. Prednosti ovoga su što

    // se scena lako i prirodno deli u manje delove i transformacije jednog čvora mogu biti u lokalnom prostoru

    // tj, u odnosu na roditeljski čvor ili u globalnom prostoru. Npr. ruke možete rotirati u odnosu na telo,

    // ne morate u odnosu na svatsku osu.

    Ogre::SceneNode *scene_node = mSceneManager->getRootSceneNode()->createChildSceneNode();

        // Entitet se mora privezati za neki čvor da bi mogao da bude iscrtan i manipulisan.

    scene_node->attachObject(entity);

        // Ovim smanjujemo malo zmaja pošto je ipak prevelik

    scene_node->setScale(0.1, 0.1, 0.1);

        // Sada dalje manipulišemo čvorom, a ne entitetom, čvor možemo translirati, rotirati itd.

}

    Evo ga trebalo bi da vidite sivkastog zmaja na ekranu sad.

    Sad da unesemo malo živosti i implementiramo i poslednju metodu za sad.

    ExampleApp.cpp

...

// Ovo će postepeno udaljavati kameru do neke granice a onda će prekinuti iscrtavanje

bool ExampleApp::frameRenderingQueued(const Ogre::FrameEvent& evt)

{

        // Nabavimo trenutnu poziciju kamere

    Ogre::Real cam_position_z = mCamera->getPosition().z;

    // Množenjem neke vrednosti sa vremenom proteklim od prošlog frejma postižemo da ta vrednost bude nezavisna od     // frejm rejta.

    cam_position_z += 1000 * evt.timeSinceLastFrame;

        // Postavimo kameru na novu poziciju

    mCamera->setPosition(0,0,cam_position_z);

    if (cam_position_z > 5000)

                // Kad preteramo vratimo false i time prekidamo ciklus iscrtavanja

        return false;

    return true;

}

   

    Sad slobodno izbacite komentarom setScale() i setAmbientLight() i dobićete potpuniji doživljaj zmaja koji proleće ispod vas u divnom crno belom kontrastu. Možete se igrati sa kreiranjem scene i rendering loopom i stvoriti neki demoscene. Ova aplikacija je nešto više od "Hello World, Ogre", pre je neki minimalni framework. Nastavite da čeprkate po Ogre wikiju i tutorialima. Sada kada ste videli Ogre-a u akciji pogled na overview from 10000 feet bi trebalo da bude mnogo jasniji. Sledeći logičan korak je dodavanje inputa, to neka ostane kao vežba, pogledajte Example Framework ili bilo šta slično na wikiju. U attachments sam dodao source code, sa MSVC9 projektom, ovog tutoriala.

sledeća stranica  >>