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

 

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

  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文檔)html

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

    本節全部代碼以下,能夠先迅速瀏覽,而後看後面詳細解釋,後面將用「啓動代碼」來指代這段代碼:windows

  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. 啓動過程概覽api

    咱們概要地看OGRE的啓動,OGRE WIKI Basic Tutorial 6: The Ogre Startup Sequence中摘出下面這段,注意它和上面的代碼(「啓動代碼」)是有差異的,各步驟的順序不一樣:ide

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圖,就大體理解吧):oop

    看完後面的詳細解釋後能夠回過頭來看這段,那時你就會對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的世界座標由Node五、Node四、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程序)

相關文章
相關標籤/搜索