Ogre中级教程(八):示例框架揭秘

  中级教程八
  示例框架揭秘
  示例框架揭秘初学者教程0:场景背后的秘密——示例框架揭秘
        目录
        [隐藏]
          1 介绍
          2 示例框架
          3 示例程序
            3.1 基础骨架
            3.2 一步接一步
            3.3 让我们开始!
            3.4 初始化
            3.5 添加资源定位
            3.6 初始化Ogre核心
            3.7 创建场景管理器
            3.8 创建摄影机镜头
            3.9 创建视口
            3.10 创建资源监听器
            3.11 初始化资源
            3.12 创建场景
            3.13 销毁场景
          4 添加帧监听器
            4.1 什么是帧监听器
            4.2 它的工作方式
            4.3 增加代码
          5 增加Ogre基本输入
          6 移动摄影机镜头
            6.1 移动摄影机镜头
            6.2 OgreApplication additions
            6.3 帧开始函数
            6.4 修改createFrameListener
            6.5 处理非缓冲输入更新
          7 其它各种改进
          8 最终代码
            8.1 OgreApplication.h
            8.2 OgreApplication.cpp
          9 示例用法
            9.1 MyApplication.h
            9.2 MyApplication.cpp


  介绍
  如果你看看Ogre演示程序的代码,并读读Wiki教程,你可能注意到了ExampleApplication和ExampleFramelistener的使用。你可能会奇怪:示例框架在场景后面都做了写什么事情呢?对于Ogre编程来说,可以肯定的是要比

ExampleApp theApp;
theApp.go();
这点儿代码多得多,并且重载了createScene()函数。本教程将准确描述示例框架的工作方式。我们将通过框架实现我们的工作——并以包含所有示例框架代码的可以替代的Ogre应用程序类结束。注意:如果那你特别特别想拷贝粘贴代码,请选择正确的代码——在最最后的代码:-)
  我们将逐步完成我们的工作,向“OgreStein类”中增加代码。注意2:如果你要使用Mac OS X,[这里有一些MacOSX命令行编译的提示
  http://www.ogre3d.org/wiki/index.php/MacOsXCommandLineCompiling],可供参考。注意3:如果由于对OIS的改变而使你在Eihort(Ogre
  1.4.X)下编译这个框架遇到任何麻烦,论坛上的[这个帖子
  http://www.ogre3d.org/phpBB2/viewtopic.php?t=31659]可能会有所帮助。
  示例框架
  示例框架包括两个类:ExampleApplication(在ExampleApplication.h中)和ExampleFramelistener(在ExampleFramelistener.h中)。它们都位于Samples/Include目录下,用于Ogre演示程序之中。事实上,此框架被设计用来快速编写演示程序,不是一个大型设计项目。可能无法满足你想要的更大更严谨的设置使用要求。但是,它节省了大量的时间。而且它可以让你非常快地做一些Ogre测试。一个使用示例框架的应用程序以一个派生于ExampleApplication的类开始。

class GroovieDemo : public ExampleApplication
{
 // details ...
};
即意味着,所有ExampleApplication能做的事,GroovieDemo也都能做。
  GroovieDemo需要定义ExampleApplication::createScene()函数,因为它是一个纯虚函数,所以GroovieDemo变成:

class GroovieDemo : public ExampleApplication
{
 virtual void createScene()
 {
  // details ...
 }
};
然后,你只要创建GroovieDemo实例,调用它的go()函数就行了。这样你就得到了最基本的Ogre演示程序。但是...ExampleApplication实际做了什么呢?

  示例程序
  这就是所发生的事:
go()
   setup()
      new Ogre::Root
      setupResources()
         // parses resources.cfg
      configure()
         // shows the Ogre config dialog which configures the render system.
         // constructs a render window.
      chooseSceneManager();
         // the scenemanager decides what to render
      createCamera();
         // we need a camera to render from
      createViewports();
         // a viewport to render to
      createResourceListener();
         // Create any resource listeners (for loading screens)
      loadResources();
         // Now we can load the resources: all systems are on-line.
      createScene();
         // Now that the system is up and running: create a scene to render.
   mRoot->startRendering();
   // Kick off Ogre
就像你看到的,它先创建一个Ogre::Root实例。然后解析resources.cfg,显示配置对话框,装载渲染系统,构造渲染窗口,选择场景管理器,创建摄影机镜头和视口,装载资源并开始渲染。

  基础骨架
  创建一个文件,取名OgreApplication.h并粘贴如下代码:
#ifndef __OgreApplication_h__
#define __OgreApplication_h__

#include <ogre.h>

using namespace Ogre;

class OgreApplication
{
public:
   OgreApplication();
   virtual ~OgreApplication();

   virtual void go();

protected:
   virtual bool initialise();
   virtual bool initOgreCore();

   virtual void createSceneManager();
   virtual void createCamera();
   virtual void createViewports();
   virtual void createResourceListener();

   virtual void addResourceLocations();
   virtual void initResources();

   virtual void createScene() = 0; // I am pure virtual, override me!
   virtual void destroyScene();

   Root *mRoot;
   Camera* mCamera;
   SceneManager* mSceneMgr;
   RenderWindow* mWindow;
};
 
#endif // __OgreApplication_h__
你会注意到一件事,就是某些函数命名不同于示例框架。那是因为新函数名更准确反映函数的功能。好了。这就是我们的OgreApplication所需要的东西,所以让我们开始吧!

  一步接一步
  好了。让我们创建一个新文件,取名为OgreApplication.cpp,并粘贴如下代码:
#include "OgreApplication.h"

//-------------------------------------------------------------------------------------
OgreApplication::OgreApplication()
 : mRoot(0)
{
}

//-------------------------------------------------------------------------------------
OgreApplication::~OgreApplication()
{
   delete mRoot;
}
如你所见,mRoot在构造函数中被赋为空值,并在析构函数中被删除。接下来,我们将向此文件增加代码。
  让我们开始!
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
void OgreApplication::go()
{
   if (!initialise())
      return;

   mRoot->startRendering();

   // clean up
   destroyScene();
}
这段代码通过调用'initialise()'启动Ogre程序。如果initialise()失败,则程序返回,游戏结束。然后它调用mRoot上的startRendering()。最后,destroyScene()被调用做收尾工作,像清除我们在createScene()中创建的那一大堆东西。下面的是Root::startRendering()所做的工作:

void Root::startRendering(void)
{
   assert(mActiveRenderer != 0);

   mActiveRenderer->_initRenderTargets();

   // Clear event times
   for(int i=0; i!=3; ++i)
      mEventTimes[i].clear();

   // Infinite loop, until broken out of by frame listeners
   // or break out by calling queueEndRendering()
   mQueuedEnd = false;

   while( !mQueuedEnd )
   {
      //Allow platform to pump/create/etc messages/events once per frame
      mPlatformManager->messagePump(mAutoWindow);

      if (!renderOneFrame())
         break;
   }
}
它初始化渲染目标,清除事件时间,开始渲染循环,直至通过调用queueEndRendering()将mQueueEnd被置为false才停止。后文有关于Root::renderOneFrame()的更详细介绍。

  初始化
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
bool OgreApplication::initialise()
{
   mRoot = new Root();

   // add resource locations
   addResourceLocations();

   // if we cannot initialise Ogre, just abandon the whole deal
   if ( !initOgreCore() ) return false;

   createSceneManager();
   createCamera();
   createViewports();

   // Set default mipmap level (NB some APIs ignore this)
   TextureManager::getSingleton().setDefaultNumMipmaps(5);

   // Create any resource listeners (for loading screens)
   createResourceListener();

   // Initialise resources
   initResources();

   // Create the scene
   createScene();

   return true;
};
这是示例程序的释义。创建Ogre::Root。解析并添加资源定位。显示配置屏(initOgreCore)。创建在前一步窗口中所选定的渲染系统。创建场景管理器。创建并设置摄影机镜头。创建视口并与摄影机镜头挂钩。解析并装载资源。创建场景。

  添加资源定位
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
void OgreApplication::addResourceLocations()
{
   // Load resource paths from config file
   ConfigFile cf;
   cf.load("resources.cfg");

   // Go through all sections & settings in the file
   ConfigFile::SectionIterator seci = cf.getSectionIterator();

   String secName, typeName, archName;
   while (seci.hasMoreElements())
   {
      secName = seci.peekNextKey();
      ConfigFile::SettingsMultiMap *settings = seci.getNext();
      ConfigFile::SettingsMultiMap::iterator i;
      for (i = settings->begin(); i != settings->end(); ++i)
      {
         typeName = i->first;
         archName = i->second;
         ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
      }
   }
}
此函数简单地解析了resources.cfg并添加了资源定位。其中使用了Ogre::ConfigFile类。
  初始化Ogre核心
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
bool OgreApplication::initOgreCore()
{
   // Show the configuration dialog and initialise the system
   // You can skip this and use root.restoreConfig() to load configuration
   // settings if you were sure there are valid ones saved in ogre.cfg
   if(mRoot->restoreConfig() || mRoot->showConfigDialog())
   {
      // If returned true, user clicked OK so initialise
      // Here we choose to let the system create a default rendering window by passing 'true'
      mWindow = mRoot->initialise(true);
      return true;
   }
   else
   {
      return false;
   }
}
此函数完成下面两件事之一:如果Root::restoreConfig()成功,则意味着当前有可用的配置,并将该信息应用于配置Ogre。如果没有可用配置,则显示配置对话框。你会问了,这个Ogre核心又是怎么初始化的呢?它所做的全部工作都显示在配置对话框中了,还是还有些东西发生在场景背后呢?是的,你说的对。配置对话框先调用Root::restoreConfig()。然后调用Root::getRenderSystem()。
  Root::getAvailableRenderers()返回一个可用渲染器的列表(惊奇吧!)
  RenderSystem::getConfigOptions()返回一个带有可用渲染系统选项的ConfigOptionMap。
  RenderSystem->setConfigOption(value, value)用来设置选项。例如:
selectedRenderSystem->setConfigOption("Full Screen","No"); 
selectedRenderSystem->setConfigOption("Video Mode","800 x 600 @ 16-bit colour");
selectedRenderSystem->setConfigOption("Allow NVPerfHUD","No");
selectedRenderSystem->setConfigOption("Anti aliasing","None");
selectedRenderSystem->setConfigOption("Floating-point mode","Fastest");
selectedRenderSystem->setConfigOption("Rendering Device","RADEON 9200");
selectedRenderSystem->setConfigOption("VSync","No");
RenderSystem::validateConfigOptions()被用来在调用Root::setRenderSystem(selectedRenderSystem)之前审核配置选项。然后,Root保存配置:Root::saveConfig()
  当这些完成时,就可以调用Root::initialise了。例如:
RenderWindow* Root::initialise(bool autoCreateWindow, const String& windowTitle)
{
   if (!mActiveRenderer)
     OGRE_EXCEPT(Exception::ERR_NO_RENDERSYSTEM_SELECTED,
     "Cannot initialise - no render "
     "system has been selected.", "Root::initialise");

   if (!mControllerManager)
      mControllerManager = new ControllerManager();

   mAutoWindow =  mActiveRenderer->initialise(autoCreateWindow, windowTitle);

   mResourceBackgroundQueue->initialise();

   if (autoCreateWindow && !mFirstTimePostWindowInit)
   {
      oneTimePostWindowInit();
      mAutoWindow->_setPrimary();
   }

   // Initialise timer
   mTimer->reset();

   // Init plugins
   initialisePlugins();

   mIsInitialised = true;

   return mAutoWindow;

}
Ogre初始化的例子,还可以参看本Ogre Wiki的其它部分。
  创建场景管理器
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
void OgreApplication::createSceneManager()
{
   // Create the SceneManager, in this case a generic one
   mSceneMgr = mRoot->createSceneManager(ST_GENERIC);
}
要求Root创建一个通用场景管理器的实例。这里我们选择通过一个SceneType创建场景管理器实例,并且忽略表示实例名的第二个参数。在Ogre中,我们可以创建许多场景管理器的实例。每个摄影机属于一个场景管理器实例,所以在不同的场景管理器上创建多个摄影机令我们只要通过改变活动的摄影机就能够在它们之间转换。我们也可以选择像这样创建场景管理器:

mSceneMgr = mRoot->createSceneManager("DefaultSceneManager");
如果我们想要多个场景管理器,我们需要传递实例名:
mSceneMgr = mRoot->createSceneManager("DefaultSceneManager", "MainOgreApplicationInstance");
要获取一个场景管理器实例可以通过Ogre::Root或Ogre::Camera:
mCamera->getSceneManager("MainOgreApplicationInstance");
或者
mRoot->getSceneManager("MainOgreApplicationInstance");
创建摄影机镜头
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
void OgreApplication::createCamera()
{
   // Create the camera
   mCamera = mSceneMgr->createCamera("PlayerCam");

   // Position it at 500 in Z direction
   mCamera->setPosition(Vector3(0,0,500));
   // Look back along -Z
   mCamera->lookAt(Vector3(0,0,-300));
   mCamera->setNearClipDistance(5);
}
要求场景管理器创建一个名为“PlayerCam”的摄影机镜头。然后,用一些默认值配置摄影机镜头。这可能是一个你将要在自己的程序中重载的函数。
  创建视口
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
void OgreApplication::createViewports()
{
   // Create one viewport, entire window
   Viewport* vp = mWindow->addViewport(mCamera);
   vp->setBackgroundColour(ColourValue(0,0,0));

   // Alter the camera aspect ratio to match the viewport
   mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
}
创建资源监听器
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
void OgreApplication::createResourceListener()
{

}
这里你可以创建自定义的资源组监听器,诸如:装载进度条之类的。看看Samples/Common下的ExampleLoadingBar,你会注意到它派生自ResourceGroupListener。
  ResourceGroupListener在资源组装载过程中接受回调,详见API文档。
  初始化资源
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
void OgreApplication::initResources()
{
   // Initialise, parse scripts etc
   ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}
这里将所有资源组一步全都初始化了。如果你愿意,也可以手动初始化它们。
  ExampleLoadingBar在Ogre完全配置完成之前初始化“Bootstrap”资源组,这是因为他需要OgreCore.zip中的媒体文件。
ResourceGroupManager::getSingleton().initialiseResourceGroup("Bootstrap");
创建场景
  因为此函数为纯虚函数,所以我们再次不定义它。稍后,当我们从OgreApplication派生时,我们需要处理它。
  销毁场景
  向OgreApplication.cpp中增加如下代码:
//-------------------------------------------------------------------------------------
void OgreApplication::destroyScene()
{
}
此函数什么都不做,但是它必须定义。意思是,假如OgreApplication类的用户们不想在其后进行清除工作,它们可以选择不重载它。
  添加帧监听器
  至此我们的OgreApplication是相当有限的。它建立了Ogre系统并开始渲染,仅此而已。如果我们有能力每帧执行任务,像回应输入,更新逻辑等等,它其实还可以更棒。幸运的是,Ogre有一个帧监听器。

  什么是帧监听器
  如果你看过OgreFrameListener.h,你会发现下面这段:
struct FrameEvent
{
   Real timeSinceLastEvent;
   Real timeSinceLastFrame;
};


class _OgreExport FrameListener
{
   /*
   Note that this could have been an abstract class, but I made
   the explicit choice not to do this, because I wanted to give
   people the option of only implementing the methods they wanted,
   rather than having to create 'do nothing' implementations for
   those they weren't interested in. As such this class follows
   the 'Adapter' classes in Java rather than pure interfaces.
   */
public:
   virtual bool frameStarted(const FrameEvent& evt) { return true; }
   virtual bool frameEnded(const FrameEvent& evt) { return true; }

   virtual ~FrameListener() {}

};
意思就是,只要我们从FrameListener派生并重载两个函数:frameStarted和frameEnded,就可以给我们的OgreApplication增加帧监听支持。注意:如果我们不想重载,我们可以不重载那些函数。但是如果我们不重载其中一个,派生自FrameListener就毫无意义。

  它的工作方式
  还记得Root::startRendering()中的renderOneFrame函数吗?这就是:
bool Root::renderOneFrame(void)
{
   if(!_fireFrameStarted())
      return false;

   _updateAllRenderTargets();

   return _fireFrameEnded();
}
_fireFrameStarted()和_fireFrameEnded()是我们最感兴趣的。让我们来看看_fireFrameStarted:
bool Root::_fireFrameStarted(FrameEvent& evt)
{
   // Increment frame number
   ++mCurrentFrame;

   // Remove all marked listeners
   std::set<FrameListener*>::iterator i;
   for (i = mRemovedFrameListeners.begin();
      i != mRemovedFrameListeners.end(); i++)
   {
      mFrameListeners.erase(*i);
   }
   mRemovedFrameListeners.clear();

   // Tell all listeners
   for (i= mFrameListeners.begin(); i != mFrameListeners.end(); ++i)
   {
      if (!(*i)->frameStarted(evt))
         return false;
   }

   return true;

}
就在返回true前,它遍历所有注册的帧监听器,并调用它们的frameStarted(evt)。好了,现在我们知道他是如何工作的了。让我们增加一些代码。
  增加代码
  看看更新过的OgreApplication.h:
#ifndef __OgreApplication_h__
#define __OgreApplication_h__

#include <ogre.h>

using namespace Ogre;

class OgreApplication : public FrameListener
{
public:
   OgreApplication(void);
   virtual ~OgreApplication(void);

   virtual void go(void);

protected:
   virtual bool initialise();
   virtual bool initOgreCore();

   virtual void createSceneManager();
   virtual void createCamera();
   virtual void createViewports();
   virtual void createResourceListener();
   virtual void createFrameListener();

   virtual void addResourceLocations();
   virtual void initResources();

   virtual void createScene() = 0; // I am pure virtual, override me!
   virtual void destroyScene();

   // FrameListener overrides
   virtual bool frameStarted(const FrameEvent& evt);
   virtual bool frameEnded(const FrameEvent& evt);

   Root *mRoot;
   Camera* mCamera;
   SceneManager* mSceneMgr;
   RenderWindow* mWindow;
};
 
#endif // __OgreApplication_h__
注意OgreApplication现在如何从FrameListener派生,又如何重载两个帧监听器函数。另外,还要注意新函数:createFrameListener()。现在我们需要在OgreApplication.cpp中增加函数定义:

//-------------------------------------------------------------------------------------
bool OgreApplication::frameStarted(const FrameEvent& evt)
{
   return true;
}

//-------------------------------------------------------------------------------------
bool OgreApplication::frameEnded(const FrameEvent& evt)
{
   return true;
}

//-------------------------------------------------------------------------------------
void OgreApplication::createFrameListener()
{
   mRoot->addFrameListener(this);
}
createFrameListener函数向Root注册了帧监听器,传递this是因为OgreApplication就是一个帧监听器。如果想让我们的frameStarted和frameEnded函数每帧调用,我们需要注册我们的帧监听器。现在,我们需要回到我们的OgreApplication::initialise()函数,增加对createFrameListener的调用。

   // Create the scene
   createScene();

   createFrameListener();

   return true;
};
我们还未向帧监听器函数中增加任何代码。我们先要向我们的OgreApplication增加输入!
  增加Ogre基本输入
  让我们增加一些基本输入。提示:输入分为非缓冲输入和缓冲输入。如果希望详细了解可以参考基础教程4:帧监听器和非缓冲输入,以及基础教程五:缓冲输入。
//-------------------------------------------------------------------------------------
bool frameStarted(const FrameEvent& evt)
{
 mKeyboard->capture();
 mMouse->capture();
 
 if(processUnbufferedKeyInput(evt)==false)
  return false;
 if(processUnbufferedMouseInput(evt)==false)
  return false;
}
移动摄影机镜头
  至此输入系统准备完毕,可以让它发挥作用了:移动我们的摄影机镜头。
  移动摄影机镜头
  向OgreApplication.h中增加如下函数声明:
virtual void moveCamera();
向OgreApplication.cpp中增加如下函数定义:
//-------------------------------------------------------------------------------------
void OgreApplication::moveCamera()
{
   // Make all the changes to the camera
   // Note that YAW direction is around a fixed axis (freelook style) rather than a natural YAW (e.g. airplane)
   mCamera->yaw(mRotX);
   mCamera->pitch(mRotY);
   mCamera->moveRelative(mTranslateVector);
}
mRotX和mRotY是旋转摄影机镜头的,而mTranslateVector是移动摄影机镜头的。
  OgreApplication additions
  我们需要一些成员变量:
Real mMoveSpeed;
Degree mRotateSpeed;
float mMoveScale;
Degree mRotScale;
把它们添加在OgreApplication.h中的mTranslateVector和鼠标旋转变量附近。这些变量被用来计算移动速度:mMoveScale等于mMoveSpeed乘以自上一帧开始经过的时间,mRotScale等于mRotateSpeed乘以自上一帧开始经过的时间。

  帧开始函数
  让我们修改一下frameStarted:
// If this is the first frame, pick a speed
if (evt.timeSinceLastFrame == 0)
{
   mMoveScale = 1;
   mRotScale = 0.1;
}
// Otherwise scale movement units by time passed since last frame
else
{
   // Move about 100 units per second,
   mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
   // Take about 10 seconds for full rotation
   mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
}
这应该被添加在frameStarted的开始处。如果这是第一帧,变量被设置为固定值。移动范围是移动速度乘以自上一帧开始经过的时间。现在我们需要在frameStarted函数中放置一个moveCamera()调用。将moveCamera()添加在frameStarted末尾,正好在return
  true;之前。
moveCamera();
return true;
修改createFrameListener
  在OgreApplication.cpp中的OgreApplication::createFrameListener添加下面这些:
mRotateSpeed = 36;
mMoveSpeed = 100;
mMoveScale = 0.0f;
mRotScale = 0.0f;
是的,它们可能已经在OgreApplication构造函数中已经初始化过了,但是……(我还是要这么做,他是一个需要完成的部分。)
  mRotateSpeed和mMoveSpeed的值对于大多数场景都工作良好。
  处理非缓冲输入更新
  向OgreApplication.cpp中的OgreApplication::processUnbufferedInput添加如下代码:
if (mInputDevice->isKeyDown(KC_A))
{
   // Move camera left
   mTranslateVector.x = -mMoveScale;
}

if (mInputDevice->isKeyDown(KC_D))
{
   // Move camera RIGHT
   mTranslateVector.x = mMoveScale;
}

/* Move camera forward by keypress. */
if (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W) )
{
   mTranslateVector.z = -mMoveScale;
}

/* Move camera backward by keypress. */
if (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S) )
{
   mTranslateVector.z = mMoveScale;
}

if (mInputDevice->isKeyDown(KC_PGUP))
{
   // Move camera up
   mTranslateVector.y = mMoveScale;
}

if (mInputDevice->isKeyDown(KC_PGDOWN))
{
   // Move camera down
   mTranslateVector.y = -mMoveScale;
}

if (mInputDevice->isKeyDown(KC_RIGHT))
{
   mCamera->yaw(-mRotScale);
}

if (mInputDevice->isKeyDown(KC_LEFT))
{
   mCamera->yaw(mRotScale);
}
这是常规WASD移动,附带方向键移动和为了摄影机纵向移动的向上、向下翻页。改变大部分由mTranslateVector和mMoveScale完成。左右方向键会通过mRotScale摆动摄影机。

  其它各种改进
  待续
  最终代码
  以下是完整的基本程序框架:
  OgreApplication.h
  [OgreApplication.h http://www.ogre3d.org/wiki/index.php/OgreApplication_h]
  OgreApplication.cpp
  [OgreApplication.cpp http://www.ogre3d.org/wiki/index.php/OgreApplication_cpp]
  使用提示:如果你不想使用OgreApplication的子类,并想在你的程序中直接使用它,你需要实现OgreApplication.cpp中的createScene,并将声明中的=0去掉,使之仅为虚函数而不是纯虚函数。

  示例用法
  别忘了你可以任意重载函数。注意你的程序也是一个帧监听器,所以你可以重载frameStarted而不必将什么东西传给什么,因为它全发生在同一个类中。你将你的类从OgreApplication派生出来,并重载了OgreApplication::createScene()。你也可以重载其它函数,那是可选的。

  MyApplication.h
#ifndef __MyApplication_h__
#define __MyApplication_h__

#include "OgreApplication.h"

class MyApplication : public OgreApplication
{
public:
   MyApplication(void);
   virtual ~MyApplication();

protected:
   virtual void createScene();
   virtual bool frameStarted(const FrameEvent& evt);

   Entity* ogreHead;
   SceneNode* headNode;
};

#endif // #ifndef __MyApplication_h__
MyApplication.cpp
#include "MyApplication.h"

//-------------------------------------------------------------------------------------
MyApplication::MyApplication() : ogreHead(0), headNode(0)
{
}
//-------------------------------------------------------------------------------------
MyApplication::~MyApplication()
{
}
//-------------------------------------------------------------------------------------
void MyApplication::createScene()
{
 ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh");

 headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
 headNode->attachObject(ogreHead);

 // Set ambient light
 mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

 // Create a light
 Light* l = mSceneMgr->createLight("MainLight");
 l->setPosition(20,80,50);
}
//-------------------------------------------------------------------------------------
bool MyApplication::frameStarted(const FrameEvent& evt)
{
    // Just a silly example to demonstrate how much easier this is than passing objects to an external framelistener
    headNode->translate(0.0f, 0.005f, 0.0f);

    return OgreApplication::frameStarted(evt);
}
//-------------------------------------------------------------------------------------

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char *argv[])
#endif
{
   // Create application object
   MyApplication app;

   SET_TERM_HANDLER;

   try
   {
      app.go();
   }
   catch( Ogre::Exception& e )
   {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
      MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
      std::cerr << "An exception has occured: " << e.getFullDescription().c_str() << std::endl;
#endif
   }

   return 0;
}

#ifdef __cplusplus
}
#endif

