Help with getting the ogre terrain and bullet shape to work

Alessio89

13-04-2014 11:22:53

Hi! I'm fairly new to Ogre and Bullet. I managed to get through all the basic stuff: collision shapes, gravity and so on.
Now i wanted to get my objects to collide with a proper Ogre terrain instead of a basic plane.

I followed this: http://www.ogre3d.org/addonforums/viewtopic.php?f=12&t=14583. The code compile with no errors, but my objects don't collide with the terrain.
Not only that, but i get a really weird visual effect on the terrain: http://i61.tinypic.com/2dgnabl.png, http://i62.tinypic.com/nyd9tz.png
I get this weird effect even if i don't add the terrain shape to the bullet dynamics world.

I'm going crazy, I really want to get this to work, but I need help.
I wrapped the ogre terrain class into my own terrain class. It just wraps the basic tutorial 3 terrain into a class that's easier to call.

I don't use OgreBullet, but pure Bullet. I don't use terrain paging system (I'm still not sure what it is and how it's used). Object to object collisions work fine.

This is my Terrain wrapper class:
namespace BFL
{
Terrain::Terrain(Ogre::SceneManager* mSceneMgr, Ogre::Light* light)
{
this->mSceneMgr = mSceneMgr;
mTerrainGlobal = OGRE_NEW Ogre::TerrainGlobalOptions();
mTerrainGroup = OGRE_NEW Ogre::TerrainGroup(mSceneMgr, Ogre::Terrain::ALIGN_X_Z, 513, 12000.0f);
mTerrainGroup->setFilenameConvention(Ogre::String("terrain"), Ogre::String(".dat"));
mTerrainGroup->setOrigin(Ogre::Vector3::ZERO);

configureTerrainDefaults(light);

for (long x = 0; x <= 0; ++x)
for (long y = 0; y <= 0; ++y)
defineTerrain(x,y);

mTerrainGroup->loadAllTerrains(true);

if (mTerrainsImported)
{
Ogre::TerrainGroup::TerrainIterator ti = mTerrainGroup->getTerrainIterator();
while(ti.hasMoreElements())
{
Ogre::Terrain* t = ti.getNext()->instance;
initBlendMaps(t);
}
}

mTerrainGroup->freeTemporaryResources();
}

void Terrain::configureTerrainDefaults(Ogre::Light* light)
{
mTerrainGlobal->setMaxPixelError(0);
mTerrainGlobal->setCompositeMapDistance(3000);

mTerrainGlobal->setLightMapDirection(light->getDerivedDirection());
mTerrainGlobal->setCompositeMapAmbient(mSceneMgr->getAmbientLight());
mTerrainGlobal->setCompositeMapDiffuse(light->getDiffuseColour());
Ogre::Terrain::ImportData& defaultimp = mTerrainGroup->getDefaultImportSettings();
defaultimp.terrainSize = 513;
defaultimp.worldSize = 12000.0f;
defaultimp.inputScale = 600; // due terrain.png is 8 bpp
defaultimp.minBatchSize = 33;
defaultimp.maxBatchSize = 65;
defaultimp.layerList.resize(3);
defaultimp.layerList[0].worldSize = 100;
defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_diffusespecular.dds");
defaultimp.layerList[0].textureNames.push_back("dirt_grayrocky_normalheight.dds");
defaultimp.layerList[1].worldSize = 30;
defaultimp.layerList[1].textureNames.push_back("grass_green-01_diffusespecular.dds");
defaultimp.layerList[1].textureNames.push_back("grass_green-01_normalheight.dds");
defaultimp.layerList[2].worldSize = 200;
defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_diffusespecular.dds");
defaultimp.layerList[2].textureNames.push_back("growth_weirdfungus-03_normalheight.dds");

}

void Terrain::defineTerrain(long x, long y)
{
Ogre::String filename = mTerrainGroup->generateFilename(x, y);
if (Ogre::ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(), filename))
{
mTerrainGroup->defineTerrain(x, y);
}
else
{
Ogre::Image img;
getTerrainImage(x % 2 != 0, y % 2 != 0, img);
mTerrainGroup->defineTerrain(x, y, &img);
mTerrainsImported = true;
}

}
void Terrain::getTerrainImage(bool flipX, bool flipY, Ogre::Image& img)
{
img.load("terrain.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
if (flipX)
img.flipAroundY();
if (flipY)
img.flipAroundX();
}
void Terrain::initBlendMaps(Ogre::Terrain* terrain)
{
Ogre::TerrainLayerBlendMap* blendMap0 = terrain->getLayerBlendMap(1);
Ogre::TerrainLayerBlendMap* blendMap1 = terrain->getLayerBlendMap(2);
Ogre::Real minHeight0 = 70;
Ogre::Real fadeDist0 = 40;
Ogre::Real minHeight1 = 70;
Ogre::Real fadeDist1 = 15;
float* pBlend0 = blendMap0->getBlendPointer();
float* pBlend1 = blendMap1->getBlendPointer();
for (Ogre::uint16 y = 0; y < terrain->getLayerBlendMapSize(); ++y)
{
for (Ogre::uint16 x = 0; x < terrain->getLayerBlendMapSize(); ++x)
{
Ogre::Real tx, ty;

blendMap0->convertImageToTerrainSpace(x, y, &tx, &ty);
Ogre::Real height = terrain->getHeightAtTerrainPosition(tx, ty);
Ogre::Real val = (height - minHeight0) / fadeDist0;
val = Ogre::Math::Clamp(val, (Ogre::Real)0, (Ogre::Real)1);
*pBlend0++ = val;

val = (height - minHeight1) / fadeDist1;
val = Ogre::Math::Clamp(val, (Ogre::Real)0, (Ogre::Real)1);
*pBlend1++ = val;
}
}
blendMap0->dirty();
blendMap1->dirty();
blendMap0->update();
blendMap1->update();
}
}


