TerrainSceneManager, OgreNewt, and TreeCollisionSceneParser

subquantum

18-12-2007 04:42:00

Hi. I'm switching from OgreOde to OgreNewt, as I'm familiar with Newton (and ODE has been giving me more headaches than I'd care to mention). I have everything in my game working fine with the new code except the collision geometry of the landscape. I'm using the normal ST_EXTERIOR_CLOSE TerrainSceneManager, and I've looked at nearly every relevant post on this forum with no luck discovering a proper way to turn the loaded terrain into a collision mesh.

At the moment, I'm attempting to get the root scene node of the terrain, and pass that into the TreeCollisionSceneParser. From what I've read, this should find the polygons making up the lowest LOD, and build geometry. Well, my rigid bodies are falling right through it. (They're colliding with eachother, so I'm pretty certain this is the problem.)


//pman is my class that holds my physics stuff, gman holds ogre stuff
OgreNewt::CollisionPrimitives::TreeCollisionSceneParser* terrainParser = new OgreNewt::CollisionPrimitives::TreeCollisionSceneParser(pman->world);

Ogre::SceneNode* t = (reinterpret_cast<Ogre::TerrainSceneManager*>(gman->sceneMgr))->getTerrainRootNode();

// This should find the terrain polys and build geometry, no?
terrainParser->parseScene( t , false );

// This creates the body for my terrain
pman->terrainBody = new OgreNewt::Body(pman->world, terrainParser);

// attach it to the terrain scene node
pman->terrainBody->attachToNode(t);


I assume there's something I'm doing wrong here?

albino

18-12-2007 09:45:45

good way to check whats wrong is to
add basic newton framelistener
and then press F3 when runnning game to see the collision
shapes etc so you see if its even creating a thing

maybe this helps:
http://www.ogre3d.org/wiki/index.php/Using_PLSM2_with_Newton

subquantum

18-12-2007 17:15:52

I enabled the debug lines, and as you can see, they are being created for the character and the little laser gun things, but not the level geometry. (The objects just fall through it and wind up landing on the floor I made, about 100 units down.)

I'd be happy to write some more wiki articles and tutorials and the like for OgreNewt, if I can just get this terrain collision working. It seems like there was a lot of talk about it a while ago, but there's no consise how-to for the TSM like there is for the PLSM.

Edit: The PLSM tutorial uses the PagingLandscapeEvent to get hooks to all the vertecies and indicies, which it then gives to Newton. If there's a way to get this data from the TSM, without using the TreeParser on the root scene node, I can't find it in the API.

subquantum

21-12-2007 00:43:31

I solved the problem, after much searching and trying and screaming, using the page callback thing and serializing the 30 mb collision mesh it generated. If anyone wants me to post my code with explanations, I'd be glad to.

albino

21-12-2007 07:45:50

I would love to see the solution I had the same problem, I still have it but i am currently working on another project. (postponed it because of this problem)

trilobite

09-01-2008 16:06:29

subquantum:
Yes, I am very interested. Please post your solution.

dudeabot

09-01-2008 18:01:28

i havent testted yet but if you use PLSM2 you can give a try:

http://www.ogre3d.org/wiki/index.php/Us ... ith_Newton

and im waiting for subquantum as well =)

dudeabot

13-01-2008 14:31:51

i managed to get the terrani collision with TSM working as well as the PLSM2

the conclusion i came is, that serializing 30 MB of data and loading it up at once isnt very good (FPS issues), this happens with the TSM


, so i should go with the PLSM2, which is very faster, and you can choose LOD(not sure how to do this with TSM)

PS:all the code i got from forums, just did some modifications here and there to make it more simple to follow

heres the code for TSM for exporting:

add this line to your constructor


Ogre::TerrainPageSourceListenerManager::getSingleton().addListener(this);


yuo should have a function like this on your class:


