1.7 terrain paging + Bullet [solved]

Problems building or running the engine, queries about how to use features etc.
fanlansen
Gnoblar
Posts: 18
Joined: Tue Jun 29, 2010 9:28 am

1.7 terrain paging + Bullet [solved]

Post by fanlansen »

I use PageProvider:prepareProceduralPage() to get terrain data ,and send data to bullet .
this:

Code: Select all

	Ogre::TerrainGroup * pGroup=((Ogre::TerrainPagedWorldSection *)section)->getTerrainGroup();
	long x,y;
	pGroup->unpackIndex(page->getID(), &x, &y);
	Ogre::Terrain * pTerrain=pGroup->getTerrain(x,y);
	float * data=pTerrain->getHeightData();
	Ogre::Vector3 tpos=pTerrain->getPosition(); 
	btVector3 pos(tpos.x,tpos.y,tpos.z);

	float * pDataConvert= new float[pTerrain->getSize() *pTerrain->getSize()];
	for (int i=0;i<pTerrain->getSize();i++)
		memcpy(pDataConvert+pTerrain->getSize()*i
		, pTerrain->getHeightData() + pTerrain->getSize()-i-1
		,sizeof(float)*pTerrain->getSize());

	pEngine->putTerrainData(
		pTerrain->getSize(),
		pTerrain->getSize(),
		pTerrain->getHeightData(),
		pTerrain->getMinHeight(),
		pTerrain->getMaxHeight(),
		pos,
		pTerrain->getWorldSize()/(pTerrain->getSize()-1) );

     delete []pDataConvert;
this:

Code: Select all

void BulletEngine::putTerrainData(float w,float h,float* data,float minH,float maxH,btVector3& pos,float scale)
{

	bool useFloatData=true;
	bool flipQuadEdges=false;
	int upIndex = 1;

	btHeightfieldTerrainShape* heightFieldShape = 
		new btHeightfieldTerrainShape(w,h,data,1,minH,maxH,upIndex,PHY_FLOAT,flipQuadEdges);
	groundShape = heightFieldShape;
	heightFieldShape->setUseDiamondSubdivision(true);
	heightFieldShape->setLocalScaling(btVector3(scale,1,scale));

	btTransform groundTransform;
	groundTransform.setIdentity();
	groundTransform.setOrigin(pos);

	collisionShapes.push_back(groundShape);

		//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
		btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
		btRigidBody* body = new btRigidBody(0.0, myMotionState,groundShape );
		body->setFriction(30);
		body->setHitFraction(30);
		body->setUserPointer(&bodyType[TERRAINTYPE]);
		
		//add the body to the dynamics world
		dynamicsWorld->addRigidBody(body);

}
The terrain in bullet ,can not collision correct .height in bullet is not consistent with in Ogre.
help!
Last edited by fanlansen on Thu Jul 01, 2010 11:41 am, edited 1 time in total.
User avatar
TheGameMaker
Kobold
Posts: 26
Joined: Fri Jun 18, 2010 4:19 pm

Re: 1.7 terrain paging + Bullet ,help!

Post by TheGameMaker »

I tried your code and I think I found 2 problems:

1. Bullet has a different terrain height system to Ogre so change this:
groundTransform.setOrigin(pos);
to this:
groundTransform.setOrigin(pos + btVector3(0, (maxH-minH)/2, 0));

2. I don't actually know how to solve the next problem but I know what it is. The bullet heightfield must be flipped along the z axis.

Maybe you can figure it out...
fanlansen
Gnoblar
Posts: 18
Joined: Tue Jun 29, 2010 9:28 am

Re: 1.7 terrain paging + Bullet ,help!

Post by fanlansen »

I have got it!
this:

Code: Select all

	float * pDataConvert= new float[pTerrain->getSize() *pTerrain->getSize()];
	for (int i=0;i<pTerrain->getSize();i++)
		memcpy(pDataConvert+pTerrain->getSize()*i
		, data + pTerrain->getSize()*(pTerrain->getSize()-i-1)
		,sizeof(float)*(pTerrain->getSize()) );


	pEngine->putTerrainData(
		pTerrain->getSize(),
		pTerrain->getSize(),
		pDataConvert,
		pTerrain->getMinHeight(),
		pTerrain->getMaxHeight(),
		pos,
		pTerrain->getWorldSize()/(pTerrain->getSize()-1) );
this:

Code: Select all

