OGRE啟動過程詳解(OGRE HelloWorld程序原理解析)


 

    本文介紹 OGRE 3D 1.9 程序的啟動過程,即從程序啟動到3D圖形呈現,背后有哪些OGRE相關的代碼被執行。會涉及的OGRE類包括:

  1. Root
  2. RenderSystem
  3. RenderWindow
  4. ResourceGroupManager
  5. LogManager
  6. Viewport
  7. SceneManager
  8. Camera
  9. SceneNode
  10. Entity
  11. Light

    建議在閱讀本文時參考OGRE API Reference,OGRE官方給的API Reference沒有類的協作圖,可以自己用Doxygen生成API文檔,見:Bullet的學習資源(用Doxygen生成API文檔)

    關於如何安裝OGRE和如何配置一個可以運行的OGRE HelloWorld程序見:OGRE 1.9 的第一個程序(OGRE HelloWorld程序)

    本節所有代碼如下,可以先迅速瀏覽,然后看后面詳細解釋,后面將用“啟動代碼”來指代這段代碼:

  1 #include<OgreRoot.h>
  2 #include<OgreRenderSystem.h>
  3 #include<OgreRenderWindow.h>
  4 #include<OgreConfigFile.h>
  5 #include<OgreResourceGroupManager.h>
  6 #include<OgreLogManager.h>
  7 #include<OgreViewport.h>
  8 #include<OgreSceneManager.h>
  9 #include<OgreCamera.h>
 10 #include<OgreLight.h>
 11 #include<OgreEntity.h>
 12 
 13 int main(int argc, char *argv[])
 14 {
 15     Ogre::Root* mRoot;
 16     Ogre::RenderWindow* mWindow;
 17     Ogre::SceneManager* mSceneMgr;
 18     Ogre::Camera* mCamera;
 19 
 20 // 創建Root,在調用OGRE任何功能之前必須已經創建了Root
 21     mRoot = new Ogre::Root("plugins.cfg","ogre.cfg","Ogre.log");
 22 
 23 // 設定 RenderSystem
 24     Ogre::RenderSystem *rs =
 25         mRoot->getRenderSystemByName("OpenGL Rendering Subsystem");
 26     mRoot->setRenderSystem(rs);
 27     rs->setConfigOption("Full Screen", "No");
 28     rs->setConfigOption("Video Mode", "800x600 @ 32-bit colour");
 29     // 另一種方法是: if(!mRoot->showConfigDialog()) return false;
 30 
 31 // 初始化 RenderSystem
 32     mRoot->initialise(false);
 33 
 34 // 創建 RenderWindow
 35     int hWnd = 0;
 36     Ogre::NameValuePairList misc;
 37     misc["externalWindowHandle"] = Ogre::StringConverter::toString((int)hWnd);
 38     mWindow = mRoot->createRenderWindow("Win Ogre", 800, 600, false, &misc);
 39     // 上2步的另一種實現是: mWindow = mRoot->initialise(true, "Win Ogre");
 40 
 41 // 創建SceneManager,將渲染目標綁定到RenderWindow
 42     mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC);
 43     // Create one camera
 44     mCamera = mSceneMgr->createCamera("PlayerCam");
 45     mCamera->setNearClipDistance(5);
 46     // Create one viewport, entire window
 47     Ogre::Viewport* vp = mWindow->addViewport(mCamera);
 48     vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
 49     // Alter the camera aspect ratio to match the viewport
 50     mCamera->setAspectRatio(
 51         Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));
 52 
 53 // 加載資源,該歩不能早於RenderSystem的初始化和RenderWindow的創建
 54     // 如果使用OverlaySystem,該歩也不能早於OverlaySystem的創建
 55     Ogre::ConfigFile cf; cf.load("resources.cfg");
 56     Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
 57     Ogre::String secName, typeName, archName;
 58     while( seci.hasMoreElements() ){
 59         secName = seci.peekNextKey();
 60         Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
 61         Ogre::ConfigFile::SettingsMultiMap::iterator i;
 62         for( i=settings->begin(); i!=settings->end(); ++i ){
 63             typeName = i->first;
 64             archName = i->second;
 65             Ogre::ResourceGroupManager::getSingleton().
 66                 addResourceLocation(archName, typeName, secName);
 67         }
 68     }
 69     Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
 70 
 71 // 構造及設置場景
 72     mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
 73     mSceneMgr->setAmbientLight(Ogre::ColourValue(0.2f, 0.2f, 0.2f));
 74 
 75     Ogre::Entity* entNinja = mSceneMgr->createEntity("entNinja", "ninja.mesh");
 76     Ogre::SceneNode* nodeNinja = mSceneMgr->createSceneNode("nodeNinja");
 77     mSceneMgr->getRootSceneNode()->addChild(nodeNinja);
 78     nodeNinja->attachObject(entNinja);
 79     Ogre::Entity* entSphere = mSceneMgr->createEntity("entSphere", "sphere.mesh");
 80     Ogre::SceneNode* nodeSphere = mSceneMgr->createSceneNode("nodeSphere");
 81     mSceneMgr->getRootSceneNode()->addChild(nodeSphere);
 82     nodeSphere->attachObject(entSphere);
 83     nodeNinja->setPosition(-50,-100,0);
 84     nodeSphere->translate(50,0,100);
 85     Ogre::Light* pointLight1 = mSceneMgr->createLight("pointLight1");
 86     pointLight1->setType(Ogre::Light::LT_POINT);
 87     pointLight1->setDiffuseColour(Ogre::ColourValue::White);
 88     pointLight1->setSpecularColour(Ogre::ColourValue::White);
 89     pointLight1->setPosition(-400,200,-200);
 90 
 91     mCamera->setPosition(Ogre::Vector3(0,0,-250));
 92     mCamera->lookAt(Ogre::Vector3(0,0,0));
 93 
 94 // 渲染循環
 95     Ogre::LogManager::getSingleton().logMessage(">>Rendering");
 96     mRoot->startRendering();
 97 
 98 // 釋放資源,目前只需釋放Root
 99     delete mRoot;
