[ODE] Framerate problem *again*

skjold@cistron.nl skjold at cistron.nl
Tue Feb 11 02:37:02 2003


Hi,

Here's the thing: You don't keep the dWorldStep interval constant. Let's say for example, if you run 1000 simulation steps of 1 millisecond each:

for(i = 0; i < 1000; i++) dWorldStep(odeWorld, 0.001);

That would have a different result from, say, running 100 steps of 10ms each:

for(i = 0; i < 100; i++) dWorldStep(odeWorld, 0.010);

Both loops compute exactly 1 second of simulated time, but the key here is that different time steps have different results. Like it says in the docs: 2*5 != 1*10.

So let's look at your code again. Am I right in assuming that GetCurrentTicks returns milliseconds, and "#define SIM_TICK 0.01" ?

> //! Run the physic
> lCurrentTick=pTimer.GetCurrentTicks();
> while (lSimTime<lCurrentTick) {
> 	fDelta=lCurrentTick-lSimTime;
> 	if (fDelta>=SIM_TICK*1000) {
> 		dWorldStep(odeWorld, SIM_TICK);
> 		lSimTime+=SIM_TICK*1000;
> 	}
> 	else {
> 		dWorldStep(odeWorld, fDelta/1000);
> 		lSimTime+=fDelta;
> 	}
> }

The problem, basically, is the 'else' block. Here's my interpretation of your code: The while loop is used to let the simulated time catch up with the actual elapsed time. fDelta contains how much time the sim is 'behind on schedule'. This is good. If fDelta is larger than a fixed simulation timestep, then do a simulation timestep. This is good too. fDelta gets updated accordingly when it loops. But what happens next, when fDelta gets small enough? In comes the 'else' block, basically telling the simulator to do a smaller-than-usual timestep to account for that little bit of fDelta time left.

So, while the 'else' block allows your game to calculate smaller simulator steps when it has processor speed available, it also means that the simulator timestep varies. And that is why you have different results at different speeds. The key to keep it consistent: Always use the exact same time step when calling dWorldStep. Your code would look something like this:

> lCurrentTick=pTimer.GetCurrentTicks();
> while ((lCurrentTick-lSimTime) >= SIM_TICK*1000) {
>	dWorldStep(odeWorld, SIM_TICK);
> 	lSimTime+=SIM_TICK*1000;
> }

I hope that helped :)

Greets



> Hi all!
> 
> I've read all the threads about which tecnique to use to keep the
> simulation time as much "real" as possible.
> I know I have to use little timesteps (5 - 10 ms) for dWorldStep().
> I know it should be constant and indipendent from the framerate.
> I know someone uses a separated thread and someone uses an
> "integration tecnique".
> 
> Maybe I know all? :) No, sure, because my game has very different
> behaviors depending on frame rates. I can also run it in two different
> screen modes (with different refresh rates (60 and 85)) on the same
> (mine) computer and it seems to be two different games!!!
> 
> So... here I post the code around dWorldStep() I use:
> 
> //! Run the physic
> lCurrentTick=pTimer.GetCurrentTicks();	// current real ticks
> while (lSimTime<lCurrentTick) {
> 	fDelta=lCurrentTick-lSimTime;
> 	if (fDelta>=SIM_TICK*1000) {
> 		dWorldStep(odeWorld, SIM_TICK);
> 		lSimTime+=SIM_TICK*1000;
> 	}
> 	else {
> 		dWorldStep(odeWorld, fDelta/1000);
> 		lSimTime+=fDelta;
> 	}
> }
> 
> lSimTime is the accumulated simulation time;
> SIMTICK is defined as 0.01 secs (10 ms);
> As you can see I use the integration tecnique, but it doesn't work.
> Do you see something really wrong about that code?
> 
> Please help... thank you!
> 
> 	Bye Bye
> 	Marco
> _______________________________________________
> ODE mailing list
> ODE@q12.org
> http://q12.org/mailman/listinfo/ode
>