1. 程式人生 > >Ogre學習教程:Ogre第一個程式

Ogre學習教程:Ogre第一個程式

1. 已經安裝了Ogre工程嚮導,VS2010 新建專案就可以看得OGRE的工程模版了,建立一個空專案,由於安裝了Orge工程助手,所以免去了麻煩的配置過程(安裝Orge工程助手步驟可以參考 Ogre1.8.1+VS2010環境配置):

圖片

2. 首先在專案中建立一個OgreDemo1.c和OgreDemo1.h檔案。分別填入如下程式碼:

OgreDemo1.h:

#ifndef _TutorialApplication_
#define _TutorialApplication_
#include "ExampleApplication.h"
class OgreDemo1 : public ExampleApplication
{
protected:
public:
OgreDemo1()
{
}
~OgreDemo1()
{
}
protected:
void createScene(void)
{
}
};
#endif

OgreDemo1.c
#include "OgreDemo1.h"

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

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
	// Create application object
	OgreDemo1 app;

	try {
		app.go();
	} catch( Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 
		MessageBoxA( NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
		fprintf(stderr, "An exception has occurred: %s ",
			e.getFullDescription().c_str());
#endif
	}

	return 0;
}

編譯,執行,會出現一個黑視窗,啥都木有!

3. 往視窗新增一個物件

直接在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,現在編譯執行你的程式,就可以看到我們偉大的機器人介面了。 



例子很簡單,內碼表不多,就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

/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2012 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
same license as the rest of the engine.
-----------------------------------------------------------------------------
*/
/*
-----------------------------------------------------------------------------
Filename:    ExampleApplication.h
Description: Base class for all the OGRE examples
-----------------------------------------------------------------------------
*/

#ifndef __ExampleApplication_H__
#define __ExampleApplication_H__

#include "Ogre.h"
#include "OgreConfigFile.h"
#include "ExampleFrameListener.h"
// Static plugins declaration section
// Note that every entry in here adds an extra header / library dependency
#ifdef OGRE_STATIC_LIB
#  define OGRE_STATIC_GL
#  if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#    define OGRE_STATIC_Direct3D9
     // dx11 will only work on vista, so be careful about statically linking
#    if OGRE_USE_D3D11
#      define OGRE_STATIC_Direct3D11
#    endif
#  endif
#  define OGRE_STATIC_BSPSceneManager
#  define OGRE_STATIC_ParticleFX
#  define OGRE_STATIC_CgProgramManager
#  ifdef OGRE_USE_PCZ
#    define OGRE_STATIC_PCZSceneManager
#    define OGRE_STATIC_OctreeZone
#  else
#    define OGRE_STATIC_OctreeSceneManager
#  endif
#  if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
#     undef OGRE_STATIC_CgProgramManager
#     undef OGRE_STATIC_GL
#     define OGRE_STATIC_GLES 1
#     ifdef __OBJC__
#       import <UIKit/UIKit.h>
#     endif
#  endif
#  include "OgreStaticPluginLoader.h"
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
#   include "macUtils.h"
#endif

#ifdef USE_RTSHADER_SYSTEM

/** This class simply demonstrates basic usage of the CRTShader system.
It sub class the material manager listener class and when a target scheme callback
is invoked with the shader generator scheme it tries to create an equvialent shader
based technique based on the default technique of the given material.
*/
class ShaderGeneratorTechniqueResolverListener : public MaterialManager::Listener
{
public:

	ShaderGeneratorTechniqueResolverListener(RTShader::ShaderGenerator* pShaderGenerator)
	{
		mShaderGenerator = pShaderGenerator;
	}

