Gluing Bullet and Irrlitch heightmaps

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
endless_dark
Posts: 18
Joined: Mon May 04, 2009 12:18 am

Gluing Bullet and Irrlitch heightmaps

Post by endless_dark »

First part
Yesterday I tried to join Irrlitch heightmaps with Bullet heightmaps and failed. So before trying it again I wanted to really understand and clarify how heightmaps work.
I have created a test program and some test images and got this (maybe someone find it helpful).

Image

Now I see quite better how do they work. But I don't see why there is a row and a column from the image file being completely ignored. Someone knows? It's because of the image size?

Thanks!

This first part is solved in the first answer, thanks to Seven
==================================================
Second part.
Once I got how the heightmaps were really working I tried to make a Bullet+Irrlitch heighmap again, and I can't get it. I've tried lots of variations and nothing seems to work.
There is already example code very similar in places like
http://bulletphysics.org/Bullet/phpBB3/ ... php?t=7560
or
http://www.gamedev.net/topic/641203-sca ... n-objects/
but none of those are working for me.

There are some things that are nosense to me, this is my code, and my output, as you can see I'm commenting and printing everything:

Code: Select all

 
//Terrain scene node
ITexture *texture=driver->getTexture("media/terrain-heightmap.bmp");
ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(texture->getName(),0,-1,vector3df(0.f, 0.f, 0.f),vector3df(0.f, 0.f, 0.f),vector3df(20.f, 1.f, 20.f));
terrain->setPosition(vector3df(0.0f, 0.0f, 0.0f));
terrain->setScale(vector3df(4.0f, 1.0f, 4.0f));
terrain->setMaterialFlag (video::EMF_WIREFRAME, true);
terrain->setMaterialFlag (video::EMF_LIGHTING, false);
 
vector3df scale=terrain->getScale();
aabbox3d<f32> box=terrain->getBoundingBox();
const vector3df size=box.getExtent()/scale;
printf("BOX SIZE = (%f,%f,%f)\n",size.X,size.Y,size.Z);
 
//f32 minHeight=terrain->getHeight(0, 0);
//=== Check out this! ===
f32 minHeight=5.f;
f32 maxHeight=minHeight;
 
int arraySize=texture->getSize().Height;
f32 *heightData = new f32[arraySize*arraySize];
const f32 stepWidthX=size.X/arraySize;
const f32 stepWidthZ=size.Z/arraySize;
u32 runVal=0;
 
vector3df minEdge=box.MinEdge/scale;
vector3df maxEdge=box.MaxEdge/scale;
 
f32 numStepsZ =(maxEdge.Z-minEdge.Z)/stepWidthZ;
printf("FOR Z=%f ; Z<%f ; Z+=%f (%f STEPS)\n",minEdge.Z,maxEdge.Z,stepWidthZ,numStepsZ);
f32 numStepsX =(maxEdge.X-minEdge.X)/stepWidthX;
printf("FOR X=%f ; X<%f ; X+=%f (%f STEPS)\n",minEdge.X,maxEdge.X,stepWidthX,numStepsX);
 
//Populate the heightData array
for(f32 z=minEdge.Z; z<maxEdge.Z; z+=stepWidthZ)
    {
        for(f32 x=minEdge.X; x<maxEdge.X; x+=stepWidthX)
        {
             //=== Check out this! ===
            //const f32 curVal= terrain->getHeight(x, z);
            const f32 curVal = 5.f;
 
            heightData[runVal]=curVal;
            printf("[%d",runVal);
            printf("|%f]",heightData[runVal]);
            runVal++;
 
            if(curVal>maxHeight){maxHeight=curVal;}
            if(curVal<minHeight){minHeight=curVal;}
        }
            printf("\n");
    }
    printf("==Calling bullet heightmap function==\n");
    printf("- Arraysize:%d\n",arraySize);
    printf("- minHeight:%f\n",minHeight);
    printf("- maxHeight:%f\n",maxHeight);
    btHeightfieldTerrainShape *Shape = new btHeightfieldTerrainShape(arraySize, arraySize, heightData, 1.f, minHeight, maxHeight, 1, PHY_FLOAT, false);
    delete[] heightData;
    Shape->setLocalScaling(btVector3(4.0f, 1.0f, 4.0f));
 
    // Ground Motion State.
    btTransform transform;
    transform.setIdentity();
    transform.setOrigin(btVector3(0.0f, 0.0f, 0.0f));
    btDefaultMotionState *groundMotionState=new btDefaultMotionState(transform);
 
    // Ground Rigid Body.
    btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0, groundMotionState, Shape, btVector3(0, 0, 0));
    btRigidBody *groundRigidBody=new btRigidBody(groundRigidBodyCI);
    groundRigidBody->setUserPointer((void *)terrain);
    World->addRigidBody(groundRigidBody);
    Objects.push_back(groundRigidBody);
 
