Ogre学习记录(一)-启动流程

        Ogre给的教程框架还是很友好的,继承其所给的BaseApplication类,只用重写createScene函数,就可以渲染出mesh模型了。但是为了更好的学习,当然要搞清楚BaseAplication中的每一段代码都做了什么。官方的第Basic Tutorial第6节讲的很清楚。

点击打开链接

1.wiki上的tutorial给定建议启动流程

1.create the root object. 创建根对象

2.define the resource that Ogre will use. 定义一个Ogre将要使用的资源文件

3.choose and setup the RenderingSystem. 选择和启动一个渲染器(例如,OpenGL,DirectX)

4.create Rendering Window. 创建一个Ogre渲染的窗口

5.Initialize the resources that you are going to use. 初始化所有要使用的资源

6.create a scene use the resource. 利用资源创建一个场景。

7.set up any thirdparty puligins and library. 设置所有的第三方插件与库

8.create any numbers of frame listeners. 创建任意数量的frameListener

9.start the render loop. 开始渲染循环

        当然,wiki上也说了,你可以不按着规矩来,但是1-4一定要乖乖的按着顺序做,7-8可以放在5-6之前,但是这样在resources和secne创建完成之前第三方插件和frameListener是无法获取任何和resource以及scene相关的内容的。

2.具体实现

2.1创建根对象

        根对象是Ogre库的核心部分,是你想用Ogre引擎做任何事情之前必须首先初始化的东西,初始化跟对象时,可以直接调用其构造函数:这里我们传入了一个参数,告诉Ogre的根对象,我们所需加载的插件配置文件名称。
#ifdef _DEBUG
    mPluginsCfg = "plugins_d.cfg";
#else
    mPluginsCfg = "plugins.cfg";
#endif
 
    // construct Ogre::Root
    mRoot = new Ogre::Root(mPluginsCfg);
 
    return true;

        根对象root的构造函数有3个参数,均有默认值:

参数类型:String默认值描述
pluginFileName“plugin.cg”插件配置文件的名称和路径
configFileName"ogre.cfg"生成的ogre配置文件名称和路径
logFileName"Ogre.log"生成的log文件名称和路径



         


        plugin.cfg是必须事先编写好的,告诉根对象需要加载哪些插件,否则Ogre引擎直接启动失败,并抛出异常,至于plugin.cfg文件,在你编译好的SampleBroswer目下就有,拷贝过来用就行了,至于Ogre的插件系统我也还没有弄清楚,就先不详细说了。

        后面两个都是Ogre输出的文件,log好理解,就是日志信息了,出了什么错,什么异常,都会记录在里面,在Linux下其实这些信息都打印在终端里了,至于windows,估计出了问题,就要好好看log了。至于ogre.cfg,是root为你保存的第一次开启引擎时记录的信息,例如:显卡,渲染器类型,全屏,分辨率,垂直同步等等,还记得SampleBroswer第一次开启时,会有一个小Dialog让你配置选项么,但是第二次启动就没有了,就是因为Ogre为你保存了你的配置,不需要你反复的输入,当然如果你希望换个配置,但是在程序内部又没有提供相应的接口,那么直接删掉这个文件即可,再启动时,Ogre会让你重新配置系统信息的。

2.2定义资源文件信息

        如果细心你会发现在SampleBroswer目录还有一个cfg文件,resource.cfg,用vim打开瞧一瞧,很容易就明白了,【】内为每个配置的section,被=赋值的是每个具体的settings,这里的settings主要描述了资源所在的绝对路径,很简单,就不多说了。
        第二步就是告诉Ogre,读取哪个资源配置文件,从而让Ogre知道每个将要加载的资源具体所在的位置。
#ifdef _DEBUG
    mResourcesCfg = "resources_d.cfg";
#else
    mResourcesCfg = "resources.cfg";
#endif

// set up resources
// Load resource paths from config file
Ogre::ConfigFile cf;
cf.load(mResourcesCfg);
// Go through all sections & settings in the file
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);
    }
}
        记住,根对象一定是第一个创建的,其后才能加载资源文件,否则将发生错误。

2.3选择一个渲染系统

        这个没什么好说的,无非就是OpenGL或者DX,我在Fedora下也没什么选择,直接OpenGL完事。
RenderSystem *rs = mRoot->getRenderSystemByName("OpenGL Rendering Subsystem");
mRoot->setRenderSystem(rs);
rs->setConfigOption("Full Screen", "No");
rs->setConfigOption("Video Mode", "1366 x 768 @ 32-bit colour");
        另外,选择好了渲染系统后,这里还是继续配置一些相关的信息,例如是否全屏拉,分辨率拉,显卡类型拉很多很多,当然,如果你想把这个选择的权利交给用户,你可以用根对象的showConfigDialog()方法来为你弹出一个配置对话框,十分方便。
// configure
// Show the configuration dialog and initialise the system
if(!(mRoot->restoreConfig() || mRoot->showConfigDialog()))
{
    return false;
}
        这里有个restoreConfig()混在里面,是为了实现上述说过的,第一次配置完后,Ogre会为你生成一个ogre.cfg文件保存你上次的配置,这样就不用每次开启程序时都要设置一遍了。