	virtual Technique* handleSchemeNotFound(unsigned short schemeIndex, 
		const String& schemeName, Material* originalMaterial, unsigned short lodIndex, 
		const Renderable* rend)
	{		
		// Case this is the default shader generator scheme.
		if (schemeName == RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME)
		{
			MaterialRegisterIterator itFind = mRegisteredMaterials.find(originalMaterial);
			bool techniqueCreated = false;

			// This material was not registered before.
			if (itFind == mRegisteredMaterials.end())
			{
				techniqueCreated = mShaderGenerator->createShaderBasedTechnique(
					originalMaterial->getName(), 
					MaterialManager::DEFAULT_SCHEME_NAME, 
					schemeName);				
			}
			mRegisteredMaterials[originalMaterial] = techniqueCreated;
		}

		return NULL;
	}

protected:
	typedef std::map<Material*, bool>		MaterialRegisterMap;
	typedef MaterialRegisterMap::iterator	MaterialRegisterIterator;


protected:
	MaterialRegisterMap				mRegisteredMaterials;		// Registered material map.
	RTShader::ShaderGenerator*		mShaderGenerator;			// The shader generator instance.
};
#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:
    /// Standard constructor
    ExampleApplication()
    {
        mFrameListener = 0;
        mRoot = 0;
		// Provide a nice cross platform solution for locating the configuration files
		// On windows files are searched for in the current working directory, on OS X however
		// you must provide the full path, the helper function macBundlePath does this for us.
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
		mResourcePath = macBundlePath() + "/Contents/Resources/";
        mConfigPath = mResourcePath;
#elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
        mResourcePath = macBundlePath() + "/";
        mConfigPath = mResourcePath;
#else
		mResourcePath = "";
        mConfigPath = mResourcePath;
#endif

#ifdef USE_RTSHADER_SYSTEM
		mShaderGenerator	 = NULL;		
		mMaterialMgrListener = NULL;
#endif
    }
    /// Standard destructor
    virtual ~ExampleApplication()
    {
        if (mFrameListener)
            delete mFrameListener;
        if (mRoot)
            OGRE_DELETE mRoot;

#ifdef OGRE_STATIC_LIB
		mStaticPluginLoader.unload();
#endif
    }

    /// Start the example 程式入口;
    virtual void go(void)
    {
		//進行初始化工作;
        if (!setup())
            return;
		//開始渲染;
        mRoot->startRendering();

        // clean up
		//清理螢幕;
        destroyScene();	

#ifdef USE_RTSHADER_SYSTEM
		// Finalize shader generator.
		finalizeShaderGenerator();
#endif

    }

protected:
	//ogre程式的root,任何ogre程式都有該物件;
    Root *mRoot;
#ifdef OGRE_STATIC_LIB
	StaticPluginLoader mStaticPluginLoader;
#endif
	//攝像機鏡頭;
    Camera* mCamera;
	//場景管理器;
    SceneManager* mSceneMgr;
    //對每一幀進行處理的類;
	ExampleFrameListener* mFrameListener;
    //渲染視窗;
	RenderWindow* mWindow;
	//資原始檔的路徑字串;
	Ogre::String mResourcePath;
	Ogre::String mConfigPath;
#ifdef USE_RTSHADER_SYSTEM
	RTShader::ShaderGenerator*					mShaderGenerator;			// The Shader generator instance.
	ShaderGeneratorTechniqueResolverListener*	mMaterialMgrListener;		// Material manager listener.	
#endif

    // These internal methods package up the stages in the startup process
    /** Sets up the application - returns false if the user chooses to abandon configuration. */
    //初始化應用程式;
	virtual bool setup(void)
    {

		String pluginsPath;
		// only use plugins.cfg if not static
#ifndef OGRE_STATIC_LIB
#if OGRE_DEBUG_MODE
		pluginsPath = mResourcePath + "plugins_d.cfg";
#else
		pluginsPath = mResourcePath + "plugins.cfg";
#endif
#endif
		//構建Root物件;
        mRoot = OGRE_NEW Root(pluginsPath, 
            mConfigPath + "ogre.cfg", mResourcePath + "Ogre.log");
#ifdef OGRE_STATIC_LIB
		mStaticPluginLoader.load();
#endif
		//配置資原始檔相關; 
        setupResources();
		//配置,主要用於初始化渲染視窗;
        bool carryOn = configure();
        if (!carryOn) 
			return false;
		//建立場景管理器;
        chooseSceneManager();
		//建立攝像機;
        createCamera();
		//建立視口;
        createViewports();
#ifdef USE_RTSHADER_SYSTEM
		// Initialize shader generator.
		carryOn = initializeShaderGenerator(mSceneMgr);
		if (!carryOn) 
			return false;
#endif

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

		// Create any resource listeners (for loading screens)
		//建立資源監聽;
		createResourceListener();
		// Load resources
		//裝載資源;
		loadResources();

		// Create the scene
		//建立螢幕,必須重寫,也就是我們OgreDemo1類中(我們現實模型需要實現的);
        createScene();

		//建立幀監聽;
        createFrameListener();

        return true;

    }
