extreme bouncing on btHeightfieldTerrainShape with small timesteps

Post Reply
H7per
Posts: 4
Joined: Thu Jan 19, 2023 2:51 am

extreme bouncing on btHeightfieldTerrainShape with small timesteps

Post by H7per »

I am working on a flight simulation as a hobby project.

I require suspension modelling, for which I need extreme mass ratios(small wheels vs a massive airplane). The way I approached this issue was by lowering the time step size to 1/1000th, however now that I started toying around with terrain, I discovered that my plane, currently consisting of two suspended wheels and a box with the box resting on the ground by one edge, would jump considerably, seemingly at random at said edge it is resting on. This is less pronounced at higher timestep lengths, however that breaks the suspension and does not completly eliminate the bouncing.

In my search for a solution I came across a thread which seems to be about a related issue. It having to do with edge contacts makes sense to me, as pushing the aircraft in one direction on the plane, results in a regular pattern of bumps, although it does not always jump that high.

The OP of that thread solved it by implementing a custom callback, however that seems to do nothing for my issue at hand, the behavior seems to exactly identical despite the callback being called(which I could confirm via a console print).

Here is a shortened version of my implementation. I hope I am not omitting crucial information here. My biggest worry there is that I could have implemented something like the generation of the triangleInfoMap wrong, leading to no effect from the callback.

Code: Select all

bool collisionCallback(btManifoldPoint& cp, const btCollisionObjectWrapper* obj1, int id1, int index1, const btCollisionObjectWrapper* obj2, int id2, int index2)
{
	btAdjustInternalEdgeContacts(cp, obj2, obj1, id2, index2);
	return true;
}
void main()
{
	btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
	btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
	btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();
	btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
	btDiscreteDynamicsWorld* dynamicsWorld = new  btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);

	double testheight[100 * 100];
	for (int i = 0; i < 100 * 100; i++)
	{
		testheight[i] = 0.0f;
	}

	gContactAddedCallback = collisionCallback;
	
	btHeightfieldTerrainShape* terrainshape = new btHeightfieldTerrainShape(100, 100, &testheight, btScalar(10), 1, true, true);
	btTriangleInfoMap* triangleInfoMap = new btTriangleInfoMap();
	btGenerateInternalEdgeInfo(terrainshape, triangleInfoMap);
	terrainshape->setTriangleInfoMap(triangleInfoMap);
	
	btCollisionShape* groundShape = terrainshape;

	btTransform groundTransform;
	groundTransform.setIdentity();
	groundTransform.setOrigin(btVector3(0, 3, 0));
	
	btScalar mass(0.);
	btVector3 localInertia(0, 0, 0);
	if (mass != 0.f)
		groundShape->calculateLocalInertia(mass, localInertia);

	btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
	btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, terrainshape, localInertia);
	btRigidBody* body = new btRigidBody(rbInfo);
	body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
	dynamicsWorld->addRigidBody(body);
	
	while(!glfwWindowShouldClose(window))
	{
		dynamicsWorld->stepSimulation(deltaTime, 100, 0.001);
	}
}
Thanks in advance for any possible solutions, I've been on this for a considerable amount of time now.
Last edited by H7per on Fri Jan 20, 2023 8:22 pm, edited 3 times in total.
User avatar
drleviathan
Posts: 827
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: extreme bouncing on btHeightfieldTerrainShape with small timesteps

Post by drleviathan »

Is it really the edge normals? The sprung constraints between the fuselage and the wheels complicate matters. A quick way to verify it is caused by edge normals would be to have the box drag on a btStaticPlaneShape. If the problem goes away that would support the edge normals theory.

Meanwhile, the code snippet you supplied looks odd. (1) I don't see where the testp variable comes from. Meanwhile you initialize the testheight array but never use it. (2) I don't see where you create the body, add it to the world, or set the CUSTOM_MATERIAL_CALLBACK flag. Are you remembering to do that?

