OGRE資源相關分析 + OGRE 啓動詳解 + 實體的加載與顯示

 

OGRE資源相關分析
Resource
 
Resource的類繼承體系如下:
   
Resource代表着一類可以被載入的資源,比如Mesh,Texture等。每個資源有其唯一的Name,根據Name可以定位到某個資源,這樣也確保了資源只能被載入一次。並且Resource必須在一段時間不使用的時候要被刪除。
要實現爲Resource子類有以下要求:
1. 構造函數和Resorce有相同的參數。子類構造函數不允許有其它的參數傳入,如果需要設置其它成員變量可以通過Set函數。
2.實現Resource中的純虛函數loadImpl和unloadImpl。而且mSize必須在loadImpl調用後設置。
3. StringInterface ParamCommand and ParamDictionary setups in order to allow setting of core parameters (prior to load)through a generic interface.
 
資源有兩種載入的方法,一個是通過解析腳本文件自動載入,另一種是手工載入。手工載入的好處是:由於某些意外原因導致資源unload,這時就不能通過Resource的reload重新載入,因爲是意外原因所以mIsLoaded就仍然爲true。通過使用手工載入就可以預防這個問題。
 
ResourceManager
ResourceManager的類繼承體系如下:
 
 
和Resource對比我們可以得出ResourceManager和Resource是一一對應的。其實一個具體類型的ResourceManager就是管理管理這個類型資源的資源池。通過ResourceManager可以可以索引這些資源,查找資源,載入和銷燬資源。
ResourceManager還有一些其它功能,比如它保存着它所掌管類型的資源的載入,卸載優先順序。這樣載入資源的時候可以一種一種的載入,節省了時間。ResourceManager自己定義了內存預算,我們載入/卸載的時候都會通知該變這個內存預算值,這樣我們就可以得知我們使用了多少內存。另外,要注意的一點是資源可以通過Resource類被載入和卸載,但只能使用ResourceManager來創建和刪除。
 
ResourceGroupManager
與這個類聲明所在的.h文件中有一個ResourceGroupListener類的聲明,這個類定義瞭如下幾種事件接口,它們在操作資源的不同時候被調用。
· resourceGroupScriptingStarted
· scriptParseStarted (*)
· scriptParseEnded (*)
· resourceGroupScriptingEnded
· resourceGroupLoadStarted
· resourceLoadStarted (*)
· resourceLoadEnded (*)
· worldGeometryStageStarted (*)
· worldGeometryStageEnded (*)
· resourceGroupLoadEnded
 
ResourceGroupManager把資源分成一個個的組,通過調用資源對應的ResourceManager(注:通過ResourceManagerMap使得string sourceType和ResourceManager掛鉤)來加載或卸載組中的資源。此外如果一個ResourceManager支持通過腳本來定義資源,那麼這個類就會找到腳本的位置然後告訴ResourceManager來解析它們。在ResourceGroupManager中,資源可以看成有4種狀態:Undefined,Declared,Unloaded,Loaded。
ResourceGroupManager可以讓你把一系列資源看成是一個單元來載入和卸載。比如一個資源組可以是遊戲中一個關卡的所有資源。OGRE中有一個預先定義的資源組: DEFAULT_RESOURCE_GROUP_NAME,它所控制的資源只有到了程序退出時纔會被釋放。
    一旦你創建了自己的資源組,你可以通過以下3種途徑爲這個資源組載入資源:
1.   調用declareResource()。
2. 通過使用腳本;ResourceManager的一些子類型擁有特定的腳本類型比如:.material,.overlay等。
3. 調用ResourceManager::create。
如果你使用前面兩種方法必須確保調用initialiseResourceGroup。
通過 void createResourceGroup(const String& name)方法我們可以創建一個資源組。
創建好一個資源組後我們就可以爲這個資源組增加搜索路徑,我們將在這些路徑中查找我們需要的資源。通過以下函數我們可以爲一個資源組添加搜索路徑:

void ResourceGroupManager::addResourceLocation(const String& name,
 const String& locType,const String& resGroup,bool recursive)
name 
The name of the resource location; probably a directory, zip file, URL etc.
locType 
The codename for the resource type, which must correspond to the Archive factory which is providing the implementation.
resGroup 
The name of the resource group for which this location is to apply. ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME is the default group which always exists, and can be used for resources which are unlikely to be unloaded until application shutdown. Otherwise it must be the name of a group; if it has not already been created with createResourceGroup then it is created automatically.
recursive 
Whether subdirectories will be searched for files when using a pattern match (such as *.material), and whether subdirectories will be indexed. This can slow down initial loading of the archive and searches. When opening a resource you still need to use the fully qualified name, this allows duplicate names in alternate paths
 
設置好資源路徑後我們就可以爲資源組聲明資源,從而你可以載入和卸載它們。聲明資源也可以通過解析腳本文件。