If you pay attention to the "Check out this!" lines, I am overwriting the height value for every point to 5. The heightmap should be flat then...

Code: Select all

 
Generated terrain data (17x17) in 0.0010 seconds
BOX SIZE = (16.000000,74.000000,16.000000)
FOR Z=0.000000 ; Z<16.000000 ; Z+=0.941176 (17.000000 STEPS)
FOR X=0.000000 ; X<16.000000 ; X+=0.941176 (17.000000 STEPS)
 
[0|5.000000][1|5.000000][2|5.000000][3|5.000000][4|5.000000][5|5.000000][6|5.000000][7|5.000000][8|5.000000][9|5.000000][10|5.000000][11|5.000000][12|5.000000][13|5.000000][14|5.000000][15|5.000000][16|5.000000]
[17|5.000000][18|5.000000][19|5.000000][20|5.000000][21|5.000000][22|5.000000][23|5.000000][24|5.000000][25|5.000000][26|5.000000][27|5.000000][28|5.000000][29|5.000000][30|5.000000][31|5.000000][32|5.000000][33|5.000000]
[34|5.000000][35|5.000000][36|5.000000][37|5.000000][38|5.000000][39|5.000000][40|5.000000][41|5.000000][42|5.000000][43|5.000000][44|5.000000][45|5.000000][46|5.000000][47|5.000000][48|5.000000][49|5.000000][50|5.000000]
[51|5.000000][52|5.000000][53|5.000000][54|5.000000][55|5.000000][56|5.000000][57|5.000000][58|5.000000][59|5.000000][60|5.000000][61|5.000000][62|5.000000][63|5.000000][64|5.000000][65|5.000000][66|5.000000][67|5.000000]
[68|5.000000][69|5.000000][70|5.000000][71|5.000000][72|5.000000][73|5.000000][74|5.000000][75|5.000000][76|5.000000][77|5.000000][78|5.000000][79|5.000000][80|5.000000][81|5.000000][82|5.000000][83|5.000000][84|5.000000]
[85|5.000000][86|5.000000][87|5.000000][88|5.000000][89|5.000000][90|5.000000][91|5.000000][92|5.000000][93|5.000000][94|5.000000][95|5.000000][96|5.000000][97|5.000000][98|5.000000][99|5.000000][100|5.000000][101|5.000000]
[102|5.000000][103|5.000000][104|5.000000][105|5.000000][106|5.000000][107|5.000000][108|5.000000][109|5.000000][110|5.000000][111|5.000000][112|5.000000][113|5.000000][114|5.000000][115|5.000000][116|5.000000][117|5.000000][118|5.000000]
[119|5.000000][120|5.000000][121|5.000000][122|5.000000][123|5.000000][124|5.000000][125|5.000000][126|5.000000][127|5.000000][128|5.000000][129|5.000000][130|5.000000][131|5.000000][132|5.000000][133|5.000000][134|5.000000][135|5.000000]
[136|5.000000][137|5.000000][138|5.000000][139|5.000000][140|5.000000][141|5.000000][142|5.000000][143|5.000000][144|5.000000][145|5.000000][146|5.000000][147|5.000000][148|5.000000][149|5.000000][150|5.000000][151|5.000000][152|5.000000]
[153|5.000000][154|5.000000][155|5.000000][156|5.000000][157|5.000000][158|5.000000][159|5.000000][160|5.000000][161|5.000000][162|5.000000][163|5.000000][164|5.000000][165|5.000000][166|5.000000][167|5.000000][168|5.000000][169|5.000000]
[170|5.000000][171|5.000000][172|5.000000][173|5.000000][174|5.000000][175|5.000000][176|5.000000][177|5.000000][178|5.000000][179|5.000000][180|5.000000][181|5.000000][182|5.000000][183|5.000000][184|5.000000][185|5.000000][186|5.000000]
[187|5.000000][188|5.000000][189|5.000000][190|5.000000][191|5.000000][192|5.000000][193|5.000000][194|5.000000][195|5.000000][196|5.000000][197|5.000000][198|5.000000][199|5.000000][200|5.000000][201|5.000000][202|5.000000][203|5.000000]
[204|5.000000][205|5.000000][206|5.000000][207|5.000000][208|5.000000][209|5.000000][210|5.000000][211|5.000000][212|5.000000][213|5.000000][214|5.000000][215|5.000000][216|5.000000][217|5.000000][218|5.000000][219|5.000000][220|5.000000]
[221|5.000000][222|5.000000][223|5.000000][224|5.000000][225|5.000000][226|5.000000][227|5.000000][228|5.000000][229|5.000000][230|5.000000][231|5.000000][232|5.000000][233|5.000000][234|5.000000][235|5.000000][236|5.000000][237|5.000000]
[238|5.000000][239|5.000000][240|5.000000][241|5.000000][242|5.000000][243|5.000000][244|5.000000][245|5.000000][246|5.000000][247|5.000000][248|5.000000][249|5.000000][250|5.000000][251|5.000000][252|5.000000][253|5.000000][254|5.000000]
[255|5.000000][256|5.000000][257|5.000000][258|5.000000][259|5.000000][260|5.000000][261|5.000000][262|5.000000][263|5.000000][264|5.000000][265|5.000000][266|5.000000][267|5.000000][268|5.000000][269|5.000000][270|5.000000][271|5.000000]
[272|5.000000][273|5.000000][274|5.000000][275|5.000000][276|5.000000][277|5.000000][278|5.000000][279|5.000000][280|5.000000][281|5.000000][282|5.000000][283|5.000000][284|5.000000][285|5.000000][286|5.000000][287|5.000000][288|5.000000]
 