void BulletEngine::putTerrainData2(SceneNode* sceneNode, float w,float h,float* data,float minH,float maxH,Ogre::Vector3& pos,float scale,float heightScale)
{
	btVector3 localScaling(scale, heightScale, scale);

	groundShape = 
		new btHeightfieldTerrainShape(w, h, data, 1/*ingnore*/, minH,maxH,1, PHY_FLOAT, true);
	groundShape->setUseDiamondSubdivision(true);
	groundShape->setLocalScaling(localScaling);
	collisionShapes.push_back(groundShape);

	btDefaultMotionState* state = new btDefaultMotionState();
	btRigidBody* rigidBody = new btRigidBody(0, state, groundShape);
	rigidBody->getWorldTransform().setOrigin(btVector3(scale*(w-1)/2, heightScale/2 *heightScale,scale* (w-1)/2));
	Ogre::Quaternion q=Ogre::Quaternion::IDENTITY;
	rigidBody->getWorldTransform().setRotation(btQuaternion(q.x, q.y, q.z, q.w) );
	rigidBody->setCollisionFlags(rigidBody->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);
	dynamicsWorld->addRigidBody(rigidBody);
}
run good,but not exactly.
User avatar
Xypher
Gremlin
Posts: 180
Joined: Tue Jun 29, 2004 1:35 am
Location: Richmond, IN; USA

Re: 1.7 terrain paging + Bullet [solved]

Post by Xypher »

I know its not a huge optimization, and it may not even be pertinent any more, however...
Last time I ran profile on division vs multiplication (using divide by 2) multiplication was marginally faster.
This was a couple of years ago with GCC 3.2.x I believe, so i've avoided divisions as much as possible, opting to multiply by a decimal instead.
Ubuntu Studio 13.04 64-bit
GCC 4.8.1
Ogre3D 1.8.1
AMD Athlon FX 8120 @4Ghz
16Gb G.Skill Ripjaws (PC3-12800)
EVGA GeForce 560 Ti FTW

http://www.hellbatgames.com
kernelpanic
Gnoblar
Posts: 16
Joined: Thu Jan 21, 2010 11:43 am

Re: 1.7 terrain paging + Bullet [solved]

Post by kernelpanic »

Fanlansen, thank you very much for your code! I changed it a bit and made it work for me - here's what I have:

Code: Select all

     float* terrainHeightData = pTerrain->getHeightData();
     Ogre::Vector3 terrainPosition = pTerrain->getPosition();

     float * pDataConvert= new float[pTerrain->getSize() *pTerrain->getSize()];
     for(int i=0;i<pTerrain->getSize();i++)
        memcpy(
                    pDataConvert+pTerrain->getSize() * i, // source
                    terrainHeightData + pTerrain->getSize() * (pTerrain->getSize()-i-1), // target
                    sizeof(float)*(pTerrain->getSize()) // size
                    );

     float metersBetweenVertices = pTerrain->getWorldSize()/(pTerrain->getSize()-1); //edit: fixed 0 -> 1 on 2010-08-13
     btVector3 localScaling(metersBetweenVertices, 1, metersBetweenVertices);

     btHeightfieldTerrainShape* groundShape = new btHeightfieldTerrainShape(
                 pTerrain->getSize(),
                 pTerrain->getSize(),
                 pDataConvert,
                 1/*ignore*/,
                 pTerrain->getMinHeight(),
                 pTerrain->getMaxHeight(),
                 1,
                 PHY_FLOAT,
                 true);

     groundShape->setUseDiamondSubdivision(true);
     groundShape->setLocalScaling(localScaling);

     mGroundBody = new btRigidBody(0, new btDefaultMotionState(), groundShape);

     mGroundBody->getWorldTransform().setOrigin(
                 btVector3(
                     terrainPosition.x,
                     terrainPosition.y + (pTerrain->getMaxHeight()-pTerrain->getMinHeight())/2,
                     terrainPosition.z));

     mGroundBody->getWorldTransform().setRotation(
                 btQuaternion(
                     Ogre::Quaternion::IDENTITY.x,
                     Ogre::Quaternion::IDENTITY.y,
                     Ogre::Quaternion::IDENTITY.z,
                     Ogre::Quaternion::IDENTITY.w));

     mBtWorld->addRigidBody(mGroundBody);
As you mention, the problem is that the bullet shape only approximates the terrain (see screenshot), so it gets messy when you have small objects colliding with the terrain.

