Hi, all!
I have set up paging terrain and it works very well now. Also I update it with my sun/moon system parameters and it even updates dynamically which is super cool. Now my appetite grows and I want to add buildings and trees and possibly grass to the terrain. So I ask how to handle objects with paging?
Adding to that I will need colliders, have anybody joined Ogre's terrain system with Bullet heightmap collider? Or trimesh collider?
Another thing is of course roads. But that is for another topic.
Paging module - how to make it stream things other than terrain? colliders?
-
- Bronze Sponsor
- Posts: 154
- Joined: Fri May 23, 2025 5:04 pm
- x 5
Paging module - how to make it stream things other than terrain? colliders?
-
- OGRE Team Member
- Posts: 2204
- Joined: Sun Mar 30, 2014 2:51 pm
- x 1188
-
- Bronze Sponsor
- Posts: 154
- Joined: Fri May 23, 2025 5:04 pm
- x 5
Re: Paging module - how to make it stream things other than terrain? colliders?
No, thanks a bunch for the find!
-
- Bronze Sponsor
- Posts: 154
- Joined: Fri May 23, 2025 5:04 pm
- x 5
Re: Paging module - how to make it stream things other than terrain? colliders?
Looks like at time when prepareProceduralPage is running no terrain exists,
so the code
Code: Select all
class DummyPageProvider : public Ogre::PageProvider {
public:
DummyPageProvider(btDynamicsWorld *world)
: Ogre::PageProvider()
, mBtWorld(world)
{
}
std::unordered_map<Ogre::PageID, btRigidBody *> body;
btDynamicsWorld *mBtWorld;
bool prepareProceduralPage(Ogre::Page *page,
Ogre::PagedWorldSection *section)
{
Ogre::TerrainGroup *pGroup =
((Ogre::TerrainPagedWorldSection *)section)
->getTerrainGroup();
long x, y;
pGroup->unpackIndex(page->getID(), &x, &y);
Ogre::Terrain *pTerrain = pGroup->getTerrain(x, y);
if (!pTerrain)
return true;
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);
btRigidBody *groundBody = new btRigidBody(
0, new btDefaultMotionState(), groundShape);
groundBody->getWorldTransform().setOrigin(btVector3(
terrainPosition.x,
terrainPosition.y + (pTerrain->getMaxHeight() -
pTerrain->getMinHeight()) /
2,
terrainPosition.z));
groundBody->getWorldTransform().setRotation(
btQuaternion(Ogre::Quaternion::IDENTITY.x,
Ogre::Quaternion::IDENTITY.y,
Ogre::Quaternion::IDENTITY.z,
Ogre::Quaternion::IDENTITY.w));
mBtWorld->addRigidBody(groundBody);
body[page->getID()] = groundBody;
return true;
}
bool loadProceduralPage(Ogre::Page *page,
Ogre::PagedWorldSection *section)
{
return true;
}
bool unloadProceduralPage(Ogre::Page *page,
Ogre::PagedWorldSection *section)
{
return true;
}
bool unprepareProceduralPage(Ogre::Page *page,
Ogre::PagedWorldSection *section)
{
return true;
}
};
doesn't work and can't work. My other tries with definers work but consume all of the CPU.
The below code works but is super expensive too. Need some task/workqueue system
for this to work properly.
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++;
}
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;
}