==Calling bullet heightmap function==
- Arraysize:17
- minHeight:5.000000
- maxHeight:5.000000
 
Every output seems like I expected, however when my scene renders I see this:
Image

The white wireframe is my Irrlitch scene node, it corresponds the heightmap bmp. The green wireframe is the bullet rendering, the ground is in a different position but also looks broken instead of flat with some random vertices going to the moon.
How can this be possible?

Thanks in advance, I'm getting a bit crazy with this. :lol:
Last edited by endless_dark on Wed Jul 02, 2014 1:39 am, edited 3 times in total.
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Re: Question understanding heightmaps

Post by Seven »

one of the params of the hieghtfield is the patch size. make sure that the patch size and the bitmap dimensions match correctly or you will get this.
endless_dark
Posts: 18
Joined: Mon May 04, 2009 12:18 am

Re: Question understanding heightmaps

Post by endless_dark »

Seven wrote:one of the params of the hieghtfield is the patch size. make sure that the patch size and the bitmap dimensions match correctly or you will get this.
Oh!!! Thanks!! I wasn't paying attention to that value.
I guess the value is rounded to the patch size. I will check it right now, marking this as solved.
endless_dark
Posts: 18
Joined: Mon May 04, 2009 12:18 am

Re: Gluing Bullet and Irrlitch heightmaps

Post by endless_dark »

Here, a balls rain confirms that is not the render what is broken, there is actually a hole there.
Image
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Re: Gluing Bullet and Irrlitch heightmaps

Post by Seven »

I have some bullet code for this. When I get back home I'll post it for you
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Re: Gluing Bullet and Irrlitch heightmaps

Post by Seven »

sorry, i dont have the bullet code anymore, but this is how I bake the PhysX code. It should help you get the mesh vertices for the bullet that you are looking for