Code: Select all

    //enable custom callback
    body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
H7per
Posts: 4
Joined: Thu Jan 19, 2023 2:51 am

Re: extreme bouncing on btHeightfieldTerrainShape with small timesteps

Post by H7per »

drleviathan wrote: Fri Jan 20, 2023 7:25 pm Is it really the edge normals? The sprung constraints between the fuselage and the wheels complicate matters. A quick way to verify it is caused by edge normals would be to have the box drag on a btStaticPlaneShape. If the problem goes away that would support the edge normals theory.
I used a giant box as the floor before hand, with no issues. This only started showing up with the switch to btHeightfieldTerrainShape.
drleviathan wrote: Fri Jan 20, 2023 7:25 pm Meanwhile, the code snippet you supplied looks odd. (1) I don't see where the testp variable comes from. Meanwhile you initialize the testheight array but never use it. (2) I don't see where you create the body, add it to the world, or set the CUSTOM_MATERIAL_CALLBACK flag. Are you remembering to do that?
The testp was a pointer that got the memory address of heightfield assigned to it. Ofcourse this is unnecessary, I changed it in my code and in my post for clarification and good practice.
I added those parts (creating and adding the body) to my original post now, for the sake of clarity.
Yes, the callback flag is set. As I mentioned, I confirmed that the callback is running via printing to console, I added that to the code embed too now.
User avatar
drleviathan
Posts: 827
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: extreme bouncing on btHeightfieldTerrainShape with small timesteps

Post by drleviathan »

I wonder if your problem isn't so much bad normals as it is interpenetration? This idea because I think the interpenetration resolution code can also introduce non-physical results that might look similar to glitches from bad normals. However, with such a small substep I doubt this could be the case: the plane would be unlikely to move fast enough within a substep to penetrate into a terrain triangle.

Have you tried temporarily disabling the wheel-plane constraint system and just using a solid plane + wheels compound shape? If that makes the glitch go away then maybe the constraints are somehow allowing the plane to penetrate. If this were the case... maybe the constraints are causing the plane box to rotate enough to interpenetrate (e.g. the penetration is not so much because of linear motion but angular). Explicitly increasing the collision margin of the box to be much larger than its default 0.04m might help. Alternatively, try making the Box's angular intertia tensor artificially large... no I take that back, since that would only increase the effective mass/inertia ratio and contribute toward instability. Hrm...

For your game mechanics... is it very important the plane's landing system be done in a physically correct way? Maybe a simple game-physics cheat system could be used: either explicit ray-tracing with custom spring/hover effect or use Bullet's vehicle system.
H7per
Posts: 4
Joined: Thu Jan 19, 2023 2:51 am

Re: extreme bouncing on btHeightfieldTerrainShape with small timesteps

Post by H7per »

drleviathan wrote: Fri Jan 20, 2023 11:50 pm I wonder if your problem isn't so much bad normals as it is interpenetration? This idea because I think the interpenetration resolution code can also introduce non-physical results that might look similar to glitches from bad normals. However, with such a small substep I doubt this could be the case: the plane would be unlikely to move fast enough within a substep to penetrate into a terrain triangle.
If "interpenetration" is penetration below the surface of the mesh, it would seem odd to me. The vertical velocity is low and it happens even if the airplane is resting on the terrain and then gets a force acting on it, moving it very slowly.

As for the other parts, I attempted using only the planes box, with no wheels and fixed blocks, as part of a multi body in the place the wheels should be. If it lands flat(without wheels), it will bounce less, although it does not eliminate it. Landing on an edge or corner of the collision box seems to make it quite a bit worse, with an instant jump on landing.

I am not attached to having physically simulated wheels, although I don't think that part is the problem, I could not observe any bouncing between the wheels and the ground and as mentioned above, the bouncing is still there, even with no wheels at all.
Here is a recording, probably should have provided that earlier: https://www.youtube.com/watch?v=yLTq2ZU ... e=youtu.be

