Ogre Version: master branch
Operating System: Ubuntu 22.04
Render System: OpenGL ES 2.0
Hi, all!
I please help me how to generate colliders with Bullet on paged terrain.
All the suggestions I got on this forum did not work for me. Looking at Ogre source I found the working recipe but it consumes all CPU
resources running each frame:
Code: Select all
std::unordered_set<long> col_terrains;
std::unordered_map<long, btRigidBody *> col_bodies;
void create_colliders()
{
btDynamicsWorld *world = mDynWorld->getBtWorld();
std::unordered_set<long> new_terrains;
Ogre::TerrainGroup::TerrainSlotMap slots =
mTerrainGroup->getTerrainSlots();
auto slot_it = slots.begin();
while (slot_it != slots.end()) {
Ogre::Terrain *terrain = slot_it->second->instance;
long x = slot_it->second->x;
long y = slot_it->second->y;
long key = y * 1024 + y;
std::cout << "x: " << x << "\n";
std::cout << "y: " << y << "\n";
if (!terrain) {
slot_it++;
continue;
}
if (new_terrains.find(key) != new_terrains.end()) {
slot_it++;
continue;
}
if (col_terrains.find(key) != col_terrains.end()) {
slot_it++;
continue;
}
new_terrains.insert(key);
col_terrains.insert(key);
btRigidBody *body = createHeightfieldShape(
terrain->getSize(), terrain->getHeightData(),
terrain->getMinHeight(),
terrain->getMaxHeight(), terrain->getPosition(),
terrain->getWorldSize() /
(terrain->getSize() - 1),
world);
OgreAssert(body, "Could not allocate body");
col_bodies[key] = body;
std::cout << "adding terrain body: " << terrain << " "
<< col_bodies[key] << "\n";
slot_it++;
}
auto col_it = col_terrains.begin();
std::list<long> rm_bodies;
while (col_it != col_terrains.end()) {
std::cout
<< "checking: terrain still exists: " << *col_it
<< "\n";
/* no terrain */
if (new_terrains.find(*col_it) == new_terrains.end()) {
std::cout << "was removed: "
<< col_bodies[*col_it] << " "
<< *col_it << "\n";
rm_bodies.push_back(*col_it);
/* free shapes and bodies */
}
col_it++;
}
#if 0
while (!rm_bodies.empty()) {
long key = rm_bodies.front();
rm_bodies.pop_front();
btRigidBody *body = col_bodies[key];
OgreAssert(body, "No body :(");
btCollisionShape *shape = body->getCollisionShape();
col_terrains.erase(key);
mDynWorld->getBtWorld()->removeRigidBody(body);
delete shape;
delete body;
}
#endif
}
btRigidBody *createHeightfieldShape(int size, float *data,
const Ogre::Real &minHeight,
const Ogre::Real &maxHeight,
const Ogre::Vector3 &position,
const Ogre::Real &scale,
btDynamicsWorld *world)
{
// Convert height data in a format suitable for the physics engine
float *terrainHeights = new float[size * size];
assert(terrainHeights != 0);
for (int i = 0; i < size; i++) {
memcpy(terrainHeights + size * i,
data + size * (size - i - 1),
sizeof(float) * size);
}
btScalar heightScale = 1.f;
btVector3 localScaling(scale, heightScale, scale);
btHeightfieldTerrainShape *terrainShape =
new btHeightfieldTerrainShape(
size, size, terrainHeights, 1 /*ignore*/,
minHeight, maxHeight, 1, PHY_FLOAT, true);
terrainShape->setUseDiamondSubdivision(true);
terrainShape->setLocalScaling(localScaling);
//Create Rigid Body using 0 mass so it is static
btRigidBody *body = new btRigidBody(BT_LARGE_FLOAT,
new btDefaultMotionState(),
terrainShape);
body->setFriction(0.8f);
body->setHitFraction(0.8f);
body->setRestitution(0.6f);
body->getWorldTransform().setOrigin(btVector3(
position.x, position.y + (maxHeight - minHeight) / 2,
position.z));
body->getWorldTransform().setRotation(
Ogre::Bullet::convert(Ogre::Quaternion::IDENTITY));
body->setCollisionFlags(body->getCollisionFlags() |
btCollisionObject::CF_STATIC_OBJECT);
world->addRigidBody(body);
return body;
}