Code: Select all

 
    CSPhysXObject* CSPhysXWorld::createTerrainObject(const IPhysicsObjectData &data)
    {
        // pointer to the terrain scenenode
        ITerrainSceneNode* terrain = dynamic_cast<ITerrainSceneNode*>(data.node);
 
        // make sure that we have a valid scenenode
        CS_CHECK_NULL(terrain, "WARNING PhysX createTerrainObject() terrain node is not valid");
 
        // temporary variable
        CDynamicMeshBuffer buffer(EVT_2TCOORDS, EIT_16BIT);
 
        // get pointer to dynamic buffer for LOD 0
        terrain->getMeshBufferForLOD(buffer, 0);
 
        // remember the scale of the terrain
        vector3df scale = terrain->getScale();
 
        // allocate a temporary array of vertices
        PxVec3* verts = new PxVec3[buffer.getVertexCount()];
 
        // get a pointer to the vertices
        S3DVertex2TCoords* vertices = (S3DVertex2TCoords*)buffer.getVertices();
 
        // scale each vertex properly
        for (u32 i = 0; i < buffer.getVertexCount(); ++i)
            verts[i] = PxVec3(vertices[i].Pos.X * scale.X, vertices[i].Pos.Y * scale.Y, vertices[i].Pos.Z * scale.Z);
 
        // Cooking recipe
        PxTriangleMeshDesc meshDesc;
        meshDesc.points.count       = buffer.getVertexCount();
        meshDesc.points.stride      = sizeof(PxVec3);
        meshDesc.points.data        = verts;
        meshDesc.triangles.count    = buffer.getIndexCount() / 3;
        meshDesc.triangles.stride   = sizeof(u16)*3;
        meshDesc.triangles.data     = buffer.getIndexBuffer().getData();
        meshDesc.flags              = PxMeshFlag::e16_BIT_INDICES;
 
        // temproary variable
        PxDefaultMemoryOutputStream stream;
        
        // check the cooking result
        if (!getPhysXManager()->getCooking()->cookTriangleMesh(meshDesc, stream))
        {
            // log this event
            CS_LOG("WARNING PhysX createTerrainObject() cooktrianglemesh failed");
 
            // cleanup our memory mess
            delete[] verts;
 
            // bail......
            return NULL;
        }
 
        // create the triangle mesh
        PxDefaultMemoryInputData rb(stream.getData(), stream.getSize());
        PxTriangleMesh* triangleMesh = getPhysXManager()->getPhysicsSDK()->createTriangleMesh(rb);
 
        // cleanup our memory mess
        delete[] verts;
 
        // check if the mesh is valid, return NULL if not
        CS_CHECK_NULL(triangleMesh, "WARNING traingle mesh is not valid");
 
        // create the actor
        PxRigidStatic* actor = getPhysXManager()->getPhysicsSDK()->createRigidStatic(PxTransform(PxVec3(data.position.X, data.position.Y, data.position.Z)));
        CS_CHECK_NULL(actor, "WARNING! actor is not valid in createTerrainObject() call");
 
        // create the shape
        PxShape* shape = actor->createShape(PxTriangleMeshGeometry(triangleMesh), *getPhysXManager()->m_DefaultMaterial);
        CS_CHECK_NULL(shape, "WARNING! shape is not valid in createTerrainObject() call");
        shape->setSimulationFilterData(getFilterData(data.objecttype));
 
        // add the actor to the physx scene
        getScene()->addActor(*actor);
 
        actor->userData = (void*)data.userdata;
        shape->userData = (void*)data.userdata;
 
        // safely release the mesh
        CS_SAFE_RELEASE(triangleMesh);
 
        // create our physx object holder
        CSPhysXObject_RigidStatic* obj = new CSPhysXObject_RigidStatic();
            obj->initialize();      // initialize the object
            obj->create(this);      // create the object
            obj->setActor(actor);   // remember the actor
 
        obj->setRotation(data.rotation);
 
        // everything went fine, return our physx object
        return obj;
    }
 
.
.
.
the CSPhysXObject is just a structure for holding all of the data once it is extracted.
endless_dark
Posts: 18
Joined: Mon May 04, 2009 12:18 am

Re: Gluing Bullet and Irrlitch heightmaps

Post by endless_dark »

Seven wrote:sorry, i dont have the bullet code anymore, but this is how I bake the PhysX code. It should help you get the mesh vertices for the bullet that you are looking for