Confirming it to be the edges would probably be easier if I had implemented some debug rendering.
User avatar
drleviathan
Posts: 827
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: extreme bouncing on btHeightfieldTerrainShape with small timesteps

Post by drleviathan »

When I look at the implementation of btAdjustInternalEdgeContacts() I see this:

Code: Select all

void btAdjustInternalEdgeContacts(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap, const btCollisionObjectWrapper* colObj1Wrap, int partId0, int index0, int normalAdjustFlags)
{
    //btAssert(colObj0->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE);
    if (colObj0Wrap->getCollisionShape()->getShapeType() != TRIANGLE_SHAPE_PROXYTYPE)
        return;

    
    btTriangleInfoMap* triangleInfoMapPtr = 0;

    if (colObj0Wrap->getCollisionObject()->getCollisionShape()->getShapeType() == TERRAIN_SHAPE_PROXYTYPE)
    {
        btHeightfieldTerrainShape* heightfield = (btHeightfieldTerrainShape*)colObj0Wrap->getCollisionObject()->getCollisionShape();
        triangleInfoMapPtr = heightfield->getTriangleInfoMap();

//#define USE_HEIGHTFIELD_TRIANGLES
#ifdef USE_HEIGHTFIELD_TRIANGLES
        btVector3 newNormal = btVector3(0, 0, 1);

        const btTriangleShape* tri_shape = static_cast<const btTriangleShape*>(colObj0Wrap->getCollisionShape());
        btVector3 tri_normal;
        tri_shape->calcNormal(tri_normal);
        newNormal = tri_normal;
        //                  cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB);
        cp.m_normalWorldOnB = newNormal;
        // Reproject collision point along normal. (what about cp.m_distance1?)
        cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1;
        cp.m_localPointB = colObj0Wrap->getWorldTransform().invXform(cp.m_positionWorldOnB);
        return;
#endif
    }
You see the #define of USE_HEIGHTFIELD_TRIANGLES is commented out. That looks like the logic you want to invoke: it replaces the contact normal with one that always points out of the triangle plane.

Try this: copy the body function and put it in your collisionCallback() and re-enable the contact normal override. If that doesn't work, write your own analysis logic there and modify it to override the contact normals in a better way.
H7per
Posts: 4
Joined: Thu Jan 19, 2023 2:51 am

Re: extreme bouncing on btHeightfieldTerrainShape with small timesteps

Post by H7per »

drleviathan wrote: Sat Jan 21, 2023 6:17 am You see the #define of USE_HEIGHTFIELD_TRIANGLES is commented out. That looks like the logic you want to invoke: it replaces the contact normal with one that always points out of the triangle plane.
I tried uncommenting this before with the .cpp added to my project, the code is being executed. This however had no effect on the bouncing. I went as far as to force the Normal to be (0, 1, 0) (same as what the adjusted normals would be), which made no difference aswell, however changing it to something like (0, -1, 0) confirms that that too is working (the box predictably phasing through the floor). I had also tried copying the code directly in the callback, but to no avail.

I doubt the normals are at fault. There seems to be an unexplicable sudden impulse upwards (as seen in cp.m_appliedImpulse, the latter supplied code in the repo prints the impulse if it exceeds a certain amount and its contact vector) at the contact.
I suppose it probably still has something to do with edges due to the fact that it doesn't happen on a static plane or a boxshape.

https://github.com/H7perus/OpenGL-Testi ... rainfixing
If anyone wants to have a shot at this, I made my repo public and made a branch which contains pretty much only the necessities(a compund shape box with commented out wheels, rotated (as edge and corner hits appear to cause it primarily) and debug drawing, for easily repeatable results). To me this issue is a blackbox right now. Luckily it appears the wheels are unaffected by this effect, so adding a tail wheel should atleast fix this behavior for the short term, however not allowing belly landings is a bit limiting for what i had in mind.
Post Reply