100 
101     return 0;
102 }

    運行結果截圖:

 

1. 啟動過程概覽

    我們概要地看OGRE的啟動,OGRE WIKI Basic Tutorial 6: The Ogre Startup Sequence中摘出下面這段,注意它和上面的代碼(“啟動代碼”)是有差別的,各步驟的順序不同:

The basic Ogre life cycle looks like this:

  1. Create the Root object.
  2. Define the resources that Ogre will use.
  3. Choose and set up the RenderSystem (that is, DirectX, OpenGL, etc).
  4. Create the RenderWindow (the window which Ogre resides in).
  5. Initialise the resources that you are going to use.
  6. Create a scene using those resources.
  7. Set up any third party libraries and plugins.
  8. Create any number of frame listeners.
  9. Start the render loop.

    總的來說,先是初始化,最后啟動渲染循環。我將所有這些類的關系總結如下圖(不是什么UML圖,就大致理解吧):

    看完后面的詳細解釋后可以回過頭來看這段,那時你就會對OGRE的啟動有個大致印象。

 

2. 創建Root

    在調用OGRE任何功能之前,首先要實例化一個Root類,該Root實例將直接或間接指向所有其他類的實例。一個OGRE程序有且只有一個Root對象,因此Root類使用Singleton設計模式(單例模式,繼承自Singleton<Root>)。說到Singleton,OGRE的很多類都是Singleton,后面還會講的。

    Root類的構造函數原型如下:

Root (const String &pluginFileName="plugins"OGRE_BUILD_SUFFIX".cfg",
    const String &configFileName="ogre.cfg", const String &logFileName="Ogre.log")

    其中OGRE_BUILD_SUFFIX宏在Release下定義為空,Debug下定義為"_d"。三個參數是三個文件名。

    pluginFileName是插件配置文件,該文件指示OGRE要加載哪些插件,一個plugins.cfg文件的例子如下,其中#表示注釋

# Defines plugins to load
# Define plugin folder
PluginFolder=.
# Define plugins
# Plugin=RenderSystem_Direct3D9
 Plugin=RenderSystem_GL
 Plugin=Plugin_ParticleFX
 Plugin=Plugin_BSPSceneManager
 Plugin=Plugin_CgProgramManager
 Plugin=Plugin_PCZSceneManager
 Plugin=Plugin_OctreeZone
 Plugin=Plugin_OctreeSceneManager

    configFileName文件設置渲染系統(OpenGL或者Direct3D)及其參數,如抗鋸齒采樣數(FSAA),一個針對OpenGL驅動的配置文件ogre.cfg例子如下:

Render System=OpenGL Rendering Subsystem
[OpenGL Rendering Subsystem]
Colour Depth=32
Display Frequency=N/A
FSAA=8
Fixed Pipeline Enabled=Yes
Full Screen=No
RTT Preferred Mode=FBO
VSync=No
VSync Interval=1
Video Mode=1024 x 768
sRGB Gamma Conversion=No

    logFileName文件是OGRE程序的日志文件,在OGRE程序可以插入寫日志的代碼,日志文件方便對OGRE程序的調試。向日志文件寫入信息的代碼的一個例子如下:

Ogre::LogManager::getSingleton().logMessage(">>Rendering");

這里的LogManager是另一個使用Singleton設計模式的類,這種類使用靜態方法getSingleton獲取全局唯一的類實例。

    “啟動代碼”中創建Root對象的代碼在第21行:

mRoot = new Ogre::Root("plugins.cfg","ogre.cfg","Ogre.log");

 

3. 設定RenderSystem,初始化

    RenderSystem類對渲染系統(底層的OpenGL或Direct3D)進行抽象,它相當於是執行渲染的設備。給 Root 添加一個RenderSystem實例的最簡單方式是調用Ogre::Root:: showConfigDialog方法,運行時系統將彈出如下對話框,讓用戶選擇要使用的圖形驅動,以及相應的參數:

if(!mRoot->showConfigDialog()) return false;

    我們在這個對話框所做的設置被記錄在ogre.cfg文件中(見上面第2節)。也可以不用對話框,而在程序中設置,也就是說在程序中設置我們在對話框所選的項:

Ogre::RenderSystem *rs = mRoot->getRenderSystemByName("OpenGL Rendering Subsystem");
mRoot->setRenderSystem(rs);
rs->setConfigOption("Full Screen", "No");
rs->setConfigOption("Video Mode", "800x600 @ 32-bit colour");

“啟動代碼”使用的是后者,代碼在第24-27行。

    如果不想每次都彈出對話框選擇渲染系統,可以用如下代碼:

if( !(mRoot->restoreConfig() || mRoot->showConfigDialog()) )
    return false;

restoreConfig方法讀入ogre.cfg文件來代替對話框設置,還記得C/C++邏輯運算表達式求值的短路性質吧,如果mRoot->restoreConfig()返回true(存在ogre.cfg文件),mRoot->showConfigDialog()將不被執行。

    RenderSystem對象創建后需要初始化,Ogre::Root::initialise(bool, const String, const String)方法就是初始化root的RenderSystem的,如果第一個bool參數為true,將自動創建窗口,“啟動代碼”沒有這樣做,在第31行:

mRoot->initialise(false);

    另外還要說的是,OGRE作為一個跨平台的高層3D圖形庫,對圖形系統進行了高度抽象,這種抽象使用戶不需要關心底層技術(如OpenGL或Direct3D、win32或Xwindow),但程序的執行必然會用到底層功能(如具體渲染任務必然是OpenGL或Direct3D執行)。OGRE(或者其他很多開源程序庫)是這樣做到這一點的:用戶使用基類(如RenderSystem和RenderWindow)接口和OGRE進行交互,代碼執行時程序自動根據系統配置調用相應子類的實現來執行命令(這得益於面向對象的繼承性和多態性)。RenderSystem類的繼承圖如下:

對於我們,使用的是OpenGL圖形驅動,所以到程序執行時,實際使用的是GLRenderSystem的實現。其實RenderSystem壓根就是個抽象類,不能被實例化。

 

4. 創建 RenderWindow

    RenderWindow是對窗口的抽象,該窗口用來顯示渲染結果(對於離線渲染或渲染到紋理則不需要窗口)。創建窗口最簡單的方法是在調用Ogre::Root::initialise方法時傳入true作為第一個參數:

mWindow = mRoot->initialise(true, "Win Ogre");

    但“啟動代碼”為了代碼的清晰,使用了手動創建RenderWindow的方法:

int hWnd = 0;
Ogre::NameValuePairList misc;
misc["externalWindowHandle"] = Ogre::StringConverter::toString((int)hWnd);
mWindow = mRoot->createRenderWindow("Win Ogre", 800, 600, false, &misc);

注意上面使用的NameValuePairList類是用來構造參數的,你可能發現了,OGRE的很多參數都使用string數據類型。

 