OGRE(O-O Graphics Rendering Engine) 使用指南________________________________________________________________1 作者_________________________________________________________________________ 6 序____________________________________________________________________________7 教程的目的_________________________________________________________________ 7 读者要求___________________________________________________________________ 7 教程的由来_________________________________________________________________ 7 OGRE简介___________________________________________________________________ 8 OGRE特点_________________________________________________________________ 8 效率特性__________________________________________________________________8 平台和3D API 支持________________________________________________________ 8 网格Meshes_______________________________________________________________ 8 场景特性__________________________________________________________________9 特效______________________________________________________________________9 其它特性__________________________________________________________________9 OGRE中的模块_____________________________________________________________ 9 OgreMain 模块____________________________________________________________ 10 SDL 平台管理模块________________________________________________________ 11 Win32 平台管理模块_______________________________________________________11 BSP 场景管理_____________________________________________________________11 文件系统插件_____________________________________________________________11 GuiElement 插件__________________________________________________________ 11 OctreeSceneManager 插件___________________________________________________ 11 ParticleFX 插件___________________________________________________________ 12 Direct3D7 渲染系统插件____________________________________________________12 Direct3D8 渲染系统插件____________________________________________________12 SDL 渲染系统插件________________________________________________________ 12 3ds2oof 工具______________________________________________________________12 3Dstudio Max 导出器_______________________________________________________12 位图字体创建工具_________________________________________________________12 Milkshape3D 导出器_______________________________________________________ 12 Python 接口______________________________________________________________ 13 XML 转换器______________________________________________________________13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值