Ogre-Paged 教程(一)

来源:互联网 发布:苹果编程器 编辑:程序博客网 时间:2024/06/11 16:07

什么是Ogre-Paged?

             PagedGeometry是一个Ogre优化大场景中大量实体渲染的一个工具,特别适合于密集的森林以及室外场景,这些大场景中往往有成千上万的树木,灌木,草,石头等等等。
        Paged geometry拥有众多的渲染优势,最大的一点在于——速度。如果使用恰当的话,室外场景的渲染效率可以达到提高100倍甚至更多。同时,静态场景是分页的,那么每一次只需要当前需要的对应实体,这也就提供了一种扩展室外场景到很大范围的可能,甚至构建一个无穷大的虚拟世界。
 
     Example均为官方文档里面附带的教程

Example1

我们按照Ogre的基本框架首先加入如下代码作为主函数

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR strCmdLine, INT nCmdShow)#elseint main(int argc, char *argv[])#endif{//Initialize OgreRoot *root = new Ogre::Root("");//Load appropriate plugins//[NOTE] PagedGeometry needs the CgProgramManager plugin to compile shaders#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32#ifdef _DEBUGroot->loadPlugin("Plugin_CgProgramManager_d");root->loadPlugin("Plugin_OctreeSceneManager_d");root->loadPlugin("RenderSystem_Direct3D9_d");root->loadPlugin("RenderSystem_GL_d");#elseroot->loadPlugin("Plugin_CgProgramManager");root->loadPlugin("Plugin_OctreeSceneManager");root->loadPlugin("RenderSystem_Direct3D9");root->loadPlugin("RenderSystem_GL");#endif#elseroot->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, continueif (result){World myWorld;myWorld.load();//Load worldmyWorld.run();//Display world}//Shut down Ogredelete root;return 0;}

其中,class World代表了整个世界,定义如下:

class World{public:World();~World();void load();//Loads the 3D scenevoid unload();//Unloads the 3D scene cleanlyvoid run();//Runs the simulationprivate:void render();//Renders a single frame, updating PagedGeometry and Ogrevoid processInput();//Accepts keyboard and mouse input, allowing you to move around in the worldbool 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 objectsOIS::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 managerroot = Root::getSingletonPtr();window = root->initialise(true, AppTitle);sceneMgr = root->createSceneManager(ST_EXTERIOR_CLOSE);//Initialize the camera and viewportcamera = sceneMgr->createCamera("MainCamera");viewport = window->addViewport(camera);viewport->setBackgroundColour(ColourValue(0.47f, 0.67f, 0.96f));//Blue sky background colorcamera->setAspectRatio(Real(viewport->getActualWidth()) / Real(viewport->getActualHeight()));camera->setNearClipDistance(1.0f);camera->setFarClipDistance(2000.0f);//Set up lightingLight *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 OISusing 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 orientationcamPitch = 0;camYaw = 0;}World::~World(){//Shut down OISinputManager->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 awaysceneMgr->setFog(FOG_LINEAR, viewport->getBackgroundColour(), 0, 100, 700);//Load the terrainsceneMgr->setWorldGeometry("terrain.cfg");//Start off with the camera at the center of the terraincamera->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 firstTreeLoader3D *treeLoader = new TreeLoader3D(trees, TBounds(0, 0, 1500, 1500));//And add a entity at the desired position/rotation/scaletreeLoader->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();}

本例的显示效果


             

0 0