Code: Select all

 
    CSPhysXObject* CSPhysXWorld::createTerrainObject(const IPhysicsObjectData &data)
    {
        // pointer to the terrain scenenode
        ITerrainSceneNode* terrain = dynamic_cast<ITerrainSceneNode*>(data.node);
 
        // make sure that we have a valid scenenode
        CS_CHECK_NULL(terrain, "WARNING PhysX createTerrainObject() terrain node is not valid");
 
        // temporary variable
        CDynamicMeshBuffer buffer(EVT_2TCOORDS, EIT_16BIT);
 
        // get pointer to dynamic buffer for LOD 0
        terrain->getMeshBufferForLOD(buffer, 0);
 
        // remember the scale of the terrain
        vector3df scale = terrain->getScale();
 
        // allocate a temporary array of vertices
        PxVec3* verts = new PxVec3[buffer.getVertexCount()];
 
        // get a pointer to the vertices
        S3DVertex2TCoords* vertices = (S3DVertex2TCoords*)buffer.getVertices();
 
        // scale each vertex properly
        for (u32 i = 0; i < buffer.getVertexCount(); ++i)
            verts[i] = PxVec3(vertices[i].Pos.X * scale.X, vertices[i].Pos.Y * scale.Y, vertices[i].Pos.Z * scale.Z);
 
        // Cooking recipe
        PxTriangleMeshDesc meshDesc;
        meshDesc.points.count       = buffer.getVertexCount();
        meshDesc.points.stride      = sizeof(PxVec3);
        meshDesc.points.data        = verts;
        meshDesc.triangles.count    = buffer.getIndexCount() / 3;
        meshDesc.triangles.stride   = sizeof(u16)*3;
        meshDesc.triangles.data     = buffer.getIndexBuffer().getData();
        meshDesc.flags              = PxMeshFlag::e16_BIT_INDICES;
 
        // temproary variable
        PxDefaultMemoryOutputStream stream;
        
        // check the cooking result
        if (!getPhysXManager()->getCooking()->cookTriangleMesh(meshDesc, stream))
        {
            // log this event
            CS_LOG("WARNING PhysX createTerrainObject() cooktrianglemesh failed");
 
            // cleanup our memory mess
            delete[] verts;
 
            // bail......
            return NULL;
        }
 
        // create the triangle mesh
        PxDefaultMemoryInputData rb(stream.getData(), stream.getSize());
        PxTriangleMesh* triangleMesh = getPhysXManager()->getPhysicsSDK()->createTriangleMesh(rb);
 
        // cleanup our memory mess
        delete[] verts;
 
        // check if the mesh is valid, return NULL if not
        CS_CHECK_NULL(triangleMesh, "WARNING traingle mesh is not valid");
 
        // create the actor
        PxRigidStatic* actor = getPhysXManager()->getPhysicsSDK()->createRigidStatic(PxTransform(PxVec3(data.position.X, data.position.Y, data.position.Z)));
        CS_CHECK_NULL(actor, "WARNING! actor is not valid in createTerrainObject() call");
 
        // create the shape
        PxShape* shape = actor->createShape(PxTriangleMeshGeometry(triangleMesh), *getPhysXManager()->m_DefaultMaterial);
        CS_CHECK_NULL(shape, "WARNING! shape is not valid in createTerrainObject() call");
        shape->setSimulationFilterData(getFilterData(data.objecttype));
 
        // add the actor to the physx scene
        getScene()->addActor(*actor);
 
        actor->userData = (void*)data.userdata;
        shape->userData = (void*)data.userdata;
 
        // safely release the mesh
        CS_SAFE_RELEASE(triangleMesh);
 
        // create our physx object holder
        CSPhysXObject_RigidStatic* obj = new CSPhysXObject_RigidStatic();
            obj->initialize();      // initialize the object
            obj->create(this);      // create the object
            obj->setActor(actor);   // remember the actor
 
        obj->setRotation(data.rotation);
 
        // everything went fine, return our physx object
        return obj;
    }
 
.
.
.
the CSPhysXObject is just a structure for holding all of the data once it is extracted.
Thanks, I'll check it.
Post Reply