terra+bullet
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
terra+bullet
I am working to get terra aligned with a bullet heightmap. I am having some problems. Does terra do anything special with it's triangles in the shaders? Seems like triangle edges aren't correct and iIve tried the various bullet options to no avail, which makes me think it could be terra specific?
-
- OGRE Team Member
- Posts: 5505
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1372
Re: terra+bullet
I use this code which matches 99.99% Bullet Terrain with Terra:
Change the "#if 1" to "#if 1" to perform the test. You can also change the location of vRayOrigin to test another or multiple points.
Let me know if you have trouble integrating it.
Cheers
Matias
Code: Select all
m_physicsSystem.setHeightMap(
terra->getHeightMap(), terra->getWidth(), terra->getDepth(),
terra->getXZRelativeSize(), terra->getHeight(), terra->getTerrainXZCenter(),
terra->getTerrainOrigin().y );
btHeightfieldTerrainShape *m_terrainShape;
btRigidBody * m_terrainBody;
/** See https://pybullet.org/Bullet/phpBB3/viewtopic.php?f=9&t=10224
"btHeightfieldTerrainShape : item collides but falls through"
This callback aims at helping prevent objects from falling through the terrain.
However it is not enough as veeeeeery fast objects (or if the heightmap moves/rotates
which we do) this callback is not enough
*/
static bool CustomMaterialCombinerCallbackForHeightmapFix(
btManifoldPoint &cp, //
const btCollisionObjectWrapper *colObj0Wrap, //
int partId0, //
int index0, //
const btCollisionObjectWrapper *colObj1Wrap, //
int partId1, //
int index1 )
{
// one-sided triangles
if( colObj1Wrap->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE )
{
const btTriangleShape *triShape =
static_cast<const btTriangleShape *>( colObj1Wrap->getCollisionShape() );
const btVector3 *v = triShape->m_vertices1;
btVector3 faceNormalLs = btCross( v[1] - v[0], v[2] - v[0] );
faceNormalLs.normalize();
btVector3 faceNormalWs = colObj1Wrap->getWorldTransform().getBasis() * faceNormalLs;
float nDotF = btDot( faceNormalWs, cp.m_normalWorldOnB );
if( nDotF <= 0.0f )
{
// flip the contact normal to be aligned with the face normal
cp.m_normalWorldOnB += -2.0f * nDotF * faceNormalWs;
}
}
// this return value is currently ignored, but to be on the safe side: return false if you don't
// calculate friction
return false;
}
void PhysicsSystem::setHeightMap( const std::vector<float> &heightMap, uint32_t width,
uint32_t depth, const Ogre::Vector2 &xzRelativeSize,
float maxHeight, const Ogre::Vector2 &terrainCenterXZ,
float yOrigin )
{
destroyTerrain();
m_terrainShape = new btHeightfieldTerrainShape( (int)width, (int)depth, &heightMap[0], 1.0f,
0.0f, maxHeight, 1, PHY_FLOAT, true );
btVector3 localScaling( xzRelativeSize.x, 1.0f, xzRelativeSize.y );
m_terrainShape->setLocalScaling( localScaling );
btVector3 localInertia( 0, 0, 0 );
btRigidBody::btRigidBodyConstructionInfo rbInfo( 0, 0, m_terrainShape, localInertia );
m_terrainBody = new btRigidBody( rbInfo );
btTransform transf;
transf.setIdentity();
transf.setOrigin( ogreToBullet( Ogre::Vector3( terrainCenterXZ.x - xzRelativeSize.x * 0.5f,
maxHeight / 2.0f + yOrigin,
terrainCenterXZ.y - xzRelativeSize.y * 0.5f ) ) );
m_terrainBody->setWorldTransform( transf );
m_terrainBody->setFriction( 1.0f );
m_terrainBody->setRollingFriction( 1.0f );
m_terrainBody->setCollisionFlags( btCollisionObject::CF_STATIC_OBJECT |
btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK );
const CollisionFilterPair colFilter = CollisionFilterSystem::getCollisionFilterPair( CFTerrain );
m_world->addRigidBody( m_terrainBody, static_cast<int>( colFilter.group ),
static_cast<int>( colFilter.mask ) );
#if 0
// Test code for checking physics matches graphics
{
Ogre::Vector3 vRayOrigin( 5, maxHeight + yOrigin + 100.0f, 5 );
Ogre::Vector3 vRayDst( vRayOrigin );
vRayDst.y = -vRayOrigin.y;
btCollisionWorld::ClosestRayResultCallback closestResults( ogreToBullet( vRayOrigin ),
ogreToBullet( vRayDst ) );
m_world->rayTest( closestResults.m_rayFromWorld, closestResults.m_rayToWorld,
closestResults );
float posY = logicSystem.getHeightAtSimple( vRayOrigin );
if( closestResults.hasHit() )
{
float bulletY = closestResults.m_hitPointWorld.getY();
assert( fabs( posY - bulletY ) < 1e-4f );
}
}
#endif
}
Let me know if you have trouble integrating it.
Cheers
Matias
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: terra+bullet
I have implemented your code, however, I am having difficulty getting the origin correct, I think. If i just want origin to be center of the terrain, what do I send to terra and the physics?
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: terra+bullet
also, what is your, terra->getTerrainXZCenter(), function?
-
- OGRE Team Member
- Posts: 5505
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1372
Re: terra+bullet
Code: Select all
//-----------------------------------------------------------------------------------
Vector2 Terra::getTerrainXZCenter(void) const
{
return Vector2( m_terrainOrigin.x + m_xzDimensions.x * 0.5f,
m_terrainOrigin.z + m_xzDimensions.y * 0.5f );
}
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: terra+bullet
OK, I don't know how on earth you got that code to work with bullet,or if it still works for you or not, but it is not at all how it turned out for me. I got bullet to align however, and here's the code folks.
This works with centering everything about origin
Thanks for the help though, your idea to move the physics to match terra is a good one. I also implemented the triangle callback.
edit: flipquads should be false
Code: Select all
terra->load(objectTemplate->mHeightMap,Ogre::Vector3(0,0,0), dimensions);
mWidth = terra->getHeightMapTex()->getWidth();
mDepth = terra->getHeightMapTex()->getHeight();
mHeight = terra->getMaxHeight();
btVector3 xzRelativeSize = MathUtilities::ogre2Bullet(terra->getXZDimensions());
auto createShape = [&]() {
mShape = new btHeightfieldTerrainShape((int)mWidth, (int)mDepth, terra->getHeightMap().data(), 1.0f,
0.0f, mHeight , 1, PHY_FLOAT, false);
btVector3 localScaling(xzRelativeSize.x()/ mWidth, 1.0f, xzRelativeSize.y()/mDepth);
mShape->setLocalScaling(localScaling);
// create ground object
physics.addShape(mShapeName, mShape);
};
createShape();
auto alignPhysicsToTerra = [&]() {
btScalar yOrigin = -dimensions.y / 2.0f;
btScalar maxHeight = terra->getMaxHeight();
btTransform transf;
transf.setIdentity();
transf.setOrigin(btVector3(-dimensions.x / mWidth / 2.0,
maxHeight / 2.0f + yOrigin,
-dimensions.z / mDepth / 2.0));
rigidBody->setWorldTransform(transf);
};
alignPhysicsToTerra();
This works with centering everything about origin
Thanks for the help though, your idea to move the physics to match terra is a good one. I also implemented the triangle callback.
edit: flipquads should be false