第一次發送超過字數了,被迫剪成兩篇!
上一篇我們介紹瞭如何搭建開發環境,並創建了一個空白的窗口程序。
這裏我們主要是實現在程序中裝載一個簡單的模型並顯示出來。
首先看一下效果吧,(模型就是ogre例子中的robot.mesh),如下:
例子很簡單,代碼頁不多,就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[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
#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
接續(二)