New PagedGeometry example, with new (free) tree models!

JohnJ

02-05-2008 05:04:14

In case you haven't noticed, the latest version of PagedGeometry (v1.05 at the time of this writing) includes a new example: "Example 8 - Forest Demo". This example uses all new artwork which was kindly donated by Christian Herzog (mr.Zog) from www.3d-diggers.de , and is free for anyone to use for commercial or non-commercial projects!

Here's the full license:
"Veggies for the people"
(c) 3D-Diggers 2008
Author: Christian Herzog
Web: www.3d-diggers.de
-----------------------------------------------------------

License:
-----------------------------------------------------------
"Do what you want"

This is a free give away from the 3D-Diggers.
You can use it in any project you want (commercial, non-commercial, etc.).

I'd be happy though, if anybody using it, could send me a link to the project or so! (just to know IF this is actually being used... ;) )
But again, you don't have to.
My email is [removed].

If you want to see more, drop by on our homepage: www.3d-diggers.de.
(you get the full fir pack there, which can easily be exported for OGRE as you can see)


And some screenshots of the new example:

Amenothep

02-05-2008 20:25:16

Works like a treat :!:

Xavyiy

02-05-2008 22:10:14

Very nice :)!

kungfoomasta

02-05-2008 22:15:34

Great work on this JohnJ! And thanks to Christian Herzog for donating the artwork! :D

Amenothep

03-05-2008 04:40:37


I am missing the grizzlies.. :shock: :D

An official height range function ( i did some ranges on treeloader3d here) would be good and natural

if ((position.y < 30) && (position.y > 15)) {
load trees etc
}

besides a densitymap also on the treeloader.

How do you do that (someone somewhere wrote something about instanciating the grassloader or so. ) :?:

JohnJ

03-05-2008 16:04:53

Wow, very nice!

I'm not sure what your question is, but GrassLoader has a setHeightRange() function which should accomplish what you're asking. The treeloaders don't have any functions like that because you add each tree individually.

Amenothep

03-05-2008 18:09:37

Hi John,

I was asking how one could make a densitymap for trees not for grass. It was somehow answered in another thread but I didn't understand it.

Could you give some pseudo code?


l->setDensityMap("densitymap-new4.dds");


for trees.


it doesn't really need to be density it could be simply,
if image region/pixel black
put tree
if white
image region/pixel don't put tree.

Maybe he explains it better:

"For vegetation placement, we process national landcover classification (LCC) data of the given terrain region to examine the closeness of related LCC types. Using this analysis and the topological influences derived previously (inspired by Johan Hammes' work), a probability map is produced for each LCC type to reflect the likelihood that a particular LCC type exists within the pixel's corresponding area on the terrain surface. Random draws against this probability map determine the location, density, and type of vegetation objects found within the synthetic environment. The resulting geotypical distribution looks plausible and this simple algorithm can be extended to incorporate soil moisture and other factors or to generate geotypical distributions of man-made landscape features."
http://www.movesinstitute.org/~wdwells/4181/index.html

They have some source from Wells Genetics PhD in Delta3D but it's SLOW.. and awkward ( I mean the Delta 3D implementation ).
One doesn't get anywhere useful with D3D imo. :?

Amenothep

03-05-2008 19:29:36

The treeloaders don't have any functions like that because you add each tree individually.

Hmm, so one would need just a placement class. I'll try to work on one if I have time.

I am not a computer scientist, my base education is biology etc.

I'll try to get:

Gaussian distribution as it's more natural in some circumstances.

Tree line. Aka Height data.

Slope, gonna be tricky.

I guess everything else should come from a density map so the user can put their biological knowledge into it and it's not forced onto them and given the amount of plant species it's also unfeasible. Theoretically everything can be achieved with the density/growth map I guess.

edit: just remembered tree height/plant height is I guess probably normally distributed. Although I am not sure if one would actually notice it. :?

JohnJ

03-05-2008 20:53:37

