您的位置:首页 > 其它

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();
}


本例的显示效果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: