Advertisement

Whats a reasonable timestep

Started by November 23, 2012 05:14 AM
38 comments, last by UnshavenBastard 12 years, 2 months ago
Hodgman, you are right that naturally there are different scenarios and types of games where the input latency has bigger or smaller effect.

Best regards!
To answer the OP question:

Will increasing the Hz update cause a "smoother/more responsive" simulation?
YES.
There is a limit though. If the hz is too high, the simulation delta will be too low. For example at 10000hz, the delta time in seconds will be 0.0001, which can't even be represented accurately using base-2 floating point.
The lack of precision can cause several artifacts, for example your objects not moving at all, or in very rare cases appear as if they're going backwards (or back and forth) due to how the integration resolves the frame.


You can resort to using doubles, but is considered a very bad practice in game development. (Check out Tom Forsyth's blog, article named "A matter of precision" for an explanation).
Probably the best option would be to resort to integers and/or fixed point in those cases.

Is stutter & responsiveness a direct cause of low simulation update frequency?
If you're above 30Hz, probably not. There's either a bad setup of the physics config, your world size, or a lag between the frame you're processing and the one you're showing (see Hodgman's explanation)
Also check there are no NaNs being passed to Bullet.
Another problem is that your timer code for waiting until the next update is probably flawed. QueryPerformanceCounter, Sleep, timeGetTime, even RDTSC are all now seriously flawed because of Cool 'n Quiet/SpeedStep, multi-core and even OS/HW/Bios bugs. Each timer method has it's own quircks. Google about how to implement them properly. It's very tricky.

What do most people use as their timestep?
Most games use 30hz (FPS & RPG games), some use 25hz (RTS games, Slow paced games, a few games limited by HW like Zelda OoT), and some use 60hz (Car driving simulations, music games, fast action games, fighting games). Other values are possible i.e. some cellphone games update at 5hz, or when the screen needs to be refreshed, or 120hz games, etc.
Note that on consoles, some companies tweak the hz for PAL games (i.e. 60hz becomes 50hz, 30hz becomes 25hz, etc)

Try to keep the Hz a multiple of the screen's refresh rate (unlike what L. Spiro suggested, 48hz is NOT a good idea, 45 or 50 is probably better)

With a monitor refreshing at 60hz, probably a 67hz game will feel less responsive than a 60hz game. John Carmack does a lot of intensive research about this. You should check his website, articles, and follow his Twitter account. Note that he complains a lot about LCD/LEDs monitors adding a lot of input lag because of unnecessary postprocessing; which is another problem of it's own.

Some games (DMC 4, Sonic Heroes) default to 60hz but include an option to change the frequency to other predefined values, like 15-30-45. I personally find this method the best one, because if the PC can't handle your "ideal" update rate, the user can tweak it down, and he'll know that the gameplay experience willl be affected and will blame his old PC, instead of the game. But at least he will be able to enjoy it without going into slow motion.

Cheers
Dark Sylinc
Advertisement
Ok, here is my new code using long longs and and microseconds. It feels noticeably more stable and consistent. However I don't know why but it just seems off in a way that I cannot describe, like I'm moving across sandpaper or something. I know it's not the graphics because I can rotate freely of the physics engine and that's smooth as butter.


unsigned long long TimeUS()
{
return physicsTimer.getTimeMicroseconds();
}

float dt = 1.0f/60.0f;
unsigned long long prevtime, accumulator, frameTime;
unsigned long long dtInUS = dt*1000000.0f;
int substeps;
unsigned long long gameTimeInUS;
void integrate(unsigned long long pausedtime)
{
gameTimeInUS = TimeUS() - pausedtime; //find out how much time has been spent "in game" and not paused
frameTime = (gameTimeInUS - prevtime); //compute the amount of time required for the last frame also convert from ms to seconds
accumulator += frameTime; //this is the amount of time that needs to be simulated
while ( accumulator >= dtInUS ) //compute the amount of substeps
{
substeps += 1;
accumulator -= dtInUS;
}
prevtime = gameTimeInUS; //store this time for the next update
}


I'm using btClock::getTimeMicroseconds();

Will increasing the Hz update cause a "smoother/more responsive" simulation?
YES.
There is a limit though. If the hz is too high, the simulation delta will be too low. For example at 10000hz, the delta time in seconds will be 0.0001, which can't even be represented accurately using base-2 floating point.

Define "accurately," please.

#include <stdio.h>

int main()
{
float f = 0.0001f;
printf("0.0001 -> %.50e\n", f);
f = 1.0f / 60.0f;
printf("1/60 -> %.50e\n", f);
}
//0.0001 -> 9.99999974737875163555145263671875000000000000000000e-05
//1/60 -> 1.66666675359010696411132812500000000000000000000000e-02

Looks to me like 0.0001 is represented just as accurately as 1/60. IMO, the issue of updating too quickly comes from mixing large numbers and small numbers (i.e. 12345678.0 + 0.1 is, effectively, 12345678.0), not from the actual timestep's representation being inaccurate.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Wow this is embarrassing, turns out that bullet does most of this heavy lifting for me, all I needed to do was pass the time since the last update. My efforts to control the timestep seemed to do nothing but compound the problem.

http://bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World

[quote name='Matias Goldberg' timestamp='1353774478' post='5003765']
Will increasing the Hz update cause a "smoother/more responsive" simulation?
YES.
There is a limit though. If the hz is too high, the simulation delta will be too low. For example at 10000hz, the delta time in seconds will be 0.0001, which can't even be represented accurately using base-2 floating point.

Define "accurately," please.

#include <stdio.h>

int main()
{
float f = 0.0001f;
printf("0.0001 -> %.50e\n", f);
f = 1.0f / 60.0f;
printf("1/60 -> %.50e\n", f);
}
//0.0001 -> 9.99999974737875163555145263671875000000000000000000e-05
//1/60 -> 1.66666675359010696411132812500000000000000000000000e-02

Looks to me like 0.0001 is represented just as accurately as 1/60. IMO, the issue of updating too quickly comes from mixing large numbers and small numbers (i.e. 12345678.0 + 0.1 is, effectively, 12345678.0), not from the actual timestep's representation being inaccurate.
[/quote]
Yeah, my bad. Thanks for clearing that out.

However, 9.999..e-05 sounds like it's a rounded aproximation, rather outputting the actual representation in the PC, because 0.0001 has a periodic representation which is bigger than 0.0001
Advertisement

However, 9.999..e-05 sounds like it's a rounded aproximation, rather outputting the actual representation in the PC, because 0.0001 has a periodic representation which is bigger than 0.0001




What do you think 0.0001f is, if not what was posted? I don't know what you mean when you say the periodic representation of 0.0001 is bigger than 0.0001.

However, 9.999..e-05 sounds like it's a rounded aproximation, rather outputting the actual representation in the PC, because 0.0001 has a periodic representation which is bigger than 0.0001

Not sure what you mean by that last part, but 9.99999974737875163555145263671875e-05 is the actual representation in the computer of the computer's approximation of 0.0001...
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

Wow this is embarrassing, turns out that bullet does most of this heavy lifting for me, all I needed to do was pass the time since the last update. My efforts to control the timestep seemed to do nothing but compound the problem.

So you might say that, instead of just increasing your time-step, which some might have done “just because it works”, it was a good idea to check for underlying problems, yes?
You should check to see how smoothly your game runs at 30 updates-per-second because this is the most common update rate. Naturally you will get faster responses from higher update rates, but it should still feel smooth and responsive enough for 90% of the games you play at a rate of 30, so if it doesn’t then once again you should keep investigating underlying issues.

If it does run smoothly at such a rate then I think you are well on your way and I am glad I could help.

Keep in mind that higher update rates have multiple disadvantages that make the lowest-possible update rate the most desirable.
The most obvious is the number of cycles that take place each frame. An update rate of 1,000 for example means that at 60 FPS you are running the physics simulation 16 or 17 times every frame, so if your game is heavy on physics that would be a huge problem. This is why this update rate is only reserved for racing games and fighting games where the amount of logic is strictly defined and capped.

The next is accuracy, although this one is a double-edged sword. Faster updates means less penetration into objects when they collide, but Bullet and most other physics engines are equipped to handle interpenetration fairly well since this is a well researched area and a classic problem to resolve. On the other hand, faster updates invariably means more accumulated floating-point errors. An object in free-fall will fall more accurately if updated only 30 times per second instead of 1,000. Each time you update you can always assume some small amount of precision has been lost, so fewer is better.

Finally, there is just less CPU usage when using lower update rates. You may very easily increase your FPS by decreasing your logical update rate. This is the biggest reason to always select the lowest possible rate that meets your needs.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Just a small sidenote about Bullet (or at least the 2.80 version I've been using), currently it AFAIK uses the following order of operations:

1) detect collisions
2) apply forces/constraints
3) extrapolate forward motion

This means that after each step it will extrapolate based on the latest velocity & acceleration. That may result in interpenetration until the next collision detection. The effect will be smaller with smaller timesteps, but is especially noticeable when scaling down the real-world elapsed time for "bullet-time" effect.

This topic is closed to new replies.

Advertisement