Loading trees from a heightmap is currently not a feature included in PagedGeomety, so yeah you'd have to do it manually like some others have done.

Also, it would be best to skip using TreeLoader2D or TreeLoader3D and write your own custom PageLoader class (there's a tutorial and example on how to do this) if you're loading from any source other than individual tree positions. That way if your tree density map results in 100 million trees over a huge area, you won't run out of memory trying to add all of them to TreeLoader2D/TreeLoader3D.

Amenothep

03-05-2008 22:10:37

Loading trees from a heightmap is currently not a feature included in PagedGeomety, so yeah you'd have to do it manually like some others have done.

Hi I did that too, so there are no trees in the water. :D

Also, it would be best to skip using TreeLoader2D or TreeLoader3D and write your own custom PageLoader class (there's a tutorial and example on how to do this) if you're loading from any source other than individual tree positions. That way if your tree density map results in 100 million trees over a huge area, you won't run out of memory trying to add all of them to TreeLoader2D/TreeLoader3D.


Yeah I saw that example. :) I also ran some test runs with it, quite cool. 8)

Amenothep

04-05-2008 03:46:05


Could you give some pseudo code?



This seems how one gets a density map for trees.

myDensitymap= DensityMap::load("alpha_blend_4.png",CHANNEL_ALPHA);
myDensitymap->setMapBounds(TBounds(0, 0, 1024, 1024));
MapFilter filter = MAPFILTER_BILINEAR;
myDensitymap->setFilter(filter);


*snip*

float bla;

bla = myDensitymap->_getDensityAt_Unfiltered((int)position.x,(int)position.z);


if (bla < 0.3) {
treeLoader->addTree(tree1, position, yaw, scale);
}


Not added yet something stochastical, just an example.

klumhru

05-05-2008 15:06:53

This is how I did it:


void TreeLoader3D::setColorMap(const Ogre::String &mapFile, MapChannel channel)
{
if (colorMap){
colorMap->unload();
colorMap = NULL;
}
if (mapFile != ""){
colorMap = ColorMap::load(mapFile, channel);
colorMap->setMapBounds(actualBounds);
colorMap->setFilter(colorMapFilter);
}
}

void TreeLoader3D::setColorMap(Ogre::Texture *map, MapChannel channel)
{
if (colorMap){
colorMap->unload();
colorMap = NULL;
}
if (map){
colorMap = ColorMap::load(map, channel);
colorMap->setMapBounds(actualBounds);
colorMap->setFilter(colorMapFilter);
}
}

void TreeLoader3D::setTreeMap(Ogre::Entity *ent, Ogre::Texture *map, int trees /* = 4 */, Ogre::uint8 seed /* = 1 */, MapChannel channel /* = CHANNEL_COLOR */)
{
treeMap = TreeMap::load(map, channel);
_makeTreesFromMap(ent, trees, seed);
}

void TreeLoader3D::setTreeMap(Ogre::Entity *ent, const Ogre::String &mapFile, int trees /* = 4 */, Ogre::uint8 seed /* = 1 */, MapChannel channel /* = CHANNEL_COLOR */)
{
treeMap = TreeMap::load(mapFile, channel);
_makeTreesFromMap(ent, trees, seed);
}

