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/cp7618@yeah/blog/static/70234777201141143014386/
http://blog.csdn.net/yangtrees/article/details/8765490