5. 創建SceneManager,將渲染目標綁定到RenderWindow

    SceneManager類管理OGRE的場景圖形(Scene Graph),《Ogre 3D 1.7 Beginner's Guide》的Chapter 6中將SceneManager的功能總結為兩個方面:

  1. 管理Camera, SceneNode, Entity, Light等場景中的對象,作為Factory提供create方法如createEntity(), createLight()(也負責釋放它們);
  2. 管理場景圖形,包括維護場景樹的可用性,計算節點的Transform信息,隱藏面剔除(Culling)。

    SceneManager不是Singleton,可以從Root創建一個(或多個)SceneManager,“啟動代碼”的第41行創建了一個普通類型的SceneManager:

mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC);

    有了SceneManager,就可以從這個Factory創建場景的對象了,主要是Camera, SceneNode, Entity, Light,構建場景(構建場景樹)留到后面說,這里說Camera和RenderWindow的對應關系。

    Camera是場景到窗口輸出的媒介,負責將3D場景映射到2D窗口,這個映射涉及到另一個類Viewport,Viewport將Camera對場景的“拍攝”結果“貼”到窗口的全部可繪制區域的一個矩形部分。一個Root可以有多個SceneManager,一個SceneManager中也可以有多個Camera,但每個Camera都需要一個Viewport對應到窗口的一個矩形區域。現在你應該知道怎樣把一個場景的不同視角,或者多個場景繪制到一個窗口的不同區域了吧。

    “啟動代碼”中創建Camera的代碼在第43行:

mCamera = mSceneMgr->createCamera("PlayerCam");
mCamera->setNearClipDistance(5);

其中也設置了Camera的近裁剪面。“啟動代碼”中創建建Viewport的代碼在隨后的第46行:

// Create one viewport, entire window
Ogre::Viewport* vp = mWindow->addViewport(mCamera);
vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
// Alter the camera aspect ratio to match the viewport
mCamera->setAspectRatio(
    Ogre::Real(vp->getActualWidth()) / Ogre::Real(vp->getActualHeight()));

    其中也設置了Viewport背景顏色和Camera長寬比例,addViewport是RenderWindow的方法,並以Camera為參數,這樣就把RenderWindow和Camera聯系起來了,正如我們所分析的。另外addViewport方法還有其他參數用來指定Viewport在窗口的哪一區域,上述代碼使用了缺省參數,即將Viewport對應到整個窗口。

    同第4節最后說的,RenderWindow是抽象類,具體的和窗口相關的功能實際是由子類實現的,在windows上,這個子類是Win32Window。

 

6. 加載資源

    OGRE的資源文件是OGRE的一個特色,最常見的資源文件莫過於Mesh(.mesh)和Material(.material)了,注意Mesh是一個可渲染物體,而不僅僅是一個網格,Material定義可渲染物體除幾何信息外的其他所有屬性,可以是而不限於顏色、紋理、着色器什么的。

    資源文件的一個好處就是當修改了物體的外觀等信息之后,不需要重新編譯程序,如果將物體的頂點數據什么的寫在代碼里那就當然要重新編譯啦。資源文件的缺點,程序在啟動時要對資源文件進行解析(分析腳本),這增加了程序啟動時間,這也是HelloWorld程序需要好幾秒之后才能看見圖形的原因。另一個缺點,對於初學者來說,最初可能就是想畫一個長方體,但在OGRE里,你就需要創建Mesh資源。當然啦,OGRE作為面向而不限於3D游戲的3D引擎,強大的資源管理能力可以大大提高開發效率,應當說,正是資源文件的龐雜換來了程序代碼的簡潔。

    有關OGRE對資源文件處理的細節見:Resources and ResourceManagers,要使用一個程序外定義(即腳本定義)的資源,需要:

  1. 用ResourceGroupManager::addResourceLocation方法添加資源文件所在目錄;
  2. 用ResourceGroupManager::declareResource方法聲明(declare)資源,可選的;
  3. 用ResourceGroupManager::initialiseResourceGroup或ResourceGroupManager::initialiseAllResourceGroups方法初始化所添加目錄中的資源文件腳本;
  4. 默認下,資源文件的數據直到該資源使用時才被加載,如一個紋理的圖片並不是在紋理定義時加載,而是在紋理被首次使用時加載至內存,也可以手動調用ResourceGroupManager::loadResourceGroup加載。

    上面的第一步在“啟動代碼”中對應代碼如下,位於第54-67行:

Ogre::ConfigFile cf; cf.load("resources.cfg");
Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
Ogre::String secName, typeName, archName;
while( seci.hasMoreElements() ){
    secName = seci.peekNextKey();
    Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
    Ogre::ConfigFile::SettingsMultiMap::iterator i;
    for( i=settings->begin(); i!=settings->end(); ++i ){
        typeName = i->first;
        archName = i->second;
        Ogre::ResourceGroupManager::getSingleton().
            addResourceLocation(archName, typeName, secName);
    }
}

    其中"resources.cfg"是資源文件名字,文件內容如下(為了簡潔,刪減了一些):

# Resources required by the sample browser and most samples.
[Essential]
Zip=../../media/packs/SdkTrays.zip
Zip=../../media/packs/profiler.zip
FileSystem=../../media/thumbnails

# Common sample resources needed by many of the samples.
# Rarely used resources should be separately loaded by the
# samples which require them.
[Popular]
FileSystem=../../media/fonts
FileSystem=../../media/models
Zip=../../media/packs/cubemap.zip
Zip=../../media/packs/cubemapsJS.zip

[General]
FileSystem=../../media

# Materials for visual tests
[Tests]
FileSystem=../../media/../../Tests/Media

    Ogre::ConfigFile是一個資源配置文件解析的輔助類,類似於XML解析,和代碼對應,Essential、Popular、Popular是secName,這是OGRE為方便對資源進行管理而分的組,每個settings的格式為:typeName= archName(參數類型=參數值)。

    注意下面這句代碼:

Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);

    OGRE有很多xxxManager類,它們負責管理特定事物,如ResourceGroupManager提供對資源組的操作,LogManager提供寫日志文件功能,SceneManager管理場景圖形等等。這些Manager中的很多,比如LogManager和ResourceGroupManager使用Singleton設計模式,可以調用靜態方法getSingleton獲取全局唯一的實例。但SceneManager不是單例模式的,因為一個Root可以有多個場景圖形(場景樹)。

    “啟動代碼”中declare資源的代碼如下,在第68行:

Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    這里采取的是簡單粗暴的方式,解析資源目錄的所有腳本,怪不得程序啟動后要等那么久了。

    注意declare資源有時不能進行的太早,例如,不能早於RenderSystem的初始化和RenderWindow的創建,如果使用OverlaySystem,也不能早於OverlaySystem的創建。原因同第3節最后分析的,因為資源的解析具體是由子類實現的,在沒有確定使用的是RenderSystem和RenderWindow的哪個子類前,不能確定使用哪個解析資源的子類,例如,RenderSystem的不同子類GLRenderSystem或D3D9RenderSystem,使用的紋理解析的類不同,如下圖:

 

    截止目前你應該了解plugins.cfg、ogre.cfg、Ogre.log、resources.cfg文件的作用了吧。

 

7. 構造場景樹

    目前大多數3D圖形庫采用了場景圖形(Scene Graph)技術,即用場景樹來組織場景的所有物體,場景樹的節點可分為兩種:分支節點和葉節點。分支節點SceneNode(繼承自Node)主要負責空間位置變化,葉節點可以為:Entity(可繪制實體),Light,Camera等。關於場景樹,最需要了解的是,葉節點對象在世界坐標中的最終位置是由父節點級聯決定的。一個典型的場景樹如下圖:

    Entity3的世界坐標由Node5、Node4、Node2聯合決定(世界坐標計算方式可以修改)。每個Node都有一些空間變換方法:setPosition、setOrientation、setScale、translate、rotate、scale,其中前三個是覆蓋式修改,后三個是增量式修改。用Ogre::Node::addChild方法連接兩個Node,用Ogre::SceneNode::attachObject方法連接Node和葉節點。上圖有一個容易混淆的地方:Light1是不是只作用於Node4子樹呢,答案是否定的,Light1作用於整個場景樹,Camera1也是類似的。Light和Camera總是作用於整個場景樹,其上級Node只起到對其世界坐標進行變換的作用。

    注意,一個可用的場景樹不能有循環路徑,如下圖的場景樹,OGRE程序運行時會拋出異常:

    可以調用Ogre::SceneManager::setShadowTechnique方法設置陰影,Ogre::SceneManager::setSkyBox方法設置天空,Ogre::SceneManager::setFog方法設置霧效果。

    “啟動代碼”構建了一個簡單的場景,代碼在第71-91行:

mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.2f, 0.2f, 0.2f));