void Level7::pageConstructed
(Ogre::TerrainSceneManager* manager, size_t pagex, size_t pagez, Real* heightData) /*= 0*/
{
class TerrainVectorCalculator
{
public:
size_t pagex_;
size_t pagez_;
int pageSize_;
Vector3 scale_;
Real* heightData_;

Vector3 v(int x, int z)
{
return scale_ * Vector3(
pagex_ * pageSize_ + x,
heightData_[pageSize_ * z + x],
pagez_ * pageSize_ + z
);
}
};

TerrainVectorCalculator terrainCalc;
terrainCalc.pagex_ = pagex;
terrainCalc.pagez_ = pagez;
terrainCalc.pageSize_ = manager->getPageSize();
terrainCalc.scale_ = manager->getScale();
terrainCalc.heightData_ = heightData;

OgreNewt::CollisionPrimitives::TreeCollision* terrainCollision=new OgreNewt::CollisionPrimitives::TreeCollision(mWorld);
terrainCollision->start();

int polyId = 0;
for (int z = 0; z < manager->getPageSize()-1; z++)
{
for (int x = 0; x < manager->getPageSize()-1; x++)
{
Vector3 va[3];

va[0] = terrainCalc.v(x , z );
va[1] = terrainCalc.v(x , z+1);
va[2] = terrainCalc.v(x+1, z );
terrainCollision->addPoly(va, polyId++);

va[0] = terrainCalc.v(x+1, z );
va[1] = terrainCalc.v(x , z+1);
va[2] = terrainCalc.v(x+1, z+1);
terrainCollision->addPoly(va, polyId++);
}
}

const bool optimize = false;
terrainCollision->finish(optimize);

OgreNewt::TreeCollisionSerializer* serializer=new OgreNewt::TreeCollisionSerializer();
serializer->exportTreeCollision(terrainCollision,"..\\coldata\\level3.col");

}



you can change coldata to any folder you want, as well as the format (i use .col here)

warning: this can take several minutes depending on your CPU

once its exported (the file should have been created), you can now remove the listener and import the level straight

i do this in the end of the constructor:


OgreNewt::CollisionPrimitives::TreeCollision* collision=new OgreNewt::CollisionPrimitives::TreeCollision(mWorld);
DataStreamPtr ptr = ResourceGroupManager::getSingleton().openResource("level3.col","col");
OgreNewt::TreeCollisionSerializer* serializer=new OgreNewt::TreeCollisionSerializer();
serializer->importTreeCollision(ptr,collision);
ptr.getPointer()->close();
new OgreNewt::Body(mWorld, collision);



make sure coldata folder is on the resources.cfg, or else Ogre will have no idea what you talking about

the problem is, i get 10 ~ 20 FPS with TSM, bc of the collision

next one is for PLSM2

dudeabot

13-01-2008 14:40:54

now lets move to PLSM2

make sure you have this functions on your class, im using the same folder as the last example


void Level4::tileLoaded(PagingLandscapeEvent* event)
{

//recover PLSM2's tile object
int pageX=event->mPagex;
int pageZ=event->mPagez;
unsigned int tileX=event->mTilex;
unsigned int tileZ=event->mTilez;



//ask reference to geometry to PLSM2
std::vector<void*> params;
int renderLevel=0;
params.push_back(&pageX);
params.push_back(&pageZ);
params.push_back(&tileX);
params.push_back(&tileZ);
params.push_back(&renderLevel);
mSceneMgr->getOption("PageGetTileVertexData_2",&params);

//recover data at the end of the vector and send it to our physics class for the next step
int* numVtx=((int*)params[5]);
Vector3* vertices=((Vector3*)params[6]);
IndexData* indexData=((IndexData*)params[7]);

String TileName = "page"+StringConverter::toString(pageX) +"-" + StringConverter::toString(pageZ) +"-tile"+StringConverter::toString(tileX)+"-"+StringConverter::toString(tileZ);

SceneNode *sn;
sn = mSceneMgr->getRootSceneNode()->createChildSceneNode (TileName);
sn->setPosition(event->mBbox.getCenter());

loadTerrainGeometry(sn,vertices,*numVtx,indexData, TileName);

//cleanup
delete[] vertices;
delete numVtx;

}

