這裡我們主要是實作在程式中裝載一個簡單的模型并顯示出來。
首先看一下效果吧,(模型就是ogre例子中的robot.mesh),如下:
例子很簡單,代碼頁不多,就4行。我們還是一步一步來分析吧。
首先我們上一個項目中的OgreDemo1類繼承自ExampleApplication類,我們之是以什麼都沒有做就能建立一個視窗,就是因為ExampleApplication為我們實作了。
首先我們打開ExampleApplication類,可以看到包含了如下幾個成員變量(下乳了少許注釋)
Cpp代碼
- //ogre的程式"根"任何ogre程式都會有改對象
- Root *mRoot;
- //錄影機鏡頭
- Camera* mCamera;
- //場景管理器
- SceneManager* mSceneMgr;
- //對于每一幀進行處理的類
- ExampleFrameListener* mFrameListener;
- //渲染視窗
- RenderWindow* mWindow;
- //資源檔案的路徑字元串
- Ogre::String mResourcePath;
//ogre的程式"根"任何ogre程式都會有改對象
Root *mRoot;
//錄影機鏡頭
Camera* mCamera;
//場景管理器
SceneManager* mSceneMgr;
//對于每一幀進行處理的類
ExampleFrameListener* mFrameListener;
//渲染視窗
RenderWindow* mWindow;
//資源檔案的路徑字元串
Ogre::String mResourcePath;
這裡的ExampleFrameListener類,如果你暫時還不清楚是做什麼的,不要緊,後面我們慢慢介紹。
知道了這些成員變量,我們在傳回OgreDemo1.c檔案中看看入口函數WinMain中是如何書寫的呢?很簡單就一句話:
Cpp代碼
- app.go();
app.go();
先将源代碼貼出來,加了詳細注意:
ExampleApplication.h
Cpp代碼
- #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[1024];
- 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);
- }
- #endif
- using namespace Ogre;
- class ExampleApplication
- {
- public:
- ExampleApplication()
- {
- mFrameListener = 0;
- mRoot = 0;
- #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
- mResourcePath = macBundlePath() + "/Contents/Resources/";
- #else
- mResourcePath = "";
- #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_LIB
- pluginsPath = 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();
- }
- };
- #endif
#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[1024];
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);
}
#endif
using 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_APPLE
mResourcePath = macBundlePath() + "/Contents/Resources/";
#else
mResourcePath = "";
#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_LIB
pluginsPath = 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();
}
};
#endif
ExampleFrameListener.h
Cpp代碼
- #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(...) { }
- }
- 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 RIGHT
- if(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )
- mTranslateVector.z = -mMoveScale; // Move camera forward
- if(mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S) )
- mTranslateVector.z = mMoveScale; // Move camera backward
- if(mKeyboard->isKeyDown(OIS::KC_PGUP))
- mTranslateVector.y = mMoveScale; // Move camera up
- if(mKeyboard->isKeyDown(OIS::KC_PGDOWN))
- mTranslateVector.y = -mMoveScale; // Move camera down
- if(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 rotate
- const 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();
- else
- mDebugOverlay->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 movement
- if (mTimeUntilNextToggle >= 0)
- mTimeUntilNextToggle -= evt.timeSinceLastFrame;
- // Move about 100 units per second
- mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
- // Take about 10 seconds for full rotation
- mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
- mRotX = 0;
- mRotY = 0;
- mTranslateVector = Ogre::Vector3::ZERO;
- }
- //Check to see which device is not buffered, and handle it
- if( !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 up
- mCurrentSpeed += evt.timeSinceLastFrame;
- }
- // Limit motion speed
- if (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
#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 RIGHT
if(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )
mTranslateVector.z = -mMoveScale; // Move camera forward
if(mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S) )
mTranslateVector.z = mMoveScale; // Move camera backward
if(mKeyboard->isKeyDown(OIS::KC_PGUP))
mTranslateVector.y = mMoveScale; // Move camera up
if(mKeyboard->isKeyDown(OIS::KC_PGDOWN))
mTranslateVector.y = -mMoveScale; // Move camera down
if(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 rotate
const 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();
else
mDebugOverlay->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 movement
if (mTimeUntilNextToggle >= 0)
mTimeUntilNextToggle -= evt.timeSinceLastFrame;
// Move about 100 units per second
mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
// Take about 10 seconds for full rotation
mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
mRotX = 0;
mRotY = 0;
mTranslateVector = Ogre::Vector3::ZERO;
}
//Check to see which device is not buffered, and handle it
if( !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 up
mCurrentSpeed += evt.timeSinceLastFrame;
}
// Limit motion speed
if (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類的構造函數接受一些符串對象的參數,這些字元代表着不同作用的檔案名稱。
Cpp代碼
- 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 * 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檔案例子
Java代碼
- # Defines plugins to load
- # Define plugin folder
- PluginFolder=.
- # Define plugins
- Plugin=RenderSystem_Direct3D9_d
- Plugin=RenderSystem_GL_d
- Plugin=Plugin_ParticleFX_d
- Plugin=Plugin_BSPSceneManager_d
- Plugin=Plugin_CgProgramManager_d
- Plugin=Plugin_PCZSceneManager_d.dll
- Plugin=Plugin_OctreeZone_d.dll
- Plugin=Plugin_OctreeSceneManager_d
# Defines plugins to load
# Define plugin folder
PluginFolder=.
# Define plugins
Plugin=RenderSystem_Direct3D9_d
Plugin=RenderSystem_GL_d
Plugin=Plugin_ParticleFX_d
Plugin=Plugin_BSPSceneManager_d
Plugin=Plugin_CgProgramManager_d
Plugin=Plugin_PCZSceneManager_d.dll
Plugin=Plugin_OctreeZone_d.dll
Plugin=Plugin_OctreeSceneManager_d
其中PluginFolder用于定義這些插件存在的位置(路徑), 這裡使用“.”,表示需要在“/”或者“/”(即根目錄)。在某些平台上可以不使用“.”直接使用""(空白),ogre照樣會在“/”或者“/”中去找。
而Plugin則說明了有哪些插件可以使用,但是需要注意,這些插件都沒有字尾名。
這裡需要注意:在“=”兩邊不能加入空格或者 Tab字元。
ogre.cfg則是一個屬性配置檔案,主要儲存使用者自定義的一些屬性,即下圖所示的界面的一些屬性。
檔案如下:
Java代碼
- Render System=Direct3D9 Rendering Subsystem
- [Direct3D9 Rendering Subsystem]
- Allow NVPerfHUD=No
- Anti aliasing=None
- Floating-point mode=Fastest
- Full Screen=No
- Rendering Device=Mobile Intel(R) 945 Express Chipset Family
- VSync=No
- Video Mode=800 x 600 @ 32-bit colour
- sRGB Gamma Conversion=No
- [OpenGL Rendering Subsystem]
- Colour Depth=32
- Display Frequency=N/A
- FSAA=0
- Full Screen=No
- RTT Preferred Mode=FBO
- VSync=No
- Video Mode=1024 x 768
- sRGB Gamma Conversion=No
Render System=Direct3D9 Rendering Subsystem
[Direct3D9 Rendering Subsystem]
Allow NVPerfHUD=No
Anti aliasing=None
Floating-point mode=Fastest
Full Screen=No
Rendering Device=Mobile Intel(R) 945 Express Chipset Family
VSync=No
Video Mode=800 x 600 @ 32-bit colour
sRGB Gamma Conversion=No
[OpenGL Rendering Subsystem]
Colour Depth=32
Display Frequency=N/A
FSAA=0
Full Screen=No
RTT Preferred Mode=FBO
VSync=No
Video Mode=1024 x 768
sRGB Gamma Conversion=No
相信這裡就不用多解釋,大家都明白了。
Ogre.log :日志檔案,用于輸出一些調試資訊等,比如下代碼:
Cpp代碼
- LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***")
LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***")
就會在 Ogre.log檔案中輸出"*** Initializing OIS ***"資訊。
另外需要說明得就是FrameListener接口了,當Ogre渲染每一幀的開始和結束的時候會回調FrameListener接口的方法,其中主要包括如下兩個渲染方法。
Cpp代碼
- 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;
- }
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 之間。
Cpp代碼
- //設定環境光
- mSceneMgr->setAmbientLight( ColourValue( 1, 1, 1 ) )
//設定環境光
mSceneMgr->setAmbientLight( ColourValue( 1, 1, 1 ) )
2:建立一個 Entity (物體),通過調用 SceneManager 的 createEntity 方法來建立
Cpp代碼
- //建立一個物體
- Entity *ent1 = mSceneMgr->createEntity( "Robot", "robot.mesh" );
//建立一個物體
Entity *ent1 = mSceneMgr->createEntity( "Robot", "robot.mesh" );
變量 mSceneMgr 是目前場景管理器的一個對象,createEntity 方法的第一個參數是為所建立的實體指定一個唯一的辨別,第二個參數 "robot.mesh" 指明要使用的網格實體,"robot.mesh" 網格實體在 ExampleApplication 類中被裝載。這樣,就已經建立了一個實體。
3:還需要建立一個場景節點來與它綁定在一起。既然每個場景管理器都有一個根節點,那我們就在根節點下建立一個場景節點。
Cpp代碼
- //建立該物體對應的場景節點
- SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode" );
//建立該物體對應的場景節點
SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode" );
首先調用場景管理器的 getRootSceneNode 方法來擷取根節點,再使用根節點的 createChildSceneNode 方法建立一個名為 "RobotNode" 的場景節點。與實體一樣,場景節點的名字也是唯一的。
4:最後,将實體與場景節點綁定在一起,這樣機器人(Robot)就會在指定的位置被渲染:
Cpp代碼
- //将該物體和場景節點關聯起來
- node1->attachObject( ent1 );
//将該物體和場景節點關聯起來
node1->attachObject( ent1 );
ok,現在編譯運作你的程式,就可以看到我們偉大的機器人界面了。
最後說一下,在建立Root對象時的檔案一般會和程式最後的可執行檔案在同一目錄(因為有人說找不到這些檔案)。祝你成功!