Ogre::Entity* entNinja = mSceneMgr->createEntity("entNinja", "ninja.mesh");
Ogre::SceneNode* nodeNinja = mSceneMgr->createSceneNode("nodeNinja");
mSceneMgr->getRootSceneNode()->addChild(nodeNinja);
nodeNinja->attachObject(entNinja);
Ogre::Entity* entSphere = mSceneMgr->createEntity("entSphere", "sphere.mesh");
Ogre::SceneNode* nodeSphere = mSceneMgr->createSceneNode("nodeSphere");
mSceneMgr->getRootSceneNode()->addChild(nodeSphere);
nodeSphere->attachObject(entSphere);
nodeNinja->setPosition(-50,-100,0);
nodeSphere->translate(50,0,100);
Ogre::Light* pointLight1 = mSceneMgr->createLight("pointLight1");
pointLight1->setType(Ogre::Light::LT_POINT);
pointLight1->setDiffuseColour(Ogre::ColourValue::White);
pointLight1->setSpecularColour(Ogre::ColourValue::White);
pointLight1->setPosition(-400,200,-200);

mCamera->setPosition(Ogre::Vector3(0,0,-250));
mCamera->lookAt(Ogre::Vector3(0,0,0));

 

8. 渲染循環

    調用Root::startRendering方法進入渲染循環,渲染結束釋放Root:

Ogre::LogManager::getSingleton().logMessage(">>Rendering");
mRoot->startRendering();

// 釋放資源,目前只需釋放Root
delete mRoot;

其中使用LogManager這個Singleton類的功能向日志文件中寫入了信息。

    startRendering函數實現如下:

void Root::startRendering(void)
{
    assert(mActiveRenderer != 0);
 
    mActiveRenderer->_initRenderTargets();
 
    // Clear event times
    clearEventTimes();
 
    // Infinite loop, until broken out of by frame listeners
    // or break out by calling queueEndRendering()
    mQueuedEnd = false;
 
    while( !mQueuedEnd )
    {
        //Pump messages in all registered RenderWindow windows
        WindowEventUtilities::messagePump();
 
        if (!renderOneFrame())
            break;
    }
}

    Root::renderOneFrame方法代碼如下:

bool Root::renderOneFrame(void)
{
    if(!_fireFrameStarted())
        return false;
 
    if(!_updateAllRenderTargets())
        return false;
 
    return _fireFrameEnded();
}

    也可以自行構造渲染循環,這樣就可以解決“啟動代碼”點擊關閉窗口程序也不退出的問題了:

while(true)
{
    // Pump window messages for nice behaviour
    Ogre::WindowEventUtilities::messagePump();
 
    if(mWindow->isClosed())
    {
        return false;
    }
 
    // Render a frame
    if(!mRoot->renderOneFrame()) return false;
}

 

9. 總結

    本文要點總結如下:

  1. OGRE程序總是從創建Root實例開始;
  2. OGRE的很多xxxManager類使用了Singleton設計模式,可以調用類的靜態方法getSingleton來獲取全局唯一的類實例,如:ResourceGroupManager、LogManager、TextureManager、MeshManager等等,但SceneManager不是;
  3. OGRE對圖形系統進行了高度抽象,用戶使用基類接口和OGRE交互,程序執行時會自動根據系統配置調用特定子類的實現,如RenderSystem和RenderWindow;
  4. OGRE的場景數據用場景圖形(Scene Graph)來組織,其本質是樹(Tree),由SceneManager來組織和管理;
  5. 每個Camera通過一個Viewport映射到窗口的一個矩形部分(當然也可以渲染到紋理);
  6. OGRE的資源文件是其一大特色,資源需要特定程序加載到執行期間的程序;
  7. OGRE采用配置文件,本文涉及的有plugins.cfg、ogre.cfg、Ogre.log、resources.cfg文件,你應該清楚它們的作用了;
  8. 場景樹的可用性要求場景樹不能有循環。

    好了,關於OGRE的基本啟動過程你應該了解的吧,本文並沒涉及WindowEventListener、FrameListener等一些事件的處理,也沒有涉及鼠標鍵盤輸入,甚至,“啟動代碼”運行起來后關閉窗口都不能結束程序,這些留到以后再講吧。

 

參考文獻:

OGRE WIKI Basic Tutorial 6: The Ogre Startup Sequence

OGRE WIKI: Resources and ResourceManagers

Ogre 3D 1.7 Beginner's Guide (Felix Kerger, 2010)

OGRE API Reference(OGRE SDK下載包中有離線版本)

OGRE 1.9 的第一個程序(OGRE HelloWorld程序)

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM