dynamic random page loader

tdev

28-07-2008 07:24:04

so i had a problem to face:
add a decent amount of trees to a 130x130 km terrain. If you do this with the default TreeLoader2D and addTree for like 30 million times, you will have to wait a long time and the memory consumption will be great. So i derived a new TreeLoader from the original class, which adds new trees to each loaded page dynamically.

What do you think about it?
Also, after flying around a bit in the terrain, the whole thing slows down a lot. What could be the cause?


#ifndef __RandomTreeLoader_H__
#define __RandomTreeLoader_H__

#include "PagedGeometry.h"
#include "PropertyMaps.h"
#include "TreeLoader2D.h"

#include <OgrePrerequisites.h>


namespace Forests {

class TreeIterator3D;
class TreeIterator2D;

class RandomTreeLoader : public TreeLoader2D
{
public:
RandomTreeLoader(PagedGeometry *geom, const TBounds &bounds) : TreeLoader2D(geom, bounds)
{
}

~RandomTreeLoader()
{
}

void loadPage(PageInfo &page)
{
//Calculate x/z indexes for the grid array
page.xIndex -= Math::Floor(gridBounds.left / pageSize);
page.zIndex -= Math::Floor(gridBounds.top / pageSize);

//Check if the requested page is in bounds
if (page.xIndex < 0 || page.zIndex < 0 || page.xIndex >= pageGridX || page.zIndex >= pageGridZ)
return;

// just take the first tree registered as an example
Entity *entity = pageGridList.begin()->first;
std::vector<TreeDef> *pageGrid = pageGridList.begin()->second;
std::vector<TreeDef> &treeList = _getGridPage(pageGrid, page.xIndex, page.zIndex);

// example values
minimumScale=0.07;
maximumScale=0.13;

// if there are no tress in the page to be loaded, add some randomly
if(treeList.size() == 0)
{
// only add trees if there are none in this page...
for (int n=0; n < pageSize/10; n++)
{
//Create the new tree
Real xrel = Math::RangeRandom(0, pageSize);
Real zrel = Math::RangeRandom(0, pageSize);
Degree yaw(Math::RangeRandom(0, 360));
Real scale = Math::RangeRandom(minimumScale, maximumScale);

TreeDef tree;
tree.xPos = 65535 * (xrel - (page.xIndex * pageSize)) / pageSize;
tree.zPos = 65535 * (zrel - (page.zIndex * pageSize)) / pageSize;
tree.rotation = 255 * (yaw.valueDegrees() / 360.0f);
tree.scale = 255 * ((scale - minimumScale) / maximumScale);
treeList.push_back(tree);
}
}

// now load page as normal
TreeLoader2D::loadPage(page);
}
};

}
#endif


to be able to derivated, change private: to protected: in treeloader2d.h (why is this no default?)

tdev

28-07-2008 07:40:13