Does anyone know why this is? I haven't quite understood why there's a need for skirts in the new terrain, but my fear is that Ogre's terrain doesn't quite stick to the heighmap it is based on (and thus needs skirts at the edges), while the bullet btHeightfieldTerrainShape does. Neither does diamondSubdivision help...
You do not have the required permissions to view the files attached to this post.
Last edited by kernelpanic on Fri Aug 13, 2010 12:59 pm, edited 1 time in total.
reptor
Ogre Magi
Posts: 1120
Joined: Wed Nov 15, 2006 7:41 pm
Location: Finland
x 5

Re: 1.7 terrain paging + Bullet [solved]

Post by reptor »

kernelpanic wrote:my fear is that Ogre's terrain doesn't quite stick to the heighmap it is based on
That's what I have understood to be the case. I recall that it tries to make the terrain appear smoother - and as a natural consequence of that it doesn't match up with the original data any more. And the physics engines use the height field as is and then you have a mismatch between graphics and physics.

But I would imagine Ogre3D would have a setting to control that? I think it would have to be possible to tell Ogre3D not to smooth it at all. I recall this has been discussed but it's a long time ago and I don't remember the details.
kernelpanic
Gnoblar
Posts: 16
Joined: Thu Jan 21, 2010 11:43 am

Re: 1.7 terrain paging + Bullet [solved]

Post by kernelpanic »

The problem can be alleviated by calling

Code: Select all

mTerrainGlobals->setMaxPixelError(0);
but its still not fixed, just better.
User avatar
Jabberwocky
OGRE Moderator
OGRE Moderator
Posts: 2819
Joined: Mon Mar 05, 2007 11:17 pm
Location: Canada
x 220

Re: 1.7 terrain paging + Bullet [solved]

Post by Jabberwocky »

reptor wrote:
kernelpanic wrote:my fear is that Ogre's terrain doesn't quite stick to the heighmap it is based on
That's what I have understood to be the case. I recall that it tries to make the terrain appear smoother
That's not quite right. Ogre does stick exactly to the heightmap, except for distant terrain.

There's two things going on here.

1. Max Pixel Error: Distant Terrain Optimization
As you've already identified, Ogre simplifies the terrain mesh for distant terrain, based on the "max pixel error" setting. This is a common optimization you'll find in any good terrain renderer, since drawing the precise details of very distant terrain is both expensive and unnecessary. Usually you'll want to keep this optimization on by having some max pixel error value > 0.

2. Terrain Tesselation
The other thing that appears to be going on is a mismatch in how Ogre tesselates the heightfield, verses how your physics engine is tesselating the heightfield. If you look at your screenshot, all the square quads are subdivided into triangles in the exact same way. This isn't how the new Ogre terrain component does it. Ogre tesselates every second row in an opposite direction.

Image

Look carefully at the difference between this image and your physics mesh. When the tesselation doesn't match, the physics will be off.

This is a bit of a pain in the ass. I use PhysX, and I had to switch from their specialized NxHeightfield class to their generic NxTriangleMesh class so that I could mimic the tesselation of the terrain in the physics.

Here's a comment from ogreterrain.cpp:

Code: Select all

		/* For even / odd tri strip rows, triangles are this shape:
		even     odd
		3---2   3---2
		| / |   | \ |
		0---1   0---1
and

Code: Select all

		/* For even / odd tri strip rows, triangles are this shape:
		6---7---8
		| \ | \ |
		3---4---5
		| / | / |
		0---1---2
		Note how vertex rows count upwards. In order to match up the anti-clockwise
		winding and this upward transitioning list, we need to start from the
		right hand side. So we get (2,5,1,4,0,3) etc on even lines (right-left)
		and (3,6,4,7,5,8) etc on odd lines (left-right). At the turn, we emit the end index 
		twice, this forms a degenerate triangle, which lets us turn without any artefacts. 
		So the full list in this simple case is (2,5,1,4,0,3,3,6,4,7,5,8)
I believe the reason for this odd tesselation is because it allows the terrain to be rendered using RenderOperation::OT_TRIANGLE_STRIP, which uses less data than the usual OT_TRIANGLE_LIST. Compare the comments between the two below:

From ogrerenderoperation.h

Code: Select all

		enum OperationType {
			/// A list of points, 1 vertex per point
            OT_POINT_LIST = 1,
			/// A list of lines, 2 vertices per line
            OT_LINE_LIST = 2,
			/// A strip of connected lines, 1 vertex per line plus 1 start vertex
            OT_LINE_STRIP = 3,
			/// A list of triangles, 3 vertices per triangle
            OT_TRIANGLE_LIST = 4,
			/// A strip of triangles, 3 vertices for the first triangle, and 1 per triangle after that 
            OT_TRIANGLE_STRIP = 5,
			/// A fan of triangles, 3 vertices for the first triangle, and 1 per triangle after that
            OT_TRIANGLE_FAN = 6
        };
So bottom line, you need to get your physics tesselation to match Ogre's. I'm not familiar with Bullet, but you might want to look more into the "diamondSubdivision" functionality which was mentioned earlier.
Image
kernelpanic
Gnoblar
Posts: 16
Joined: Thu Jan 21, 2010 11:43 am

Re: 1.7 terrain paging + Bullet [solved]

Post by kernelpanic »

Jabberwocky wrote: 2. Terrain Tesselation
The other thing that appears to be going on is a mismatch in how Ogre tesselates the heightfield, verses how your physics engine is tesselating the heightfield. If you look at your screenshot, all the square quads are subdivided into triangles in the exact same way. This isn't how the new Ogre terrain component does it. Ogre tesselates every second row in an opposite direction.
Jabberwocky, thank you for this great answer!

If you're saying that maxPixelError only affects distant terrain, this means the terrain will change when I move the camera, so this is a LOD implementation, right? Does it mean maxPixelError is always 0 close to the camera (whatever value "close" is...)?
terrainproblem.jpg
What you said about the different tesselations does (in my head) not quite match the fact that in my screenshot above (maxPixelError is 0), you can not see single vertices being off, but whole groups of neighboring vertices (e.g. around 10x10 patches). If there was a problem with the way things were tesselated, wouldn't that mean that only single vertices should be off, not whole clusters?

In any case, you wouldn't know how to patch http://www.bulletphysics.com/Bullet/Bul ... tml#l00360 to match the terrains tesselation? *g*
You do not have the required permissions to view the files attached to this post.
User avatar
Jabberwocky
OGRE Moderator
OGRE Moderator
Posts: 2819
Joined: Mon Mar 05, 2007 11:17 pm
Location: Canada
x 220

Re: 1.7 terrain paging + Bullet [solved]

Post by Jabberwocky »

kernelpanic wrote: If you're saying that maxPixelError only affects distant terrain, this means the terrain will change when I move the camera, so this is a LOD implementation, right? Does it mean maxPixelError is always 0 close to the camera (whatever value "close" is...)?
I haven't studied the code for maxPixelError. But it is the metric used to decide whether to eliminate verticies from the terrain mesh. Since a distant terrain quad is much smaller on-screen than a terrain quad near the camera, it is much more likely to fall within the maxPixelError threshold, and be simplified to a lower density mesh, to optimize the graphic load of drawing the terrain.

If you crank up the maxPixelError, then look at your terrain in wireframe mode, you'll see that distant terrain uses less verticies, as adjacent verticies are merged together into larger quads.
kernelpanic wrote: you can not see single vertices being off, but whole groups of neighboring vertices (e.g. around 10x10 patches). If there was a problem with the way things were tesselated, wouldn't that mean that only single vertices should be off, not whole clusters?
While tesselation is definitely a problem, you're right. There may be something else too. There's a number of other things which could have gone wrong, such as:
  • feeding in an incorrect value for the world size of the terrain to your physics engine.
  • feeding in an incorrect value for the number of verticies across the terrain to your physics engine. e.g. 2^n vs. 2^n+1
Some things to try:
  • if you switch between a wireframe of your graphical terrain and your physics terrain and look from above, do the verticies match up? Look at both edges of the terrain.
  • pick the positions of several verticies across the terrain. Write some code to compare the height at these points in physics vs. graphics. For the graphics terrain use Terrain::getHeightAtWorldPosition(..). Bullet must have some kind of similar function. If the values aren't the same, then somehow you must be feeding different data into your physics vs. graphics components.
kernelpanic wrote: In any case, you wouldn't know how to patch http://www.bulletphysics.com/Bullet/Bul ... tml#l00360 to match the terrains tesselation? *g*
Nope, I'm a little too busy to patch physics code for a physics engine I don't use. ;)
Image
reptor
Ogre Magi
Posts: 1120
Joined: Wed Nov 15, 2006 7:41 pm
Location: Finland
x 5

Re: 1.7 terrain paging + Bullet [solved]

Post by reptor »

I remember sinbad said so :)

Of course maybe I remember wrong!
kernelpanic
Gnoblar
Posts: 16
Joined: Thu Jan 21, 2010 11:43 am

Re: 1.7 terrain paging + Bullet [solved]

Post by kernelpanic »

reptor wrote:I remember sinbad said so :)
Reptor, what exactly are you talking about? The different ways of tesselation between ogre and bullet?

Jabberwocky, I'm really sorry, I think you are right and only the tesselation is the problem. While trying to fix things, I forgot to change

Code: Select all

float metersBetweenVertices = pTerrain->getWorldSize()/(pTerrain->getSize()-0);
back to

Code: Select all

float metersBetweenVertices = pTerrain->getWorldSize()/(pTerrain->getSize()-1);
so my bullet-shape was a little smaller, thus causing whole clusters being off. D'oh.

It looks much better now:
terrain.jpg
I'll try to compare heights for those nasty single vertices and report back.
You do not have the required permissions to view the files attached to this post.
kernelpanic
Gnoblar
Posts: 16
Joined: Thu Jan 21, 2010 11:43 am

Re: 1.7 terrain paging + Bullet [solved]

Post by kernelpanic »

Wireframe mode was a great idea! I can see that all vertices x/z-parts match up.

Using MaxPixelError 0 shows that the bullet shapes vertices (white) differ in being both higher, lower and equal to ogres mesh (green):
terrainmpe0.jpg
But then, using MaxPixelError != 0 shows ogre's optimzations:
terrainmpe8.jpg
So as soon as MaxPixelError != 0, there's *probably* bigger problems than just the tesselation. Being a graphics-newbie, I currently don't fel up to the task of patching btHeightfieldTerrainShape to include a TesselationMode::Ogre, so I'll leave it at that for now.

Thank you!
You do not have the required permissions to view the files attached to this post.
User avatar
AntonTheManton
Greenskin
Posts: 100
Joined: Sun Jan 14, 2007 1:47 am

Re: 1.7 terrain paging + Bullet [solved]

Post by AntonTheManton »

Why can't you just use a raycast method and manually create the collision points as you move over the terrain? Generating a massive physics-based mesh to match the terrain seems like too much work.
monah
Gnoblar
Posts: 15
Joined: Tue May 05, 2009 9:09 pm

Re: 1.7 terrain paging + Bullet [solved]

Post by monah »

I have some problems with the use of bullet and 1.7 terrain. After the creation of shapes everything works, but when the Character is on the border Tile it falls under the ground. How do I fix it?
User avatar
NoxWings
Gnoblar
Posts: 9
Joined: Sun Jun 06, 2010 8:57 pm

Re: 1.7 terrain paging + Bullet [solved]

Post by NoxWings »

Another option would be to get the pages/tiles of the terrain and conform the bullet mesh with each tile renderable.
yamashi
Halfling
Posts: 40
Joined: Sat Jan 23, 2010 11:27 pm
x 2

Re: 1.7 terrain paging + Bullet [solved]

Post by yamashi »

For those interested, to solve this issue modify line 341 in btHeightFieldTerrainShape.cpp :

Code: Select all

if (m_flipQuadEdges || (m_useDiamondSubdivision && !((j+x) & 1)))
into

Code: Select all

if (j+1 & 1 || m_flipQuadEdges || (m_useDiamondSubdivision && !((j+x) & 1)))
That's how I solved it.
lockie
Gnoblar
Posts: 2
Joined: Sat Mar 05, 2011 7:32 pm

Re: 1.7 terrain paging + Bullet [solved]

Post by lockie »

yamashi, just simple

Code: Select all

if (m_flipQuadEdges || (m_useDiamondSubdivision && !(j & 1))) // i.e. removing "+x"
did the trick for me.
underworldguardian
Gnoblar
Posts: 12
Joined: Thu Nov 13, 2014 3:08 pm

Re: 1.7 terrain paging + Bullet [solved]

Post by underworldguardian »

Hello guys!

Sorry to dig up a pretty old thread but I am really stuck with having a properly paging terrain with orge and bullet. I wanted to use the ogre endless world sample with the perlin noise generator and make this work with bullet. First of all, do you keep all the terrain in one bullet mesh? It would be really helpful if somebody could give me a working code example of a paging ogre terrain with bullet physics integration. I think some of you here only would have to provide the whole code that the snippets come from.