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程序)

相关文章
相关标签/搜索