#ifdef USE_RTSHADER_SYSTEM
	virtual bool initializeShaderGenerator(SceneManager* sceneMgr)
	{	
		if (RTShader::ShaderGenerator::initialize())
		{
			mShaderGenerator = RTShader::ShaderGenerator::getSingletonPtr();

			// Set the scene manager.
			mShaderGenerator->addSceneManager(sceneMgr);

			// Setup core libraries and shader cache path.
			ResourceGroupManager::LocationList resLocationsList = ResourceGroupManager::getSingleton().getResourceLocationList("Popular");
			ResourceGroupManager::LocationList::iterator it = resLocationsList.begin();
			ResourceGroupManager::LocationList::iterator itEnd = resLocationsList.end();
			String shaderCoreLibsPath;
			String shaderCachePath;

			// Default cache path is current directory;
			shaderCachePath = "./";

			// Try to find the location of the core shader lib functions and use it
			// as shader cache path as well - this will reduce the number of generated files
			// when running from different directories.
			for (; it != itEnd; ++it)
			{

				if ((*it)->archive->getName().find("RTShaderLib") != String::npos)
				{
					shaderCoreLibsPath = (*it)->archive->getName() + "/";
					shaderCachePath    = shaderCoreLibsPath;
					break;
				}
			}

			// Core shader libs not found -> shader generating will fail.
			if (shaderCoreLibsPath.empty())			
				return false;			

			// Add resource location for the core shader libs. 
			ResourceGroupManager::getSingleton().addResourceLocation(shaderCoreLibsPath , "FileSystem");
				
			// Set shader cache path.
			mShaderGenerator->setShaderCachePath(shaderCachePath);		
									
			// Create and register the material manager listener.
			mMaterialMgrListener = new ShaderGeneratorTechniqueResolverListener(mShaderGenerator);				
			MaterialManager::getSingleton().addListener(mMaterialMgrListener);
		}

		return true;
	}

	virtual void finalizeShaderGenerator()
	{
		// Unregister the material manager listener.
		if (mMaterialMgrListener != NULL)
		{			
			MaterialManager::getSingleton().removeListener(mMaterialMgrListener);
			delete mMaterialMgrListener;
			mMaterialMgrListener = NULL;
		}

		// Finalize CRTShader system.
		if (mShaderGenerator != NULL)
		{
			RTShader::ShaderGenerator::finalize();
			mShaderGenerator = NULL;
		}
	}