And this is how I call the createTerrain in my physics class:

void Physics::createTerrain(BFL::Terrain* t)
{
Ogre::Terrain* pTerrain = t->mTerrainGroup->getTerrain(0,0);
int terrainPageSize = pTerrain->getSize(); // Number of vertices along x/z axe


// >>> We need to mirror the ogre-height-data along the z axis first!
// This is related to how Ogre and Bullet differ in heighmap storing
float *pTerrainHeightData = pTerrain->getHeightData();
float *pTerrainHeightDataConvert = new float[terrainPageSize * terrainPageSize];
for(int i = 0; i < terrainPageSize; ++i)
{
memcpy(pTerrainHeightDataConvert + terrainPageSize * i,
pTerrainHeightData + terrainPageSize * (terrainPageSize - i - 1),
sizeof(float)*(terrainPageSize));
}
// <<< End of conversion

btHeightfieldTerrainShape* pHeightShape
= new btHeightfieldTerrainShape(terrainPageSize,
terrainPageSize,
pTerrainHeightDataConvert,
1, /* Terrains getHeightData() is already scaled perfectly */
pTerrain->getMinHeight(),
pTerrain->getMaxHeight(),
1, /* upVector is Y positive in ogre-, bullet- and our world */
PHY_FLOAT,
true);

// Scale the mesh along x/z
float unitsBetweenVertices = pTerrain->getWorldSize() / (terrainPageSize - 1);
btVector3 scaling(unitsBetweenVertices, 1, unitsBetweenVertices);
pHeightShape->setLocalScaling(scaling);

// Ogre uses DiamonSubdivision for Terrain-mesh, so bullet should use it too
pHeightShape->setUseDiamondSubdivision(true);

// Now we create a btRigidBody
btRigidBody *pBody = new btRigidBody(0.0 /* mass 0.0 means static */,
new btDefaultMotionState(),
pHeightShape);

//
Ogre::Vector3 terrainPosition = pTerrain->getPosition();
pBody->getWorldTransform().setOrigin(btVector3(terrainPosition.x,
terrainPosition.y
+ (pTerrain->getMaxHeight() - pTerrain->getMinHeight()) / 2, // Bullet's position differs from Ogre's. Ogre's y is at the bottom, bullet needs the middle if the height to be positioned right
terrainPosition.z));

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

dynamicsWorld->addRigidBody(pBody);

// Advanced Body configuration ->
// You can play with these or just leave the defaults:
// pBody->setFriction(1.0);
// pBody->setRestitution(0.0);
// pBody->setHitFraction(0.0);
// pBody->setDamping(0.2, 0.2);

}


Basically a copy\paste of the thread I linked. I really need help because I'm unable to figure out this one myself. :(

Pbateman

23-04-2014 16:21:18

forget about btHeightfieldTerrainShape if u dont want i to fix it ;)

http://www.youtube.com/watch?v=zCJwxk08 ... e=youtu.be
https://github.com/bulletphysics/bullet3/issues/57

Pbateman

16-05-2014 20:43:40

good news! collision for static terrain seems to be fixed! :)

AlexeyKnyshev

16-05-2014 23:22:08

It would be great if you will provide more info about fix.
Best regards, Alexey Knyshev

Pbateman

17-05-2014 01:50:29

https://github.com/bulletphysics/bullet3/issues/57 ?


and that was the problem before the fix?:
https://www.youtube.com/watch?v=zCJwxk0 ... e=youtu.be

with moving terrain the cubes sometimes still fall through. but with static terrain i seems the problems are gone ...

erwin closed the issue. hehe. not so good because the moving terrain problem won't be addressed.