Complicated ODE Shenanigans not working

git clone git://github.com/magcius/explr.git
cd explr
python app.py

WASD is backwards, I know. Hold shift to run.

So… what’s with the bouncing stuff using ODE?

I don’t have a computer to run that on right now, and I’m not sure many people here know what git is anyway (Personally I use it all the time, and think anyone who doesn’t is mad ( :stuck_out_tongue: ), but ho hum.) - you would be better off linking to a .zip archive.

Anyway, straight guess, but 9 times out of 10 when people complain about bouncing in ODE they aren’t running the simulation with a fixed time step, which is a requirement of ODE. Typically you would have your application running its graphics as fast as possible, with ODE specifically running at, say, 50 frames per second, regardless of what the rest of the application is doing.

I am running at a fixed time step.

self.physStep  = 1. / 120

def _updateWorld(self):
        self.physSpace.autoCollide()

        self.physAccum += globalClock.getDt()
        
        while self.physAccum > self.physStep:
            self.physAccum -= self.physStep
            self.physWorld.quickStep(self.physStep)
            
        for cell in self.cells.itervalues():
            cell.simulate()

        self.physContactGroup.empty()

No your not, or not all of it at any rate - your doing a fixed frame rate on the simulation but a variable frame rate on the collision detection. Its actually the collision detection part where a fixed time step matters, its just that you can’t run the simulation variable and the collision detection fixed, so you have to do both fixed. Move those calls to self.physSpace.autoCollide() and self.physContactGroup.empty() inside the loop and you should be all set.

Also, just a warning - if you do a fixed frame rate simulation as you have done and then run on too slow a computer you will hit a problem when the collision detection ends up taking more processor time each frame until everything else grinds to a halt - its good to throw a limiter in there so the simulation slows down rather than goes berserk. (Either slow down the progress of time or accept unstable behaviour on really slow computers - both are better than it freezing up entirely. Obviously this is only a polishing feature - only really matters for widely distributed/commercial work.)

okay, it’s still bouncing

github.com/magcius/explr/blob/ma … m/world.py

Sorry for the double post, but ran into another snag:

setOffsetPosition with any parameter in the Vec3 negative doesn’t work.

physGeom.setOffsetPosition(Vec3(0, 0, -100)) works the same as physGeom.setOffsetPosition(Vec3(0, 0, 0)).

With physGeom.setOffsetPosition(Vec3(0, 0, 2)) I notice a difference.

hmm… the bouncing seems to be fixed when I lower the mu, but then my character takes too long to stop…

It’s bouncy even when bounce and bounce_vel are 0.

Ah, ok, that is enough info to make a guess. As I said, I’m in no position right now to run your code, so can’t do anything but guess!

What you need to understand about ODE is its an approximation of physical reality, and a bad one at that. This means the parameters can do strange things, in this case because the system is somewhat relaxed about conservation of energy - its very easy to make the system have a constant supply of energy, or even an explosively increasing supply of energy (The consequences of which can be… interesting. And not in a good way.). A common mistake, though I don’t think this particular one, is to not allow energy to drain from the system, and as all simulations start with some energy in them it never goes away, resulting in jittering/bouncing etc. (Source of starting energy could be from any object that doesn’t start precisely in a rest position… and rest positions in ODE have the objects penetrating each other by an amount dependent on, among other things, the framerate, which is why you need to fix it. This also means none of your objects will be starting in rest positions unless you want to do some hairy maths dependent on the ode internals.)

What I think is happening for you is a consequence of how ODE models friction - it applies a force in the other direction to motion in the plane of the colliding surface. Problem is for infinity that force is calculated to cause the object to dead stop by the next time step (As defined by each substep of the quick step call.) - its a very large value in other words, and due to floating point imprecision that force vector is not perfectly in the collision plane. Consequentially it applies some force perpendicular to the collision plane which is how energy is getting in. Reducing mu will lower that vector very quickly, and make that perpendicular force negligible.

My advised solution is what I do for every ODE object - I add my own damping force - I take the velocity and apply a force that is some small negative multiple of it (The ODE manual actually recommends this solution.) This removes energy from the system and tends to stop all of these kinds of problems. Well, mostly. (You do end up tuning the value on a per object basis - you can do the maths and define it as an air resistance term if you want, which saves on tuning the parameter.) With that in place you can drop mu and let your own resistance do its job, getting a more stable simulation to boot.

Another thing - when dealing with a character - I would recommend having mu set to zero and doing friction yourself. Makes for much better motion as you can switch it off when the player is pressing the keys and max it out when they stop. I even go so far as to cap the force so the player takes a couple of (perceptual) steps to hit max speed and again a few steps to slow down from moving full throttle; this also limits the ramps the player can climb before they get too steep.

