[PATCH] Heightfield collision

SFCBias

11-09-2010 20:45:26

I'm finding it a little difficult to build the library so i'm just going to submit this as a patch. As far as an example, I can try to create one but you would have to build it on your own.

This is the patch for the Heightfield collision need to change header and source..
Create this as you would any other collision but you don't need to create a body for it.Umm... notify me of any problems and that should be it.

OgreNewt_CollisionPrimitives.h
//! HeightField Collision
/*!
builds a HeightField collision from raw data or directly from a OgreTerrain page

more info: http://newtondynamics.com/wiki/index.php5?title=NewtonCreateHeightFieldCollision
*/
class _OgreNewtExport HeightField : public OgreNewt::Collision
{
public:
HeightField(const World* world, Ogre::Terrain *terrain, int shapeID);

~HeightField(){}

};


OgreNewt_CollisionPrimitives.cpp

HeightField::HeightField(const OgreNewt::World *world,
Ogre::Terrain *terrain, int shapeID) :
OgreNewt::Collision(world)
{

int width, height;
width = height = terrain->getSize() - 1;
int size = width * height;
float* array32 = new float[size];
char* attributes;

// find the min am max in the map
float min = terrain->getMinHeight();
float max = terrain->getMaxHeight();

// crate the new map
unsigned short* elevation = new unsigned short[size];
attributes = (char*) malloc(width * width * sizeof(char));
//float scale = max - min;
float scale = (fabs(max - min) > 1.0e-1f) ? 1.0 : 66535.0f / (max
- min);
// nwo populate the elavation map
Ogre::Real horizontalScale = (terrain->getWorldSize()
/ (terrain->getSize() - 2));

int x = 0;
for (int i = 0; i < width; i++)
{
for (int k = 0; k < height; k++)
{
array32[x] = terrain->getHeightAtPoint(i, k);
x++;
}
}

for (int i = 0; i < size; i++)
{
elevation[i] = (unsigned short) ((array32[i] - min) * scale);
}

float verticalScale = (1.0f / (scale));

m_col = NewtonCreateHeightFieldCollision(m_world->getNewtonWorld(),
width, height, 1, elevation, attributes, horizontalScale,
verticalScale, 2);

delete[] elevation;
delete[] array32;
free(attributes);

NewtonBody* body = NewtonCreateBody(m_world->getNewtonWorld(),
m_col);
// Ogre::SceneNode * sn = m_world->getRootSceneNode();



float matrix[16];
Ogre::Quaternion rot(Ogre::Degree(90), Ogre::Vector3(0, 1, 0));
rot = rot * Ogre::Quaternion::IDENTITY;

OgreNewt::Converters::QuatPosToMatrix(rot, Ogre::Vector3::ZERO,
&matrix[0]);

float mX = width / 2 * horizontalScale;
float mZ = height / 2 * horizontalScale;
matrix[12] -= mX;
matrix[13] += min;
matrix[14] += mZ;

NewtonBodySetMatrix(body, &matrix[0]);

// NewtonBodySetUserData(body, sn);


/* createRigidBody(WORLD,
collision, terrain);*/

// NewtonReleaseCollision(WORLD, collision);

}

kamaliang

28-09-2010 08:51:23

Hi, thanks for this great Patch !
But i met some problems below :
The OgreNewt::Body was not at the same position with the Ogre::Terrain, whether i added these code or not

Ogre::Vector3 tPosi = terrain->getPosition();
Ogre::Vector3 posi = tPosi - Ogre::Vector3(TERRAIN_WORLD_SIZE/2, 0, TERRAIN_WORLD_SIZE/2);
bod->setPositionOrientation( posi, Ogre::Quaternion::IDENTITY );


Please show some code of using this patch, thanks for your help so much ! :)

kamaliang

28-09-2010 08:59:04

And you can also see that the OgreNewt::Body did not express the hollows(holes) of the terrain accurately...The OgreNewt::Body risen in the hollows' position! :oops:

SFCBias

30-09-2010 01:29:49

I was afraid that would happen. If you can figure out how to get the rootSceneNode, then where it's commented out (//sn = m_world->getRootSceneNode()) sn needs to be the rootSceneNode. If you manage to get it then replace Ogre::Quaternion::IDENTITY with sn->getOrientation();

NewtonBody* body = NewtonCreateBody(m_world->getNewtonWorld(),
m_col);
Ogre::SceneNode * sn =GETROOTSCENENODESOMEHOW;



float matrix[16];
Ogre::Quaternion rot(Ogre::Degree(90), Ogre::Vector3(0, 1, 0));
rot = rot * sn->getOrientation();

Nodrev

30-09-2010 08:23:44

It's a common issue with this library: Newton set the bodies coordonates in global space terms, while the the get/setOrientation and get/setPosition of Ogre's scene node are relative to their parents. So, if your parent scene node is not the root (the point (0,0,0) ), and this parent node has been moved, then there will be a shift beetween Ogre and OgreNewt.
See http://www.ogre3d.org/addonforums/viewtopic.php?f=4&t=13400&start=0 for more informations

So, the simplest way to fix it, whenever your parent node is the root or not, is to use global positioning in your new OgreNewt function (use get/setDerivedPosition and orientation).

SFCBias

30-09-2010 20:02:02

Yes i know that problems but the real issue is making the class portable for any terrain. Also Newton uses the bottom right corner as the origin while Ogre uses the Center which is why it's offset .

Nodrev

30-09-2010 22:43:11

Also Newton uses the bottom right corner as the origin Ha, right, i knew that but i've completely missed that point.

kamaliang

05-10-2010 11:13:37

Thanks for all your warmly replies...
I did not check this before cause i was in holiday these days, and today i try to make it right, but i found the result was wrong too!
The OgreNewt body's position and orientation were wrong too,
I also tried :
Ogre::SceneNode * sn = GETROOTSCENENODESOMEHOW; --> Ogre::SceneNode * sn = terrain->_getRootSceneNode();
but the result was the same...
P.S: The terrain was created by Ogitor0.4.2.

SFCBias

05-10-2010 16:47:59

Wait, are you using the OgreNewt::Debugger ? If so, it doesn't accurately display the Terrain body because of some mods, to the code. SO Actually test the terrain collision or you can add the drawing code yourself(It's in OgreNewt_Debugger.cpp) or I will post it later when i Get home. But test the collision first.