2.4创建渲染窗口

        第三步之前的编译运行后,如果你观察啊终端输出或者log文件,会发现Ogre什么都没有做就退出了,其实并不是什么都没有做,只是没有找到一个可供它渲染的窗口,于是它自动退出了,但是前面所提到的加载插件,加载资源,Ogre可是一个也没落下。用以下方法就可以简单的创建一个渲染窗口了:
Ogre::RenderWindow* mWindow;
mWindow = mRoot->initialise(true, "Render Window");
        当然,如果你想要把Ogre嵌入你的win32窗口,或者其他的什么GUI窗口,Linux下GUi如Qt等等,wiki也给出了答案:
mRoot->initialise(false);
HWND hWnd = 0;  // Get the hWnd of the application!
NameValuePairList misc;
misc["externalWindowHandle"] = StringConverter::toString((int)hWnd);
RenderWindow *win = mRoot->createRenderWindow("Main RenderWindow", 800, 600, false, &misc);
        注意到,这与简单的初始化一个窗口唯一的区别就是,在调用Ogre::RenderWindow的initialise方法时,没有直接使用true参数,而是在后面通过HWND获取你想要嵌入的窗体的句柄,至于这个句柄怎么获得,那就取决于你用的GUI类型了,之后根对象的createRenderWindow()方法可以帮你将Ogre的渲染窗口指定为你所提供的其它GUI如win32已经建立的窗体,至于这些API具体怎么用大家去看官方手册吧。

2.5加载资源

2.6创建场景信息:包括entity,node,light等等

        这里我将这两部放在一起,我是这么理解的,如果1-4步只是在程序启动时运行一次,也就是我们写程序通常使用的initial的话,那么剩下的这些内容,可能会在程序运行时动态的运行,wiki也说了,其实在真正的大型游戏或者其它什么3D软件中,资源并不是一次全部加载的,而是按需加载的,举个例子,当你玩WOW和朋友在黑暗神庙开25人团的时候,程序不会蛋疼到把奥格瑞玛的地形信息和3D模型什么的加载到内存里面去吧?否则为什么你炉石完了之后会有一段读条。
        所以从这里开始的第五步和第六步,就是可能在程序中多次出现的了,先加载资源,再创建场景,当然具体怎么做,要使用到Ogre的一个类,叫做ResouceManager,如果有兴趣,可以去学习学习,下面给出链接:
        当然,如果你的程序很小,那么可以直接一次将所有资源全部加载,示例代码如下:
// Set default mipmap level (note: some APIs ignore this)
Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
// initialise all resource groups
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
        至于第六步也就是创建场景信息,我就不多说了,内容太多,可以自己去wiki上学习,讲的很清楚。

2.7加载第三方插件

2.8创建任意数量的帧监听器(FrameListener)

        第三方插件我暂时还没有碰到过,FranmeListener可以理解为一个回调函数吧,这样在每帧运行时,都可以嵌入我们想要做的一些其他事情,如数据处理,动画播放,网络通信等等,现在还没有具体深入,也不详细描述了,免得被鄙视。

2.9进入渲染循环

        Ogre通过调用Ogre::Root::startRendering()就可以进入渲染循环了,当然,Ogre的渲染循环具体是那样的呢,wiki上也解释的很清楚,可以理解如为如下代码:
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;
    }
}
        这里其实循环最关键的就是while中的renderOneFrame这个函数的,这个函数可以这样理解:
bool Root::renderOneFrame(void)
{
    if(!_fireFrameStarted())
        return false;
 
    if(!_updateAllRenderTargets())
        return false;
 
    return _fireFrameEnded();
}
        所以我们可以在go方法中写入一个简单的循环,如下代码所示:
while(true)
{
    // Pump window messages for nice behaviour
    Ogre::WindowEventUtilities::messagePump();
 
    if(mWindow->isClosed())
    {
        return false;
    }
 
    // Render a frame
    if(!mRoot->renderOneFrame()) return false;
}
        这样,直到窗口关闭,或者renderOneFrame()返回false,Ogre不会停止对窗体的渲染。
        那么,renderOneFrame什么时候会返回false呢,这就又要提到farmeLisener和frameRenderingQueued()等方法了,其实理解起来也很简单,就是一个回调函数,会在每帧渲染时调用,这样就可以在这个回调函数中做我们想做的任何事件,如捕获输入信息,改变模型位置、大小,进行网络通信等,如果在某一帧我们捕捉到用户输入ESC键,我们理解为“退出”,那么我们可以让frameRenderingQueued()返回false,这样Ogre就会停止渲染,正常卸载资源与插件,并退出了。

PS:

        真的觉得Ogre是初学者学习3D引擎最好的选择了,没有之一,先不说它开不开源,Ogre的wiki上资源太丰富了,wiki上的tutorials一步一步引导你进入Ogre的世界,学到很多3D引擎相关的概念和只是,除了关于引擎本身的教程外,还有一些列的其它相关教程,如DCC tutorials,CEGUI的相关链接,OIS的相关教程,还列出了很多支持Ogre的第三方插件和子系统,并且Ogre的社区是十分活跃的,如果你有什么问题,抛到论坛上很快就会有人回复你,当然,不要问一些傻傻的问题,否则你将得到的答案绝对是RTFM。虽然接触Ogre才2周,但是已经完全喜欢上了这个东西,每天都像当初玩wow一样搞到一两点,但是,收获也是大大滴,不是吗。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值