#endif
    /** Configures the application - returns false if the user chooses to abandon configuration. */
    /** 是否配置完成,完成則初始化系統 */ 
	virtual bool configure(void)
    {
        // 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
		//判斷是否進入(即執行過了配置視窗,進入demo視窗);
        if(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;
        }
    }

    virtual void chooseSceneManager(void)
    {
        // Create the SceneManager, in this case a generic one
		// 建立一個場景管理器(場景型別,視窗標題) ;
        mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "ExampleSMInstance");
    }
    virtual void createCamera(void)
    {
        // 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);
		//同樣還有設定最遠裁剪距離  ;
		//mCamera->setFarClipDistance(1000); 

    }
    virtual void createFrameListener(void)
    {
		//例項化幀監聽,(渲染視窗,攝像機);
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
        mFrameListener= new ExampleFrameListener(mWindow, mCamera, true, true, true);
#else
        mFrameListener= new ExampleFrameListener(mWindow, mCamera);
#endif
		//設定是否顯示除錯資訊(比如:fps...) ;
        mFrameListener->showDebugOverlay(true);
		//新增幀監聽到root中;
        mRoot->addFrameListener(mFrameListener);
    }

	//建立螢幕;
    virtual void createScene(void) = 0;    // pure virtual - this has to be overridden
	//清屏;
    virtual void destroyScene(void){}    // Optional to override this
	/* 建立視口並初始化 */ 
    virtual void createViewports(void)
    {
        // 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()));
    }

    /// Method which will define the source of resources (other than current folder)
	/// 初始化資源,比如:模型、貼圖等資源;
    virtual void setupResources(void)
    {
        // Load resource paths from config file
        ConfigFile cf;
		//讀取配置檔案 ;
#if OGRE_DEBUG_MODE
        cf.load(mResourcePath + "resources_d.cfg");
#else
		cf.load(mResourcePath + "resources.cfg");
#endif

        // 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;
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
                // OS X does not set the working directory relative to the app,
                // In order to make things portable on OS X we need to provide
                // the loading with it's own bundle path location
				if (!StringUtil::startsWith(archName, "/", false)) // only adjust relative dirs
					archName = String(macBundlePath() + "/" + archName);
#endif
                ResourceGroupManager::getSingleton().addResourceLocation(
                    archName, typeName, secName);

            }
        }
    }

	/// Optional override method where you can create resource listeners (e.g. for loading screens)
	//建立資源監聽,比如(正在裝載資源,請稍等介面);
	virtual void createResourceListener(void)
	{

	}

	/// Optional override method where you can perform resource group loading
	/// Must at least do ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
	//裝載資源;
	virtual void loadResources(void)
	{
		// Initialise, parse scripts etc
		ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

	}

};

#endif

ExampleFrameListener.h
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2012 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
same license as the rest of the engine.
-----------------------------------------------------------------------------
*/
/*
-----------------------------------------------------------------------------
Filename:    ExampleFrameListener.h
Description: Defines an example frame listener which responds to frame events.
This frame listener just moves a specified camera around based on
keyboard and mouse movements.
Mouse:    Freelook
W or Up:  Forward
S or Down:Backward
A:        Step left
D:        Step right
             PgUp:     Move upwards
             PgDown:   Move downwards
             F:        Toggle frame rate stats on/off
			 R:        Render mode
             T:        Cycle texture filtering
                       Bilinear, Trilinear, Anisotropic(8)
             P:        Toggle on/off display of camera position / orientation
			 F2:	   Set the main viewport material scheme to default material manager scheme.
			 F3:	   Set the main viewport material scheme to shader generator default scheme.
			 F4:	   Toggle default shader generator lighting model from per vertex to per pixel.
-----------------------------------------------------------------------------
*/

#ifndef __ExampleFrameListener_H__
#define __ExampleFrameListener_H__



#include "Ogre.h"
#include "OgreStringConverter.h"
#include "OgreException.h"


//Use this define to signify OIS will be used as a DLL
//(so that dll import/export macros are in effect)
#define OIS_DYNAMIC_LIB
#include <OIS/OIS.h>

using namespace Ogre;

#ifdef USE_RTSHADER_SYSTEM
#include "OgreRTShaderSystem.h"
#endif

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: ";

		// update stats when necessary
		// 需要更新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:
	// Constructor takes a RenderWindow because it uses that to determine input context
	// 建構函式,初始化成員變數;
	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 );

		//Create all devices (We only catch joystick exceptions here, as, most people have Key/Mouse)
		//建立輸入裝置、滑鼠、鍵盤、搖桿;
		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;
		}

		//Set initial mouse clipping size
		//根據視窗的大小來設定滑鼠的初始裁剪區域;
		windowResized(mWindow);
		//顯示debug資訊;
		showDebugOverlay(true);

		//Register as a Window listener
		//註冊一個windows視窗事件監聽;
		WindowEventUtilities::addWindowEventListener(mWindow, this);		
	}

#ifdef USE_RTSHADER_SYSTEM
	virtual void processShaderGeneratorInput()
	{		
		// Switch to default scheme.
		if (mKeyboard->isKeyDown(OIS::KC_F2))
		{	
			mCamera->getViewport()->setMaterialScheme(MaterialManager::DEFAULT_SCHEME_NAME);			
			mDebugText = "Active Viewport Scheme: ";
			mDebugText += MaterialManager::DEFAULT_SCHEME_NAME;						
		}

		// Switch to shader generator scheme.
		if (mKeyboard->isKeyDown(OIS::KC_F3))
		{
			mCamera->getViewport()->setMaterialScheme(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
			mDebugText = "Active Viewport Scheme: ";
			mDebugText += RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME;
		}	

		// Toggles per pixel per light model.
		if (mKeyboard->isKeyDown(OIS::KC_F4) && mTimeUntilNextToggle <= 0)
		{	
			mTimeUntilNextToggle = 1.0;

			static bool userPerPixelLightModel = true;
			RTShader::ShaderGenerator* shaderGenerator = RTShader::ShaderGenerator::getSingletonPtr();			
			RTShader::RenderState* renderState = shaderGenerator->getRenderState(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);

			// Remove all global sub render states.
			renderState->reset();

			// Add per pixel lighting sub render state to the global scheme render state.
			// It will override the default FFP lighting sub render state.
			if (userPerPixelLightModel)
			{
				RTShader::SubRenderState* perPixelLightModel = shaderGenerator->createSubRenderState(RTShader::PerPixelLighting::Type);
				renderState->addTemplateSubRenderState(perPixelLightModel);

				mDebugText = "Per pixel lighting model applied to shader generator default scheme";
			}
			else
			{
				mDebugText = "Per vertex lighting model applied to shader generator default scheme";
			}

			// Invalidate the scheme in order to re-generate all shaders based technique related to this scheme.
			shaderGenerator->invalidateScheme(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);

			userPerPixelLightModel = !userPerPixelLightModel;
		}	
		
	}

#endif

	//Adjust mouse clipping area
	//調整滑鼠裁剪區域;
	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;
	}

	//Unattach OIS before window shutdown (very important under Linux)
	//關閉視窗之前進行的處理;
	virtual void windowClosed(RenderWindow* rw)
	{
		//Only close for window that created OIS (the main window in these demos)
		//檢測是否關閉了我們的渲染視窗;
		if( rw == mWindow )
		{
			if( mInputManager )
			{
				//清除輸入裝置;
				mInputManager->destroyInputObject( mMouse );
				mInputManager->destroyInputObject( mKeyboard );
				mInputManager->destroyInputObject( mJoy );
				//銷燬輸入管理器;
				OIS::InputManager::destroyInputSystem(mInputManager);
				mInputManager = 0;
			}
		}
	}

	virtual ~ExampleFrameListener()
	{		
		//Remove ourself as a Window listener
		//移除所有的視窗事件監聽;
		WindowEventUtilities::removeWindowEventListener(mWindow, this);
		//關閉視窗;
		windowClosed(mWindow);
	}

	//按鍵事件處理;
	virtual bool processUnbufferedKeyInput(const FrameEvent& evt)
	{
		Real moveScale = mMoveScale;
		if(mKeyboard->isKeyDown(OIS::KC_LSHIFT))
			moveScale *= 10;

		if(mKeyboard->isKeyDown(OIS::KC_A))
			mTranslateVector.x = -moveScale;	// Move camera left 向左移動攝像頭矩陣;

		if(mKeyboard->isKeyDown(OIS::KC_D))
			mTranslateVector.x = moveScale;	// Move camera RIGHT

		if(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )
			mTranslateVector.z = -moveScale;	// Move camera forward

		if(mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S) )
			mTranslateVector.z = moveScale;	// Move camera backward

		if(mKeyboard->isKeyDown(OIS::KC_PGUP))
			mTranslateVector.y = moveScale;	// Move camera up

		if(mKeyboard->isKeyDown(OIS::KC_PGDOWN))
			mTranslateVector.y = -moveScale;	// 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 = "";
		}

		// Print camera details
		if(displayCameraDetails)
			mDebugText = "P: " + StringConverter::toString(mCamera->getDerivedPosition()) +
						 " " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation());

		// Return true to continue rendering
		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);
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
            // Adjust the input depending upon viewport orientation
            Radian origRotY, origRotX;
            switch(mCamera->getViewport()->getOrientation())
            {
                case Viewport::OR_LANDSCAPELEFT:
                    origRotY = mRotY;
                    origRotX = mRotX;
                    mRotX = origRotY;
                    mRotY = -origRotX;
                    break;
                case Viewport::OR_LANDSCAPERIGHT:
                    origRotY = mRotY;
                    origRotX = mRotX;
                    mRotX = -origRotY;
                    mRotY = origRotX;
                    break;
                    
                // Portrait doesn't need any change
                case Viewport::OR_PORTRAIT:
                default:
                    break;
            }