void TreeLoader3D::_makeTreesFromMap(Ogre::Entity *ent, int trees /* = 4 */, Ogre::uint8 seed /* = 1 */)
{
treeMap->setMaxScale(maximumScale);
treeMap->setMinScale(minimumScale);
treeMap->setMapBounds(actualBounds);

if(seed == 0)
srand(0);
else if(seed == 1)
{
srand(time(NULL));
}
else
srand(seed);
PixelBox pb = treeMap->getPixelBox();
size_t height = pb.getHeight();
size_t width = pb.getWidth();
Real pxWidth = actualBounds.width() / width;
Real pxHeight = actualBounds.height() / height;
TRect<Real> pxArea;
// for each row
for(size_t h = 0; h < height; h++)
{
// for each pixel in row
for(size_t w = 0; w < width; w++)
{
// get actual location of pixel in rect
pxArea.left = w * pxWidth;
pxArea.right = pxArea.left + pxWidth;
pxArea.top = h * pxHeight;
pxArea.bottom = pxArea.top + pxHeight;
// get densitiy in the middle of the pixel and if it's zero, skip loop instance, no trees to see here
float scale = treeMap->getDensityAt(pxArea.left + (pxWidth/2), pxArea.top +(pxHeight/2));

if( scale == 0.0f)
continue;
for(int i = 0; i < trees; i++)
{
Vector3 pos;
pos.x = Math::RangeRandom(pxArea.left, pxArea.right);
pos.z = Math::RangeRandom(pxArea.top, pxArea.bottom);
if(heightFunction)
pos.y = heightFunction(pos.x, pos.z, heightFunctionUserData);
else
pos.y = 0;
Real _scale = minimumScale + (scale*(maximumScale - minimumScale));
addTree(ent, pos, Degree(Math::UnitRandom()*360), _scale);
}
}
}
geom->reloadGeometry();
}

void TreeLoader3D::addDensityMap(std::map<MapChannel, Ogre::Entity*> *entities, Ogre::String &mapFile, int trees /* = 4 */, Ogre::uint8 seed /* = 1 */)
{
if(seed == 0)
srand(0);
else if(seed == 1)
{
srand(time(NULL));
}
else
srand(seed);

PixelBox pb;
size_t height, width;
Real pxWidth, pxHeight;
TRect<Real> pxArea;
Ogre::Entity *ent;
// for each row
DensityMapChannelIterator d;
for (d = entities->begin(); d != entities->end(); ++d)
{
MapChannel channel = d->first;
ent = d->second;
densityMap = DensityMap::load(mapFile, channel);
densityMap->setMapBounds(actualBounds);
pb = densityMap->getPixelBox();
height = pb.getHeight();
width = pb.getWidth();
pxWidth = actualBounds.width() / width;
pxHeight = actualBounds.height() / height;

for(size_t h = 0; h < height; h++)
{
// for each pixel in row
for(size_t w = 0; w < width; w++)
{
// get actual location of pixel in rect
pxArea.left = w * pxWidth;
pxArea.right = pxArea.left + pxWidth;
pxArea.top = h * pxHeight;
pxArea.bottom = pxArea.top + pxHeight;
// get densitiy in the middle of the pixel and if it's zero, skip loop instance, no trees to see here
float scale = densityMap->getDensityAt(pxArea.left + (pxWidth/2), pxArea.top +(pxHeight/2));

if( scale == 0.0f)
continue;
for(int i = 0; i < trees; i++)
{
Vector3 pos;
pos.x = Math::RangeRandom(pxArea.left, pxArea.right);
pos.z = Math::RangeRandom(pxArea.top, pxArea.bottom);
if(heightFunction)
pos.y = heightFunction(pos.x, pos.z, heightFunctionUserData);
else
pos.y = 0;
Real _scale = minimumScale + (scale*(maximumScale - minimumScale));
addTree(ent, pos, Degree(Math::UnitRandom()*359), _scale);
}
}
}
}
geom->reloadGeometry();
}


I'm currently engaged in other things, but plan to use a pageloader instead, as JohnJ suggested.

NOTE: works wonky, since random clustering causes trees to cluster in pixel areas, but the general gist remains. The initial load is pretty heavy, taking 10s to load 20k~ trees on a 2x3.0ghz/4gb machine. It does to differnet models per channel though (r/g/b/a) :)

EDIT: Snipped extra code

Amenothep

06-05-2008 13:28:58

Hello khlumru,

thanks. :D


On Unix
under examples/source
the CMakeFile.txt
has missing:

add_executable(../bin/release/Example8 Example8.cpp)

target_link_libraries (../bin/release/Example8 PagedGeometry)

to get the new example 8 compiled