yarin 发表于 2013-1-30 22:45:50

ogre研究之第一个程序

版权申明:http://yarin.iteye.com/blog/453262
 
上一篇我们介绍了如何搭建开发环境,并创建了一个空白的窗口程序。
 
这里我们主要是实现在程序中装载一个简单的模型并显示出来。
 
首先看一下效果吧,(模型就是ogre例子中的robot.mesh),如下:

http://dl.iteye.com/upload/attachment/187985/ca8308b8-8158-373a-83a9-9ad7effacdcc.png
 
例子很简单,代码页不多,就4行。我们还是一步一步来分析吧。
 
首先我们上一个项目中的OgreDemo1类继承自ExampleApplication类,我们之所以什么都没有做就能创建一个窗口,就是因为ExampleApplication为我们实现了。
 
首先我们打开ExampleApplication类,可以看到包含了如下几个成员变量(下乳了少许注释)
 
//ogre的程序"根"任何ogre程序都会有改对象Root *mRoot;//摄像机镜头Camera* mCamera;//场景管理器SceneManager* mSceneMgr;//对于每一帧进行处理的类ExampleFrameListener* mFrameListener;//渲染窗口RenderWindow* mWindow;//资源文件的路径字符串Ogre::String mResourcePath;这里的ExampleFrameListener类,如果你暂时还不清楚是做什么的,不要紧,后面我们慢慢介绍。
 
知道了这些成员变量,我们在返回OgreDemo1.c文件中看看入口函数WinMain中是如何书写的呢?很简单就一句话:
app.go();先将源代码贴出来,加了详细注意:
ExampleApplication.h
#ifndef __ExampleApplication_H__#define __ExampleApplication_H__#include "Ogre.h"#include "OgreConfigFile.h"#include "ExampleFrameListener.h"#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE#include <CoreFoundation/CoreFoundation.h>std::string macBundlePath(){    char path;    CFBundleRef mainBundle = CFBundleGetMainBundle();    assert(mainBundle);    CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);    assert(mainBundleURL);    CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle);    assert(cfStringRef);    CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);    CFRelease(mainBundleURL);    CFRelease(cfStringRef);    return std::string(path);}#endifusing namespace Ogre;/** Base class which manages the standard startup of an Ogre application.    Designed to be subclassed for specific examples if required.*/class ExampleApplication{public:    ExampleApplication()    {      mFrameListener = 0;      mRoot = 0;#if OGRE_PLATFORM == OGRE_PLATFORM_APPLEmResourcePath = macBundlePath() + "/Contents/Resources/";#elsemResourcePath = "";#endif    }    /// Standard destructor    virtual ~ExampleApplication()    {      if (mFrameListener)            delete mFrameListener;      if (mRoot)            OGRE_DELETE mRoot;    }    /// 程序的入口    virtual void go(void)    {//进行初始化工作      if (!setup())            return;//开始渲染      mRoot->startRendering();      // 清理屏幕      destroyScene();    }protected://ogre的程序"根"任何ogre程序都会有改对象    Root *mRoot;//摄像机镜头    Camera* mCamera;//场景管理器    SceneManager* mSceneMgr;//对于每一帧进行处理的类    ExampleFrameListener* mFrameListener;//渲染窗口    RenderWindow* mWindow;//资源文件的路径字符串Ogre::String mResourcePath;    //初始化应用程序    virtual bool setup(void)    {String pluginsPath;#ifndef OGRE_STATIC_LIBpluginsPath = mResourcePath + "plugins.cfg";#endif//构建Root对象      mRoot = OGRE_NEW Root(pluginsPath,             mResourcePath + "ogre.cfg", mResourcePath + "Ogre.log");//配置资源文件相关      setupResources();//配置,主要用于初始化渲染窗口      bool carryOn = configure();      if (!carryOn) return false;//创建场景管理器      chooseSceneManager();//创建摄像机      createCamera();//创建视口      createViewports();      TextureManager::getSingleton().setDefaultNumMipmaps(5);//创建资源监听createResourceListener();//床在资源loadResources();//创建屏幕,必须重写,也就是我们OgreDemo1类中(我们现实模型需要实现的)      createScene();//创建帧监听      createFrameListener();      return true;    }    /** 是否配置完成,完成则初始化系统 */    virtual bool configure(void)    {      //判断是否进入(即运行过了配置窗口,进入demo窗口)      if(mRoot->showConfigDialog())      {            //初始化系统,得到一个渲染窗口对象            mWindow = mRoot->initialise(true);            return true;      }      else      {            return false;      }    }    virtual void chooseSceneManager(void)    {      // 创建一个场景管理器(场景类型,窗口标题)      mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "ExampleSMInstance");    }    virtual void createCamera(void)    {      // 创建一个摄像机      mCamera = mSceneMgr->createCamera("PlayerCam");      // 设置摄像机的位置      mCamera->setPosition(Vector3(0,0,500));      // 设置观察点      mCamera->lookAt(Vector3(0,0,-300));// 设置最近裁剪距离,如果超出则不显示      mCamera->setNearClipDistance(5);//同样还有设置最远裁剪距离//mCamera->setFarClipDistance(1000);    }//创建帧监听    virtual void createFrameListener(void)    {//实例化帧监听,(渲染窗口,摄像机)      mFrameListener= new ExampleFrameListener(mWindow, mCamera);//设置是否显示调试信息(比如:fps...)      mFrameListener->showDebugOverlay(true);//添加帧监听到root中      mRoot->addFrameListener(mFrameListener);    }//创建屏幕    virtual void createScene(void) = 0; //清屏    virtual void destroyScene(void){}/* 创建视口并初始化 */    virtual void createViewports(void)    {      // 创建一个“视口”      Viewport* vp = mWindow->addViewport(mCamera);//设置背景颜色      vp->setBackgroundColour(ColourValue(0,0,0));      //设置屏幕的长宽比(视口的宽度和高度比,目前的宽屏电脑)      mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));    }    /// 初始化资源,比如:模型、贴图等资源    virtual void setupResources(void)    {      ConfigFile cf;//读取配置文件      cf.load(mResourcePath + "resources.cfg");      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;#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE                ResourceGroupManager::getSingleton().addResourceLocation(                  String(macBundlePath() + "/" + archName), typeName, secName);#else                ResourceGroupManager::getSingleton().addResourceLocation(                  archName, typeName, secName);#endif            }      }    }//创建资源监听,比如(正在装载资源,请稍等界面)virtual void createResourceListener(void){}//装载资源virtual void loadResources(void){ResourceGroupManager::getSingleton().initialiseAllResourceGroups();}};#endifExampleFrameListener.h 
#ifndef __ExampleFrameListener_H__#define __ExampleFrameListener_H__#include "Ogre.h"#include "OgreStringConverter.h"#include "OgreException.h"#define OIS_DYNAMIC_LIB#include <OIS/OIS.h>using namespace Ogre;class ExampleFrameListener: public FrameListener, public WindowEventListener{protected:virtual void updateStats(void){static String currFps = "Current FPS: ";static String avgFps = "Average FPS: ";static String bestFps = "Best FPS: ";static String worstFps = "Worst FPS: ";static String tris = "Triangle Count: ";static String batches = "Batch Count: ";// 需要更新debug信息时更新try {OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");const RenderTarget::FrameStats& stats = mWindow->getStatistics();guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)+" "+StringConverter::toString(stats.bestFrameTime)+" ms");guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)+" "+StringConverter::toString(stats.worstFrameTime)+" ms");OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));OverlayElement* guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches");guiBatches->setCaption(batches + StringConverter::toString(stats.batchCount));OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");guiDbg->setCaption(mDebugText);}catch(...) { /* ignore */ }}public:// 构造函数,初始化成员变量ExampleFrameListener(RenderWindow* win, Camera* cam, bool bufferedKeys = false, bool bufferedMouse = false,   bool bufferedJoy = false ) :mCamera(cam), mTranslateVector(Vector3::ZERO), mCurrentSpeed(0), mWindow(win), mStatsOn(true), mNumScreenShots(0),mMoveScale(0.0f), mRotScale(0.0f), mTimeUntilNextToggle(0), mFiltering(TFO_BILINEAR),mAniso(1), mSceneDetailIndex(0), mMoveSpeed(100), mRotateSpeed(36), mDebugOverlay(0),mInputManager(0), mMouse(0), mKeyboard(0), mJoy(0){//得到debug视图mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");//日志管理器LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");OIS::ParamList pl;size_t windowHnd = 0;std::ostringstream windowHndStr;//取得自定义的属性win->getCustomAttribute("WINDOW", &windowHnd);windowHndStr << windowHnd;pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));//创建输入管理器mInputManager = OIS::InputManager::createInputSystem( pl );//创建输入设备、鼠标、键盘、摇杆mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, bufferedKeys ));mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, bufferedMouse ));try {mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject( OIS::OISJoyStick, bufferedJoy ));}catch(...) {mJoy = 0;}//根据窗口的大小来设置鼠标的初始裁剪区域windowResized(mWindow);//显示debug信息showDebugOverlay(true);//注册一个windows窗口事件监听WindowEventUtilities::addWindowEventListener(mWindow, this);}//调整鼠标裁剪区域virtual void windowResized(RenderWindow* rw){unsigned int width, height, depth;int left, top;//取得窗口矩阵rw->getMetrics(width, height, depth, left, top);//得到鼠标const OIS::MouseState &ms = mMouse->getMouseState();ms.width = width;ms.height = height;}//关闭窗口之前进行的处理virtual void windowClosed(RenderWindow* rw){//检测是否关闭了我们的渲染窗口if( rw == mWindow ){if( mInputManager ){//清除输入设备mInputManager->destroyInputObject( mMouse );mInputManager->destroyInputObject( mKeyboard );mInputManager->destroyInputObject( mJoy );//销毁输入管理器OIS::InputManager::destroyInputSystem(mInputManager);mInputManager = 0;}}}virtual ~ExampleFrameListener(){//移除所有的窗口事件监听WindowEventUtilities::removeWindowEventListener(mWindow, this);//关闭窗口windowClosed(mWindow);}//按键事件处理virtual bool processUnbufferedKeyInput(const FrameEvent& evt){if(mKeyboard->isKeyDown(OIS::KC_A))mTranslateVector.x = -mMoveScale;// 向左移动摄像头矩阵if(mKeyboard->isKeyDown(OIS::KC_D))mTranslateVector.x = mMoveScale;// Move camera RIGHTif(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )mTranslateVector.z = -mMoveScale;// Move camera forwardif(mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S) )mTranslateVector.z = mMoveScale;// Move camera backwardif(mKeyboard->isKeyDown(OIS::KC_PGUP))mTranslateVector.y = mMoveScale;// Move camera upif(mKeyboard->isKeyDown(OIS::KC_PGDOWN))mTranslateVector.y = -mMoveScale;// Move camera downif(mKeyboard->isKeyDown(OIS::KC_RIGHT))mCamera->yaw(-mRotScale);if(mKeyboard->isKeyDown(OIS::KC_LEFT))mCamera->yaw(mRotScale);if( mKeyboard->isKeyDown(OIS::KC_ESCAPE) || mKeyboard->isKeyDown(OIS::KC_Q) )return false;       if( mKeyboard->isKeyDown(OIS::KC_F) && mTimeUntilNextToggle <= 0 ){mStatsOn = !mStatsOn;showDebugOverlay(mStatsOn);mTimeUntilNextToggle = 1;}if( mKeyboard->isKeyDown(OIS::KC_T) && mTimeUntilNextToggle <= 0 ){switch(mFiltering){case TFO_BILINEAR:mFiltering = TFO_TRILINEAR;mAniso = 1;break;case TFO_TRILINEAR:mFiltering = TFO_ANISOTROPIC;mAniso = 8;break;case TFO_ANISOTROPIC:mFiltering = TFO_BILINEAR;mAniso = 1;break;default: break;}MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);showDebugOverlay(mStatsOn);mTimeUntilNextToggle = 1;}if(mKeyboard->isKeyDown(OIS::KC_SYSRQ) && mTimeUntilNextToggle <= 0){std::ostringstream ss;ss << "screenshot_" << ++mNumScreenShots << ".png";mWindow->writeContentsToFile(ss.str());mTimeUntilNextToggle = 0.5;mDebugText = "Saved: " + ss.str();}if(mKeyboard->isKeyDown(OIS::KC_R) && mTimeUntilNextToggle <=0){mSceneDetailIndex = (mSceneDetailIndex+1)%3 ;switch(mSceneDetailIndex) {case 0 : mCamera->setPolygonMode(PM_SOLID); break;//设置多边形的模式case 1 : mCamera->setPolygonMode(PM_WIREFRAME); break;case 2 : mCamera->setPolygonMode(PM_POINTS); break;}mTimeUntilNextToggle = 0.5;}static bool displayCameraDetails = false;if(mKeyboard->isKeyDown(OIS::KC_P) && mTimeUntilNextToggle <= 0){displayCameraDetails = !displayCameraDetails;mTimeUntilNextToggle = 0.5;if (!displayCameraDetails)mDebugText = "";}if(displayCameraDetails)mDebugText = "P: " + StringConverter::toString(mCamera->getDerivedPosition()) + " " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation());return true;}//鼠标事件处理virtual bool processUnbufferedMouseInput(const FrameEvent& evt){// Rotation factors, may not be used if the second mouse button is pressed// 2nd mouse button - slide, otherwise rotateconst OIS::MouseState &ms = mMouse->getMouseState();if( ms.buttonDown( OIS::MB_Right ) ){mTranslateVector.x += ms.X.rel * 0.13;mTranslateVector.y -= ms.Y.rel * 0.13;}else{mRotX = Degree(-ms.X.rel * 0.13);mRotY = Degree(-ms.Y.rel * 0.13);}return true;}//移动摄像头virtual void moveCamera(){//偏移mCamera->yaw(mRotX);//倾斜mCamera->pitch(mRotY);//移动摄像机到指定位置mCamera->moveRelative(mTranslateVector);}//显示debug信息virtual void showDebugOverlay(bool show){if (mDebugOverlay){if (show)mDebugOverlay->show();elsemDebugOverlay->hide();}}// 渲染队列bool frameRenderingQueued(const FrameEvent& evt){if(mWindow->isClosed())return false;mSpeedLimit = mMoveScale * evt.timeSinceLastFrame;//捕获、更新设备mKeyboard->capture();mMouse->capture();if( mJoy ) mJoy->capture();bool buffJ = (mJoy) ? mJoy->buffered() : true;    Ogre::Vector3 lastMotion = mTranslateVector;if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ ){// one of the input modes is immediate, so setup what is needed for immediate movementif (mTimeUntilNextToggle >= 0)mTimeUntilNextToggle -= evt.timeSinceLastFrame;// Move about 100 units per secondmMoveScale = mMoveSpeed * evt.timeSinceLastFrame;// Take about 10 seconds for full rotationmRotScale = mRotateSpeed * evt.timeSinceLastFrame;mRotX = 0;mRotY = 0;mTranslateVector = Ogre::Vector3::ZERO;}//Check to see which device is not buffered, and handle itif( !mKeyboard->buffered() )if( processUnbufferedKeyInput(evt) == false )return false;if( !mMouse->buffered() )if( processUnbufferedMouseInput(evt) == false )return false;// ramp up / ramp down speed    if (mTranslateVector == Ogre::Vector3::ZERO){// decay (one third speed)mCurrentSpeed -= evt.timeSinceLastFrame * 0.3;mTranslateVector = lastMotion;}else{// ramp upmCurrentSpeed += evt.timeSinceLastFrame;}// Limit motion speedif (mCurrentSpeed > 1.0)mCurrentSpeed = 1.0;if (mCurrentSpeed < 0.0)mCurrentSpeed = 0.0;mTranslateVector *= mCurrentSpeed;if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )moveCamera();return true;}//帧结束,更新状态bool frameEnded(const FrameEvent& evt){updateStats();return true;}protected://指向摄像机的指针Camera* mCamera;//一个3维向量,用于摄像机的位置变换Vector3 mTranslateVector;Real mCurrentSpeed;//指向渲染窗口的指针RenderWindow* mWindow;//是否显示调试信息bool mStatsOn;//debug信息std::string mDebugText;//主要用于截图unsigned int mNumScreenShots;//该demo中,摄像机会旋转float mMoveScale;//速度限制float mSpeedLimit;//同样用于摄像机变换Degree mRotScale;//延时Real mTimeUntilNextToggle ;//鼠标旋转的角度,用于摄像机的更新Radian mRotX, mRotY;//纹理差值的类型,枚举类型TextureFilterOptions mFiltering;int mAniso;int mSceneDetailIndex ;//移动速度Real mMoveSpeed;//旋转速度Degree mRotateSpeed;//debug视图Overlay* mDebugOverlay;//一些输入设备(输入设备管理器)OIS::InputManager* mInputManager;//鼠标OIS::Mouse*    mMouse;//键盘OIS::Keyboard* mKeyboard;//摇杆OIS::JoyStick* mJoy;};#endif首先,我们要分析的就是Root类,使用Ogre的程序所需要作的第一件事情就是实例化一个Root对象。如果没有这个对象,你就无法调用(除了日志管理以外)的任何一个功能。Root类的构造函数接受一些符串对象的参数,这些字符代表着不同作用的文件名称。
Root * root = new Root();Root * root = new Root("plugins.cfg"); Root * root = new Root("plugins.cfg", "ogre.cfg");Root * root = new Root("plugins.cfg", "ogre.cfg", "ogre.log");Root * root = new Root("", "");上面列出了一些不同的方法来创建Root实例,这里面任何的方法都能单独的正确执行。参数也是系统所默认的值(“plugins.cfg”, “ogre.cfg”, “ogre.log”——当你没有填写参数的时候,系统就认为采用了默认的这些值)。 
plugins.cfg:插件,Ogre中所谓的插件就是符合Ogre插件接口的代码模块,比如场景管理(SceneManager)插件和渲染系统(RenderSystem)插件等。在启动的Ogre时候,他会载入plugins.cfg配置文件来查看有哪些插件可以被使用。下面是一个plugins.cfg文件例子
# Defines plugins to load# Define plugin folderPluginFolder=.# Define pluginsPlugin=RenderSystem_Direct3D9_dPlugin=RenderSystem_GL_dPlugin=Plugin_ParticleFX_dPlugin=Plugin_BSPSceneManager_dPlugin=Plugin_CgProgramManager_dPlugin=Plugin_PCZSceneManager_d.dllPlugin=Plugin_OctreeZone_d.dllPlugin=Plugin_OctreeSceneManager_d其中PluginFolder用于定义这些插件存在的位置(路径),  这里使用“.”,表示需要在“\”或者“/”(即根目录)。在某些平台上可以不使用“.”直接使用""(空白),ogre照样会在“\”或者“/”中去找。
而Plugin则说明了有哪些插件可以使用,但是需要注意,这些插件都没有后缀名。
这里需要注意:在“=”两边不能加入空格或者 Tab字符。
 