void Level4::tileUnloaded(PagingLandscapeEvent* event){
//recover PLSM2's tile object
int pageX=event->mPagex;
int pageZ=event->mPagez;
int tileX=event->mTilex;
int tileZ=event->mTilez;

String TileName = "page"+StringConverter::toString(pageX) +"-" + StringConverter::toString(pageZ) +"-tile"+StringConverter::toString(tileX)+"-"+StringConverter::toString(tileZ);

mSceneMgr->getRootSceneNode()->removeAndDestroyChild (TileName);
UnloadTerrainGeometry (TileName);



}

void Level4::loadTerrainGeometry(Ogre::SceneNode * tileNode, Ogre::Vector3* vertices, int numVertices, Ogre::IndexData* indexData, String TileName)
{
if(tilesBodies[TileName]==NULL)
{

OgreNewt::TreeCollisionSerializer* serializer=new OgreNewt::TreeCollisionSerializer();
OgreNewt::CollisionPrimitives::TreeCollision* collision;

if(!ResourceGroupManager::getSingleton().resourceExists("col",TileName + ".col"))
{
collision = new OgreNewt::CollisionPrimitives::TreeCollision(mWorld,numVertices,vertices,indexData,false);
serializer->exportTreeCollision(collision,"..\\coldata\\" + TileName + ".col");
}
else
{
collision=new OgreNewt::CollisionPrimitives::TreeCollision(mWorld);
DataStreamPtr ptr = ResourceGroupManager::getSingleton().openResource(TileName + ".col","col");
serializer->importTreeCollision(ptr,collision);
ptr.getPointer()->close();
}

OgreNewt::Body* body = new OgreNewt::Body(mWorld,collision);
body->attachToNode(tileNode);

tilesBodies[TileName]=body;

delete collision;
}

}

void Level4::UnloadTerrainGeometry(String TileName) {
OgreNewt::Body *body = tilesBodies[TileName];
delete body;
tilesBodies[TileName]=NULL;
}


this is what you have to put on your constructor:


loadTileDelegate=new PagingLandscapeDelegate();
loadTileDelegate->bind(this,&Level4::tileLoaded);
mSceneMgr->setOption("addLoadTileListener",loadTileDelegate);


unloadTileDelegate=new PagingLandscapeDelegate();
unloadTileDelegate->bind(this,&Level4::tileUnloaded);
mSceneMgr->setOption("addUnloadTileListener",unloadTileDelegate);


and in your destructor:


mSceneMgr->setOption("removeLoadTileListener",loadTileDelegate);
mSceneMgr->setOption("removeUnloadTileListener",unloadTileDelegate);

if (loadTileDelegate)
delete loadTileDelegate;

tilesBodies.clear();


this is the properties you should declare:


//PLSM2
PagingLandscapeDelegate* loadTileDelegate;
PagingLandscapeDelegate* unloadTileDelegate;
PagingLandScapePageManager* mPageMgr;


this is how you call the method (pretty much as the TSM):


mSceneMgr = mRoot->createSceneManager("PagingLandScapeSceneManager", "MyScene");


mSceneMgr->setWorldGeometry("TsmTerrain.cfg");


i usually call it in the beggining of the constructor

you will need this includes:


//PLSM2
#include "OgrePagingLandScapeOptions.h"
#include "OgrePagingLandScapeCamera.h"
#include "OgrePagingLandScapeData2DManager.h"
#include "OgrePagingLandScapeRenderableManager.h"
#include "OgrePagingLandScapeTextureCoordinatesManager.h"
#include "OgrePagingLandScapeRenderable.h"
#include "OgrePagingLandScapeTextureManager.h"
#include "OgrePagingLandScapeTexture.h"
#include "OgrePagingLandScapePageManager.h"
#include "OgrePagingLandScapeTile.h"
#include "OgrePagingLandScapeTileInfo.h"
#include "OgrePagingLandScapeTileManager.h"
#include "OgrePagingLandScapeRenderable.h"
#include "OgrePagingLandScapeRenderableManager.h"
#include "OgrePagingLandScapeRaySceneQuery.h"
#include "OgrePagingLandScapeCamera.h"

#include "OgrePagingLandScapeListenerManager.h"

#include "OgrePagingLandScapeSceneManager.h"

#include "OgrePagingLandScapeHorizon.h"