void declareResource(const String& name, const String& resourceType,
           const String& groupName = DEFAULT_RESOURCE_GROUP_NAME,
           const NameValuePairList& loadParameters = NameValuePairList());
當我們創建資源組後,添加了搜索路徑,並且可能也聲明瞭一些資源後,我們還不能直接使用資源,這個時候我們要調用void initialiseResourceGroup(const String& name)來初始化資源組。這個方法也觸發了以下兩個行爲:
1. 通過給定的資源路徑解析資源路徑中所有類型資源的腳本,腳本里面的資源將被創建,但這個時候還沒有被載入。           
2. 創建通過調用declareResource聲明的資源。同樣這個時候資源也僅僅是被創建而沒有被載入。
所以這個方法只是爲各個ResourceManager創建資源而沒有載入它們。僅僅是表面應用程序可以找到這些資源,但在調用load之前還不能被使用。還有就是一旦調用這個方法後你就無法再通過腳本,和提前聲明來創建新的資源。如果要那麼做只有先調用clearResourceGroup,然後重新聲明資源,再調用這個函數。
 
資源創建好後爲了使用我們必須調用
void loadResourceGroup(const String& name, bool loadMainResources = true,
           bool loadWorldGeom = true);
這樣我們纔可以使用這些資源。
與它相對的是void unloadResourceGroup(const String& name)調用這個函數後資源將被卸載,但是資源的聲明仍然存在於各個ResourceManager中。要取消所有的聲明必須調用
void clearResourceGroup(const String& name),當這個函數被調用後所有資源的聲明也就不存在了,只剩下資源的搜索路徑。
下面這個方法最徹底,它先卸載資源,然後清空資源,最後把資源組從資源組的集合中刪除。
void destroyResourceGroup(const String& name)
 
[demo分析]

 
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    // 執行應用程序初始化:
    Root * ogreRoot=new Root();
    // 顯示配置窗口
    bool rtn = g_ogreRoot->showConfigDialog();
    // 如果配置文件已經存在(已經執行過起碼一次 showConfigDialog ),
    // 那麼你可以用下面這句之間讀取配置,而不需要顯示配置窗口。
    // g_ogreRoot->restoreConfig();
    // 創建渲染窗口
    g_ogreRoot->initialise(true, "My Render Window"); // 這裏的 true 指示 ogre 自動創建窗口
    RenderWindow * renderWindow =g_ogreRoot->getAutoCreatedWindow();
    renderWindow->setAutoUpdated(true);
    // 創建場景管理器,這個TerrainSceneManager 是指地形場景管理器
    SceneManager* mSceneMgr = g_ogreRoot->createSceneManager("TerrainSceneManager");
    // 創建攝像機
    Camera* mCamera = mSceneMgr->createCamera("PlayerCam");
    mCamera->setPosition(Vector3(0,0,-300)); // 攝像機位置
    mCamera->lookAt(Vector3(0,0,800)); // 攝像機朝向
    // 設置渲染窗口的視口(和我們的攝像機綁定)
    Viewport *vp = renderWindow->addViewport(mCamera);
    vp->setBackgroundColour(ColourValue(0, 0, 0));
   // 定義資源的讀取目錄/文件,dragon.zip 放在執行目錄,這個文件可以在 OgreSDK/media/packs 目錄下找到
    ResourceGroupManager::getSingleton().addResourceLocation(
        "dragon.zip", "Zip", "General"
        );
    // 我把 script 目錄從 OgreSDK/media/materials/scripts 複製到執行目錄下了,龍的皮膚着色需要用到某個腳本
    ResourceGroupManager::getSingleton().addResourceLocation(
        "scripts", "FileSystem", "General"
        );
    // 初始化資源管理器
    ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
    // 讀取龍的模型
    Entity * ent = mSceneMgr->createEntity("dragon", "dragon.mesh");
    // 把模型放入場景管理器
    mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);
    // 開始渲染
    g_ogreRoot->startRendering();
    return 0;
};
  OgreSDK/bin/release 下的文件都複製到執行目錄,然後試試吧!
好了,這樣我們的第一個 ogre 程序就寫好了,很簡單吧。當初寫的時候碰到不少問題,主要是文件找不到,資源找不到……
OGRE 啓動詳解 + 實體的加載與顯示