Hope that helps! - try reading the ODE manual, it contains a lot of this kind of advice - there is a surprising amount of black magic that goes into getting ODE to play ball. Possibly literally;-)

Your reply makes me want Bullet physics and dynamics more and more.

@Magcius

Have you tried making a kinematic character controller? I know the ODE wiki and some(most?) of the mails on the ODE mailing lists suggest to go with dynamic, but as far as I know, none of the more feature complete physics engines goes this way, and with my own experiments with KCs I’ve found the dynamic to be only apparently easier to make, but it’s also quite unpredictable sometimes and that’s exactly what you want to avoid with KCs. PhyX, Bullet, and I guess Havok too, use Kinematic Character Controllers, because they’re so much easier to control and get right. With dynamic you have to constrain the body so much, it doesn’t really have a point.

I actually have wrote a KKC, but it’s very deep in my code, so before posting it here I need to extract it from there and make it more universal (right now the code is a typical internal one). But I will post it eventually, I promise.

Anyway, the route I’ve taken is that I’ve made a body-less capsule geom, stuck a down-facing ray to the bottom of it (remember that geoms in ODE have position at the center, not at the bottom), hovered it a little above the ground. “A little” means the height of the steps the character is meant to be able to walk up.

In every step I update the position of the character to be exactly X units above the ground. That way it can easilly walk up and down stairs, and I avoid a situation in which the character - walking very fast - “takes off” of the ground and glides a little above steps or a slide. At the same time, the capsule allows it to collide normally with everything higher than the steps limit. And obviously when the character happens to be higher above the ground than it should (that is when the foot ray doesn’t collide with anything) I put the character into falling. Otherwise it would be falling instantaneously of cliffs, ending up on ground like 10 meters lower in a fraction of a second.

For jumping (explanation - highest entry is the higest hit point on the foot ray - I sort them myself, because I don’t trust it always being the first, or the last, I prefer to make sure I get it right myself, and jumpTime is zeroed when the jump is finished):

def processJump(self, newPos, stepSize, highestEntry):
	self.jumpTime += stepSize
	
	np = self.jumpStartPos + self.jumpSpeed*self.jumpTime + (-9.81)*(self.jumpTime)**2
		
	if highestEntry and np <= highestEntry.getContactPoint(0)[2] + self.levitation:
		self.state = "ground"
		return highestEntry.getContactPoint(0)[2] + self.levitation
	
	return np

Falling:

def fall(self, newPos, stepSize, highestEntry):
	if self.state != "falling":
		self.fallStartPos = self.capsuleGeom.getPosition()[2]
		self.fallSpeed = 0.0
		self.fallTime = 0.0
		self.state = "falling"
	else:
		self.fallTime += stepSize
	newPos[2] = self.fallStartPos + self.fallSpeed*self.fallTime + (-9.81)*(self.fallTime)**2
	return newPos

I post those jumping and falling functions because I found making that look good the toughest part of making a KCC.

For movement I have a simple self.speed = [0, 0] list. The way I handle that in update is very simple and very standard:

speedVec = Vec3(self.speed[0]*stepSize, self.speed[1]*stepSize, 0)
quat = self.capsuleGeom.getQuaternion()
speedVec = quat.xform(speedVec)
newPos += speedVec

Also, I use a state variable (not Panda FSM in that case, too sophisticated for the task) with possible values of “ground”, “falling”, “jumping”. When the character jumps and get’s hit in the head (i.e. the normal of the collision geom is (0, 0, -1)) I set it to “falling” and the character doesn’t penetrate through other geoms.

For collisions with static geometry I move the character away in the direction of the normal by the length of penetration depth (I’ve found that making it smaller than the penetration depth, like depth * 0.8 gives better results and the character doesn’t shiver). And for collisions with dynamic objects, I just get the collision normal and set a force on the body. That way I can puch objects around.

I hope this helps in any way. I will try to get my ode character controller code out there, because I myself found that subject in ODE the most problematic, and there aren’t any real sollutions on the net as far as I know. But as I said, it’s just a typpical internal code - almost no comments and very integrated with the rest of the stuff. Additionally, I also use my own collision callback (i.e. I don’t use autoCollide) because with autoCollide handling the foot ray was a little problematic. Still, if you want ODE collision detection for a real game, you will find autoCollide unsuitable because there’s no way to make area triggers with it.

Oh, and for time steps, I personally don’t use the proposed time accumulator code, but just doMethodLater with return task.again instead of task.cont. That gave me a little better results, and while the simulation still slows down sometimes, I’ve never got it to freeze (even though my PC is not very strong).

Again, I hope you’ll find my suggestions helpful in any way.