ogre.cfg则是一个属性配置文件,主要保存用户自定义的一些属性,即下图所示的界面的一些属性。

http://dl.iteye.com/upload/attachment/187987/9dfd7301-4690-3ceb-9031-f70abb36cdb9.jpg
文件如下:
Render System=Direct3D9 Rendering SubsystemAllow NVPerfHUD=NoAnti aliasing=NoneFloating-point mode=FastestFull Screen=NoRendering Device=Mobile Intel(R) 945 Express Chipset FamilyVSync=NoVideo Mode=800 x 600 @ 32-bit coloursRGB Gamma Conversion=NoColour Depth=32Display Frequency=N/AFSAA=0Full Screen=NoRTT Preferred Mode=FBOVSync=NoVideo Mode=1024 x 768sRGB Gamma Conversion=No相信这里就不用多解释,大家都明白了。
 
Ogre.log :日志文件,用于输出一些调试信息等,比如下代码:
LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***")就会在 Ogre.log文件中输出"*** Initializing OIS ***"信息。
 
另外需要说明得就是FrameListener接口了,当Ogre渲染每一帧的开始和结束的时候会回调FrameListener接口的方法,其中主要包括如下两个渲染方法。
class ExampleFrameListener : public FrameListener{public:bool frameStarted (const FrameEvent &evt);bool frameEnded (const FrameEvent &evt );};bool ExampleFrameListener::frameStarted (const FrameEvent &evt){//在每一帧画面渲染前return true;}bool ExampleFrameListener::frameEnded (const FrameEvent &evt ){//在每一帧画面渲染后return true;}所以我们就可以根据需要来实现这两个方式,实现渲染。 
 
注意:在新的版本中frameRenderingQueued方法基本上取代了frameStarted,所以本例中我们就是用了frameRenderingQueued,一般在这个函数中都需要检测各种输入设备的情况,以进行相应的处理。
 
最后,当我们在程序中调用mRoot->startRendering();方法时,就告诉ogre,我们需要开始渲染了。ogre就会开始渲染。也正是ExampleApplication类中的go方法,所做的,初始化(setup)完成之后就开始渲染(mRoot->startRendering())。
 
之所以有了这两个类,上一篇中我们才可以不写任何代码就可以构建一个窗口,那么本节内容,我们要显示模型当然就很简单了。
直接在OgreDemo1类的createScene方法中来实现,
1:设置环境光,首先需要为整个场景设置环境光,这样才可以看到要显示的内容,通过调用setAmbientLight函数并指定环境光的颜色就可以做到这些。指定的颜色由红、绿、蓝三种颜色组成,且每种色数值范围在 0 到 1 之间。
//设置环境光mSceneMgr->setAmbientLight( ColourValue( 1, 1, 1 ) ) 2:创建一个 Entity (物体),通过调用 SceneManager 的 createEntity 方法来创建
//创建一个物体Entity *ent1 = mSceneMgr->createEntity( "Robot", "robot.mesh" );变量 mSceneMgr 是当前场景管理器的一个对象,createEntity 方法的第一个参数是为所创建的实体指定一个唯一的标识,第二个参数 "robot.mesh" 指明要使用的网格实体,"robot.mesh" 网格实体在 ExampleApplication 类中被装载。这样,就已经创建了一个实体。
3:还需要创建一个场景节点来与它绑定在一起。既然每个场景管理器都有一个根节点,那我们就在根节点下创建一个场景节点。
//创建该物体对应的场景节点SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode" ); 首先调用场景管理器的 getRootSceneNode 方法来获取根节点,再使用根节点的 createChildSceneNode 方法创建一个名为 "RobotNode" 的场景节点。与实体一样,场景节点的名字也是唯一的。
4:最后,将实体与场景节点绑定在一起,这样机器人(Robot)就会在指定的位置被渲染:
//将该物体和场景节点关联起来node1->attachObject( ent1 );ok,现在编译运行你的程序,就可以看到我们伟大的机器人界面了。 
 
最后说一下,在创建Root对象时的文件一般会和程序最后的可执行文件在同一目录(因为有人说找不到这些文件)。祝你成功!
页: [1]
查看完整版本: ogre研究之第一个程序