even added page unloading now, but the FPS still goes down as more trees are added :(


#ifndef __RandomTreeLoader_H__
#define __RandomTreeLoader_H__

#include "PagedGeometry.h"
#include "PropertyMaps.h"
#include "TreeLoader2D.h"

#include <OgrePrerequisites.h>


namespace Forests {

class TreeIterator3D;
class TreeIterator2D;

class RandomTreeLoader : public TreeLoader2D
{
public:
RandomTreeLoader(PagedGeometry *geom, const TBounds &bounds) : TreeLoader2D(geom, bounds)
{
}

~RandomTreeLoader()
{
}

void loadPage(PageInfo &page)
{
//Calculate x/z indexes for the grid array
page.xIndex -= Math::Floor(gridBounds.left / pageSize);
page.zIndex -= Math::Floor(gridBounds.top / pageSize);

//Check if the requested page is in bounds
if (page.xIndex < 0 || page.zIndex < 0 || page.xIndex >= pageGridX || page.zIndex >= pageGridZ)
return;

// just take the first tree registered as an example
std::vector<TreeDef> *pageGrid = pageGridList.begin()->second;
std::vector<TreeDef> &treeList = _getGridPage(pageGrid, page.xIndex, page.zIndex);

// example values
minimumScale=0.07;
maximumScale=0.13;

// if there are no tress in the page to be loaded, add some randomly
if(treeList.size() == 0)
{
// only add trees if there are none in this page...
for (int n=0; n < pageSize/10; n++)
{
//Create the new tree
Real xrel = Math::RangeRandom(0, pageSize);
Real zrel = Math::RangeRandom(0, pageSize);
Degree yaw(Math::RangeRandom(0, 360));
Real scale = Math::RangeRandom(minimumScale, maximumScale);

TreeDef tree;
tree.xPos = 65535 * (xrel - (page.xIndex * pageSize)) / pageSize;
tree.zPos = 65535 * (zrel - (page.zIndex * pageSize)) / pageSize;
tree.rotation = 255 * (yaw.valueDegrees() / 360.0f);
tree.scale = 255 * ((scale - minimumScale) / maximumScale);
treeList.push_back(tree);
}
}

// now load page as normal
TreeLoader2D::loadPage(page);
}

void unloadPage(PageInfo &page)
{
//Calculate x/z indexes for the grid array
page.xIndex -= Math::Floor(gridBounds.left / pageSize);
page.zIndex -= Math::Floor(gridBounds.top / pageSize);

//Check if the requested page is in bounds
if (page.xIndex < 0 || page.zIndex < 0 || page.xIndex >= pageGridX || page.zIndex >= pageGridZ)
return;

// just take the first tree registered as an example
std::vector<TreeDef> *pageGrid = pageGridList.begin()->second;
std::vector<TreeDef> &treeList = _getGridPage(pageGrid, page.xIndex, page.zIndex);

// clear all existing trees
if(treeList.size() >= 0)
treeList.clear();

// now unload page as normal
TreeLoader2D::unloadPage(page);
}
};

}
#endif

JohnJ

28-07-2008 15:30:51

The problem here is that you're still adding trees to a giant list (consuming memory and CPU time), which are passed on to the actual loading system. There's a much more efficient way to do it, which requires no additional memory at all, and none of the unnecessary complexity of TreeLoader2D that you're inheriting.

I would recommend that you read Tutorial 4.pdf. This tutorial shows you how to make a simple, efficient dynamic random tree loader (by extending PageType).

tdev

28-07-2008 20:31:27

I would recommend that you read Tutorial 4.pdf. This tutorial shows you how to make a simple, efficient dynamic random tree loader (by extending PageType).
thank you very much i am going to read that now.

tdev

31-07-2008 01:18:34

i read tutorial 4 and tried to make it working. my results:
- still major slowdown (fly around some kilometers and the FPS sinks ...)
- if i use the imposter and mesh, both are not in sync. Means the imposter position does not fit to the mesh positions. I think for that reason an array would be required (as i did above?)

the implementation:

#ifndef __RandomTreeLoader_H__
#define __RandomTreeLoader_H__

#include "PagedGeometry.h"
#include "PropertyMaps.h"
#include "TreeLoader2D.h"

#include <OgrePrerequisites.h>


namespace Forests {

class TreeIterator3D;
class TreeIterator2D;

class RandomTreeLoader : public PageLoader
{
public:
RandomTreeLoader(PagedGeometry *geom, const TBounds &bounds, Ogre::Entity *te) : treeEntity(te)
{
}

~RandomTreeLoader()
{
}

void loadPage(PageInfo &page)
{
Vector3 position;
Quaternion rotation;
Vector3 scale;
ColourValue color;
for (int i = 0; i < 10; i++)
{
//Calculate a random rotation around the Y axis
rotation = Quaternion(Degree(Math::RangeRandom(0, 360)),
Vector3::UNIT_Y);
//Calculate a position within the specified boundaries
position.x = Math::RangeRandom(page.bounds.left, page.bounds.right);
position.z = Math::RangeRandom(page.bounds.top, page.bounds.bottom);
//Calculate terrain height at pos.x / pos.z to get pos.y
if (heightFunction != NULL)
position.y = heightFunction(position.x, position.z, NULL);
else
position.y = 0.0f;
//Calculate a scale value (uniformly scaled in all dimensions)
float uniformScale = Math::RangeRandom(0.07f, 0.13f);
scale.x = uniformScale;
scale.y = uniformScale;
scale.z = uniformScale;
//All trees will be fully lit in this demo
color = ColourValue::White;
//Add a tree to the scene at the desired location
addEntity(treeEntity, position, rotation, scale, color);
}
}

void setHeightFunction(Ogre::Real (*heightFunction)(Ogre::Real x, Ogre::Real z, void *unused), void *unused=0)
{
this->heightFunction = heightFunction;
}

void unloadPage(PageInfo &page)
{

}
protected:
//Height data
Ogre::Real (*heightFunction)(Ogre::Real x, Ogre::Real z, void *unused); //Pointer to height function
Ogre::Entity *treeEntity;
};

}
#endif