#endif
		}

		return true;
	}

	//移動攝像頭;
	virtual void 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);
	}

	//顯示debug資訊;
	virtual void showDebugOverlay(bool show)
	{
		if (mDebugOverlay)
		{
			if (show)
				mDebugOverlay->show();
			else
				mDebugOverlay->hide();
		}
	}

	// Override frameRenderingQueued event to process that (don't care about frameEnded)
	// 渲染佇列;
	bool frameRenderingQueued(const FrameEvent& evt)
	{

		if(mWindow->isClosed())	return false;

		mSpeedLimit = mMoveScale * evt.timeSinceLastFrame;

		//Need to capture/update each device
		//捕獲、更新裝置;
		mKeyboard->capture();
		mMouse->capture();
		if( mJoy ) mJoy->capture();

		bool buffJ = (mJoy) ? mJoy->buffered() : true;

    	Ogre::Vector3 lastMotion = mTranslateVector;

		//Check if one of the devices is not buffered
		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 OGRE_PLATFORM != OGRE_PLATFORM_APPLE_IOS
		if( !mKeyboard->buffered() )
			if( processUnbufferedKeyInput(evt) == false )
				return false;

#ifdef USE_RTSHADER_SYSTEM
		processShaderGeneratorInput();
#endif

#endif
		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資訊;
	String mDebugText;
	//主要用於截圖;
	unsigned int mNumScreenShots;
	//該demo中,攝像機會旋轉;
	float mMoveScale;
	//速度限制;
	float mSpeedLimit;
	//同樣用於攝像機變換;
	Degree mRotScale;
	// just to stop toggles flipping too fast
	//延時;
	Real mTimeUntilNextToggle ;
	//滑鼠旋轉的角度,用於攝像機的更新;
	Radian mRotX, mRotY;
	//紋理差值的型別,列舉型別;
	TextureFilterOptions mFiltering;
	int mAniso;

	int mSceneDetailIndex ;
	//移動速度;
	Real mMoveSpeed;
	//旋轉速度;
	Degree mRotateSpeed;
	//debug檢視;
	Overlay* mDebugOverlay;

	//OIS Input devices
	//一些輸入裝置(輸入裝置管理器);
	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 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則是一個屬性配置檔案,主要儲存使用者自定義的一些屬性,即下圖所示的介面的一些屬性。



檔案如下:

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

相信這裡就不用多解釋,大家都明白了。

4. Reference:

http://yarin.iteye.com/blog/561474

http://yarin.iteye.com/blog/561477

http://blog.163.com/[email protected]/blog/static/70234777201141143014386/