#include "stdafx.h"
#ifdef _DEBUG
#pragma comment(lib,"ogremain_d.lib")
#else
#pragma comment(lib,"ogremain.lib")
#endif
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
{
        using namespace Ogre;
        try
        {
                /**//// Root的構造函數裏會創建所有Factory以及Manager
                /// 這裏的3個參數,都是可以爲空的(不是省略).
                /// 1個參數指明瞭插件配置的文件名. 這個文件裏指明瞭我們將要使用的圖形驅動(DX or GL)DLL.
                /// 既然是圖形程序,所以肯定要有圖形驅動了,如果這個參數爲空,那麼我們必須手動去加載圖形驅動.
                /// 2個參數指明瞭OGRE的圖形驅動配置文件。
                /// 這個參數實際上是在調試的時候使用的,發佈版本的時候肯定是不要它的.
                /// 它在Root裏的ShowDialg裏使用,用來動態的配置當前要使用的圖形驅動.
                /// 如果我們可以確定我們要使用的圖形驅動,完全可以配置我們自己的圖形驅動. 具體代碼可以參考下面.
                /// 3個參數指定了我們要使用的LOG文件名
                Root * root = new Root("",
                                       "",
                                       "");
                /**//// 我們手動加載圖形驅動
#ifdef _DEBUG
                root->loadPlugin("Plugins/RenderSystem_Direct3D9_d");
#else
                root->loadPlugin("Plugins/RenderSystem_Direct3D9");
#endif
                /**//// 由於OGRE的資源加載都由ResourceGroupManager來管理,不通過WINDOWS直接管理.
                /// 所以,要正常使用OGRE的資源加載,我們還得把我們的資源目錄給加到這個Manager裏去.
                /// 說白了,就是資源的環境路徑.
                /// 最起碼,當前目錄是要加的吧 ^_^
                /// 這裏也有3個參數。
                /// 1個參數指明瞭我們要加入的資源的相對目錄名
                /// 2個參數指明瞭我們要加入的資源屬於什麼資源包。
               /// 這個參數比較詭異,到底這個參數要依據什麼原則來填寫呢。
                /// 其實這個參數的名字OGRE的代碼裏已經定義好了.
                /// 如果是文件系統包呢,就查看FileSystemArchiveFactory這個類的定義裏的createInstance,名字爲FileSystem
                /// 如果是ZIP壓縮包呢,就查看ZipArchiveFactory這個類的定義裏的createInstance,名字爲Zip
                /// 也就是說,這個名字必須以ArchiveFactory的派生類裏定義的爲準,否則肯定會出錯地.
                /// 3個參數就比較簡單了,可以隨便填寫,它只是對資源做一個邏輯上的分類.
                ResourceGroupManager::getSingleton().addResourceLocation(
                    ".", "FileSystem", "General");
                ResourceGroupManager::getSingleton().addResourceLocation(
                    "media", "FileSystem", "General");
                /**//// 做完以上這步,我們需要把這些資源路徑裏的文件信息都提取出來,以便加速查找.
                /// 下面這個函數就是幹這個苦差事的.
                ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
                /**//// 剛剛不是說了嗎,我們把Root裏的第二個參數給留空了,也就是說我們得自己指定一個RenderSystem
                /// 以及給它配置屬性
                /// 這裏我們就用在Plugins里加載進OGRE裏的第一個RenderSystem,我這裏是DX
                RenderSystem * render_system = *root->getAvailableRenderers()->begin();
                /**//// 設置爲窗口模式
                render_system->setConfigOption("Full Screen","No");
                /**//// 把這個RenderSystem給設爲系統默認的
                root->setRenderSystem(render_system);
                /**//// 好了,有了RenderSystem,我們就可以初始化我們的Root.(其實就是創建窗口的過程)
                /// 這裏我們把RenderSystem的名字也顯示在窗口的標題欄中.
                RenderWindow *render_win = root->initialise(true,String("my simple orge window,rendersystem : ") + render_system->getName());
                /**//// 場景的渲染,SceneManager必須創建一個,這個就是我們的遊戲舞臺了
                SceneManager * scene_mgr = root->createSceneManager(ST_GENERIC, "my scene");
                /**//// 設置燈光的亮度
                scene_mgr->setAmbientLight(ColourValue(1,1,1));
                /**//// 場景設置好了,但必須還得有個觀察者,這個觀察者在這裏就是Camera
                Camera * camera = scene_mgr->createCamera("my camera");
                camera->setPosition(Vector3(0,0,500));
                camera->lookAt(Vector3(0,0,-300));
                camera->setNearClipDistance(5);
                /**//// 有了觀察者,但我們怎麼看到場景的內容呢?
                /// 我們還得需要一個眼睛,在這裏叫做Viewport
                Viewport* vp = render_win->addViewport(camera);
                vp->setBackgroundColour(ColourValue(0,0,0));
                /**//// 這裏設置camera的圖形比例,必須設置,否則圖象會變形
                camera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
                /**//// 我們通過例子裏的資源模型ogrehead來做個演示
                Entity *ent = scene_mgr->createEntity("Robot","ogrehead.mesh");
                SceneNode *node = scene_mgr->getRootSceneNode()->createChildSceneNode("RobotNode");
                node->setPosition(50,30,0);
                node->attachObject(ent);
                root->startRendering();
                delete root;
        }
        catch (Ogre::Exception & e)
        {
                ::MessageBox( NULL,
                                e.getFullDescription().c_str(),
                                "An exception has occured!",
                                MB_OK | MB_ICONERROR | MB_TASKMODAL);
        }
}
本文來自http://blog.csdn.net/pizi0475/archive/2010/03/18/5389975.aspx
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章