Ogre-Paged 教程(一)
2014-02-28 21:47
141 查看
什么是Ogre-Paged?
PagedGeometry是一个Ogre优化大场景中大量实体渲染的一个工具,特别适合于密集的森林以及室外场景,这些大场景中往往有成千上万的树木,灌木,草,石头等等等。Paged geometry拥有众多的渲染优势,最大的一点在于——速度。如果使用恰当的话,室外场景的渲染效率可以达到提高100倍甚至更多。同时,静态场景是分页的,那么每一次只需要当前需要的对应实体,这也就提供了一种扩展室外场景到很大范围的可能,甚至构建一个无穷大的虚拟世界。
Example均为官方文档里面附带的教程
Example1
我们按照Ogre的基本框架首先加入如下代码作为主函数#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR strCmdLine, INT nCmdShow) #else int main(int argc, char *argv[]) #endif { //Initialize Ogre Root *root = new Ogre::Root(""); //Load appropriate plugins //[NOTE] PagedGeometry needs the CgProgramManager plugin to compile shaders #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 #ifdef _DEBUG root->loadPlugin("Plugin_CgProgramManager_d"); root->loadPlugin("Plugin_OctreeSceneManager_d"); root->loadPlugin("RenderSystem_Direct3D9_d"); root->loadPlugin("RenderSystem_GL_d"); #else root->loadPlugin("Plugin_CgProgramManager"); root->loadPlugin("Plugin_OctreeSceneManager"); root->loadPlugin("RenderSystem_Direct3D9"); root->loadPlugin("RenderSystem_GL"); #endif #else root->loadPlugin("Plugin_CgProgramManager"); root->loadPlugin("Plugin_OctreeSceneManager"); root->loadPlugin("RenderSystem_GL"); #endif //Show Ogre's default config dialog to let the user setup resolution, etc. bool result = root->showConfigDialog(); //If the user clicks OK, continue if (result) { World myWorld; myWorld.load(); //Load world myWorld.run(); //Display world } //Shut down Ogre delete root; return 0; }
其中,class World代表了整个世界,定义如下:
class World { public: World(); ~World(); void load(); //Loads the 3D scene void unload(); //Unloads the 3D scene cleanly void run(); //Runs the simulation private: void render(); //Renders a single frame, updating PagedGeometry and Ogre void processInput(); //Accepts keyboard and mouse input, allowing you to move around in the world bool running; //A flag which, when set to false, will terminate a simulation started with run() //Various pointers to Ogre objects are stored here: Root *root; RenderWindow *window; Viewport *viewport; SceneManager *sceneMgr; Camera *camera; //OIS input objects OIS::InputManager *inputManager; OIS::Keyboard *keyboard; OIS::Mouse *mouse; //Variables used to keep track of the camera's rotation/etc. Radian camPitch, camYaw; //Pointers to PagedGeometry class instances: PagedGeometry *trees, *bushes; };
在构造函数的实现中做如下操作:
下面的这些操作都是为了渲染一个基本的世界,并且能够提供场景漫游的功能
World::World() { //Setup Ogre::Root and the scene manager root = Root::getSingletonPtr(); window = root->initialise(true, AppTitle); sceneMgr = root->createSceneManager(ST_EXTERIOR_CLOSE); //Initialize the camera and viewport camera = sceneMgr->createCamera("MainCamera"); viewport = window->addViewport(camera); viewport->setBackgroundColour(ColourValue(0.47f, 0.67f, 0.96f)); //Blue sky background color camera->setAspectRatio(Real(viewport->getActualWidth()) / Real(viewport->getActualHeight())); camera->setNearClipDistance(1.0f); camera->setFarClipDistance(2000.0f); //Set up lighting Light *light = sceneMgr->createLight("Sun"); light->setType(Light::LT_DIRECTIONAL); light->setDirection(Vector3(0.0f, -0.5f, 1.0f)); sceneMgr->setAmbientLight(ColourValue(1, 1, 1)); //Load media (trees, grass, etc.) ResourceGroupManager::getSingleton().addResourceLocation("media/trees", "FileSystem"); ResourceGroupManager::getSingleton().addResourceLocation("media/terrains", "FileSystem"); ResourceGroupManager::getSingleton().addResourceLocation("media/grass", "FileSystem"); ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); //Initialize OIS using namespace OIS; size_t windowHnd; window->getCustomAttribute("WINDOW", &windowHnd); inputManager = InputManager::createInputSystem(windowHnd); keyboard = (Keyboard*)inputManager->createInputObject(OISKeyboard, false); mouse = (Mouse*)inputManager->createInputObject(OISMouse, false); //Reset camera orientation camPitch = 0; camYaw = 0; } World::~World() { //Shut down OIS inputManager->destroyInputObject(keyboard); inputManager->destroyInputObject(mouse); OIS::InputManager::destroyInputSystem(inputManager); unload(); }
接下来就是我们构建核心场景(类似Basic Tutorial里面的CreateScene函数)
加载雾,地形,以及相机
需要注意的是这一个函数setWorldGeometry以及文件terrain.cfg(文件在官方下载里面有)
在Ogre V1.8.1以及之后的版本不再支持ST_EXTERIOR_CLOSE等SceneManager,所以会
自动初始化SceneManager为ST_GENERIC,这里采用的Ogre sdk 为 V1.7.4
//Setup the fog up to 500 units away sceneMgr->setFog(FOG_LINEAR, viewport->getBackgroundColour(), 0, 100, 700); //Load the terrain sceneMgr->setWorldGeometry("terrain.cfg"); //Start off with the camera at the center of the terrain camera->setPosition(700, 100, 700);
完成以上几步以后地形创建工作就已经完成了
接下来需要创建需要的树
第一步,创建一个PageGeometry对象,如
PagedGeometry *trees = new PagedGeometry();
构造函数可以加入两个参数,这里先不填写,后面可以通过其它操作进行修改。这两个参数的设置顺序是无关紧要的。一般而言,创建为对象以后接下来需要进行的是设置相机
PagedGeometry *trees = new PagedGeometry();
PageGeometry设计的时候并没有考虑多相机的问题,但从技术层面上说,仍然是可以使用多相机的(调用setCamer()函数在渲染之前切换相机)。
设置相机的目的是为了进行LODs计算,更平滑的缓存静态物体。没有相机的话,几乎所有的优化都不能实现(实际上几乎所有的内部优化算法都依赖于照相机的位置)。
接下来继续设置如下:
trees->setPageSize(50); trees->setInfinite();
这两个函数做了如下两件事情:
①setPageSize(50) 函数设置了单个page的大小为50*50单位。内部的几乎所有信息都是存放在这样的名叫page的网格当中。page的大小越大,帧率可能会更好,但有时候也会引起震颤。需要通过一些实践来确定合适的page大小达到最优化的目标。
②setInfinite() 告诉PagedGeometry不对任何的几何实体(树等其它物体)做尺寸上的要求。默认就是该设置,所以其实不必调用该函数也可以。
除此以外,也可以通过调用PagedGeometry::setBounds()来设置。这个函数允许设置相应的限制使得实体能被包含在设置的范围之中。设置世界大小的好处在于能够提高一些性能,因为在infinite模式下,缓存只载入当前需要显示屏幕上显示的东西。
目前还不能通过paged-geom显示任何东西。还需要设置PagedGeometry 如何在屏幕上显示树木或其它东西,通过addDetailLevel() 可以实现:
trees->addDetailLevel<BatchPage>(150, 30); trees->addDetailLevel<ImpostorPage>(400, 50);
第一行表示,150单位以内的树木采用BatchPage 的方式显示(视觉效果上没有降低,但比一般的显示方式要快),第二个参数30表示LOD在超过30单位以外(在150基础上)会减弱。这个参数是非必须的,会降低显示效果。
第二行加入了第二个细节层ImpostorPage,在400单位以外的图像采用平面图像。ImpostorPage非常的快,但应该在距离较远的地方使用否则可能会被注意到这是平面图形。在此基础上50单位开外的渲染就没有LOD支持,连平面图像的效果也会消失。
注意 addDetailLevel()是PagedGeometry 中必须被调用的函数,而且必须以从近处到远处的方式调用,比如不能先定义400单位以外的效果再定义150单位以外的效果。
目前的代码如下:
PagedGeometry *trees = new PagedGeometry();
trees->setCamera(camera);
trees->setPageSize(50); trees->setInfinite();
trees->addDetailLevel<BatchPage>(150, 30);
trees->addDetailLevel<ImpostorPage>(400, 50);
加入树木
Paged_Geom的场景管理并不是直接采用Ogre的SceneManager 结构,所以直接加入实体到Ogre的场景不会得到任何的优化,必须通过Page_Geom的方式进行。PagedGeometry 类里面没有提供任何创建和移除实体的函数,对应的,需要采用PageLoader-derived相关的类,可以把 PageLoader 想象成一系列要传给PagedGeometry 的实体列表。
PagedGeometry 中有两种不同的加载类,TreeLoader2D 和TreeLoader3D。在这个例子里面我们使用TreeLoader3D进行(更为简单一些),只需要下面这几行就可以加载实体:
//Create a new TreeLoader3D object first TreeLoader3D *treeLoader = new TreeLoader3D(trees, TBounds(0, 0, 1500, 1500)); //And add a entity at the desired position/rotation/scale treeLoader->addTree(myEntity, position, yaw, scale);
第一行创建了一个TreeLoader3D 实例,注意它需要一个PagedGeometry 对象的指针,而且还需要一个边界范围作为限制。与PagedGeometry Engine本身不同,TreeLoader3D 总是需要一个范围参数,因为范围里面的实体总是被存储在内存当中(采用一种压缩技术,只需要少量的MB内存就可以存储上百万棵树)。
一旦TreeLoader3D 被创建,剩下的就是加入实体了。如第二行所示,参数主要有实体,位置,扭转,缩放。
加载完毕以后看,需要设置PagedGeometry 的page loader
trees->setPageLoader(treeLoader);
更新PagedGeometry
对每一帧,需要调用PagedGeometry::update()来更新PagedGeometry的实例用于计算。如果不调用的话,树木可能会显示不正常。[each frame] { trees->update(); }
本例的显示效果
相关文章推荐
- Ogre 1.7中的地形教程
- OGRE基础教程六 The Ogre Startup Sequence
- Ogre3d Android平台编译教程
- Ogre笔记九:基础教程六—CEGUI和Ogre
- OgreOde官方教程出现的问题
- OGRE基础教程1(下)
- ogre 入门教程
- Ogre源码编译教程
- OGRE基础教程七 CEGUI and Ogre
- Ogre基础教程8:多个以及双场景管理器
- OGRE CG教程(二): 如何编译CG
- OGRE 引擎官方基础教程 (二)
- Ogre 1.7中的地形教程
- [OGRE]基础教程来一发:来谈一谈基础框架
- OGRE基础教程八 Multiple and Dual SceneManagers
- 基础教程六(CEGUI和OGRE)
- OGRE初级教程总结
- Ogre 1.7.2中的地形教程
- OGRE基础教程七运行时遇到的两个异常
- Ogre基础教程(一)----- 场景管理器,场景节点和实体.