1 /* 使用OGRE默认的资源文件语法分析器得到所有的资源 */ 2 mResourceCfg = "plugins_d.cfg"; 3 Ogre::ConfigFile cf; 4 cf.load(mResourceCfg); 5 6 Ogre::ConfigFile::SectionInterator seci; 7 seci = cf.getSectionInterator(); 8 Ogre::ConfigFile::SettingsMultiMap *settings; 9 Ogre::ConfigFile::SettingsMultiMap::Interator *i; 10 Ogre::String secName, typeName, archName; 11 while(seci.hasMoreElement()) 12 { 13 secName = seci.peekNextKey(); 14 settings = seci.getNext(); 15 for(i=settings->begin(); i != settings->end(); ++i) 16 { 17 /* 隐藏了访问资源的细节,不论是文件夹还是ZIP文件,都是透明的 */ 18 typeName = i->first; 19 archName = i->second; 20 /* 现在OGRE核心之一资源管理器,就能够直接取得需要的资源 */ 21 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName,typeName,secName); 22 } 23 } 24 25 26 /* 你如果不想在你的程序运行前出现配置对话框,可以用Root方法直接写入配置文件 */ 27 Ogre::RenderWindow *mWindow; 28 /* 这里有个细节问题,即或运算先判断前一个是否成立,如果成立后面一个不会继续判断 */ 29 if(!(mRoot->restoreConfig() || mRoot->showConfigDialog())) 30 { 31 return false; 32 } 33 /* 你也可以用WIN32API自己创建一个用于渲染的窗口 */ 34 mWindow = mRoot->initialise(true, "Game Render Window"); 35 36 /* 一个游戏需要大量的资源文件,可是在某个时刻却只需要其中的一部分;前一部分已经做完,后部分马上完成; 37 * 不过在此之前,需要设置MipMap的等级,参考笔记中MipMap资料 38 */ 39 Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5); 40 Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); 41 42 /* 现在,完成了第一阶段-准备阶段,现在进入启动阶段-创建场景: 43 * 1. 创建场景管理器 44 * 2. 创建相机 45 * 3. 创建观察点 46 */ 47 Ogre::SceneManager *mSceneMgr; 48 mSceneMgr = mRoot->createSceneManager("DefaultSceneManager"); 49 Ogre::Camera *mCamera; 50 mCamera = mSceneMgr->createCamera("DefaultCamera"); 51 mCamera->setPosition(Ogre::Vector3(0,0,80)); 52 mCamera->lookAt(Ogre::Vector3(0,0,-300)); // why -300 ,not 0 53 mCamera->setNearClipDistance(5); // 如果相机与物体距离小于5个距离单元,就只能看到物体内部了。 54 Ogre::Viewport *mViewport; 55 /* 这里猜测一下设计上的思路: 56 * 相机、灯光等都被看做特殊的实体,所以应该由资源管理器管理; 57 * 而观察点并不是一个实体,比如照相的时候别人让你站在某个位置照相,那个位置是属于空间中的点; 58 * 在这里那个空间就是渲染窗口,所以观察点应该由渲染窗口添加和管理; 59 * 正是因为将相机也当做实体资源,而资源在OGRE中使用非常灵活,你可以多创建几个相机,摆放好位置, 60 * 当你想用哪个相机时直接指定那个相机的位置是观察点即可; 61 * 进一步思考: 62 * 如果我想将一个渲染窗口分开在不同位置分别观察某个场景,那么实现上应该再创建一个观察点,然后 63 * 每个观察点单独指定相机。 64 */ 65 mViewport = mWindow->addViewport(mCamera); 66 /* 疑问: 67 * 为什么需要设置观察点的背景颜色呢?难道不是所有的颜色都是由灯光指定? 68 * 背景颜色的指定是不是相当于指定白天黑夜黄昏? 69 */ 70 mViewport->setBackgroundColor(Ogre::ColourValue(0,0,0)); 71 /* 疑问: 72 * 设置相机的纵横比,如果参数偏大,会是什么效果? 73 * 偏小呢? 74 */ 75 mCamera->setAspectRatio(Ogre::Real(mViewport->getActualWidth()) / Ogre::Real(mViewport->getActualHeight())); 76 77 /* 现在,启动工作也完成了,只需要载入实体就可以看到丰富的场景效果了 */ 78 /* 因为已经初始化过资源文件了,我们只需要直接指定资源名称就可以使用了 */ 79 Ogre::Entity *ogreHead; 80 ogreHead = mSceneManager->createEntity("Head", "ogrehead.mesh"); 81 Ogre::SceneNode *headNode; 82 /* OGRE中实体的名称都必须是惟一的,你可以通过两种方式访问到这些实体: 83 * 1. 实体句柄,其实是一个指针,比如headNode 84 * 2. 实体名称,比如headNode指向的场景节点的名称也是headNode 85 */ 86 headNode = mSceneManager->getRootSeneNode()->createChildSceneNode("headNode"); 87 headNode->setPosition(Ogre::Vector3(0,0,0)); 88 headNode->attachObject(ogreHead); 89 /* 疑问: 90 * AmbientLight是环境光,Viewport背景光又是什么呢? 91 */ 92 mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5,0.5,0.5)); 93 Ogre::Light *light; 94 light = mSceneMgr->createLight("MainLight"); 95 light->setPosition(Ogre::Vector3(20,100, 50)); 96 97 /* 你现在可以得到这个场景的效果图了,不过却是一闪而过的;我希望计算机保持这个场景, 98 * 并且当我与之交互时,能够改变这个场景中的某个部分;那么你就需要一个循环等待的过程; 99 * 这个过程在OGRE中叫做渲染循环: 100 * OGRE提供了多种方式让你根据每个循环的特点选取其中一个,最简单的是: 101 * Ogre::Root::RenderOneFrame() 102 * 下面这段代码实现的功能是,一直等待用户关闭窗口,或者渲染一帧画面的时候出错了。 103 */ 104 while(true) 105 { 106 Ogre::WindowEventUtilities::messagePump(); 107 if(mWindow->isClosed()) 108 { 109 return false; 110 } 111 112 if(!mRoot->RenderOneFrame()) 113 { 114 return false; 115 } 116 } 117 118 /* OIS(Object Oriented Input System )是OGRE推荐使用的用户输入插件; 119 * 如果在进入渲染循环之前设置了OIS,那么我们的鼠标和键盘就能够在场景中得到响应; 120 * 这相当于为OGRE添加了一个中断系统 121 */ 122 Ogre::LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***"); 123 OIS::ParamList pl; 124 size_t WindowHnd = 0; 125 std::ostringstream windowHndStr; 126 127 mWindow->getCustomAttribute("WINDOW", &windowHnd); 128 windowHndStr << windowHnd; 129 pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str())); 130 131 mInputManager = OIS::InputManager::createInputSystem(pl); 132 133 mKeyboard = static_cast<OIS::Keyboard *>(mInputManager->createInputObject(OIS::OISKeyboard, false)); 134 mMouse = static_cast<OIS::Keyboard *>(mInputManager->createInputObject(OIS::OISKeyboard, false)); 135 136 /* 我们不仅要让渲染循环能够响应键盘上对场景的操作,还要在将渲染窗口关闭的时候同时停止OIS模块的运行, 137 * 之所以这么做是因为OIS是独立于OGRE的单独模块,写好后,在主程序中将其注册为窗口监听函数。 138 */ 139 void Game::windowClosed(Ogre::RenderWindow *rw) 140 { 141 if(rw == mWindow) 142 { 143 if(mInputManager) 144 { 145 mInputManager->destroyInputObject(mKeyboard); 146 mInputManager->destroyInputObject(mMouse); 147 148 OIS::InputManager::destroyInputSystem(mInputManager); 149 mInputManager = 0; 150 } 151 } 152 } 153 154 Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); 155 156 /* 有了OIS作为内嵌的中断系统,我们可以编写帧监听函数,这些函数实际上相当于中断处理程序 157 * 首先要在Game类的保护区申明如下定义: 158 * virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt); 159 * 在保护区表明该功能不能被继承,然而为何在保护区? 160 */ 161 bool Game::frameRenderingQueued(const Ogre::FrameEvent &evt) 162 { 163 if(mWindow->isClosed()) 164 { 165 return false; 166 } 167 mKeyboard->capture(); 168 mMouse->capture(); 169 170 if(mKeyboard->isKeyDown(OIS::KC_ESCAPE)) 171 { 172 return false; 173 } 174 175 return true; 176 } 177 /* 中断程序写好后,需要注册才能使用 */ 178 mRoot->addFrameListener(this); 179 mRoot->startRendering(); 180 181 182