Jump to content

  • Log In with Google      Sign In   
  • Create Account


Whats a reasonable timestep


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
40 replies to this topic

#21 L. Spiro   Crossbones+   -  Reputation: 12298

Like
0Likes
Like

Posted 23 November 2012 - 12:30 PM

This is why I have been frustrated with this topic. People arguing just to win a retarded debate about semantics (gosh, does L. Spiro mean “unacceptable” literally?) have made it hard to find the important posts, and as a result I overlooked the original poster’s reply in my last reply.


I think I really need to clarify how my timestep works for example at 60 fps the physics engine will simulate 1/120th of a second twice per frame. The time required to render the last frame is divided up into intervals of 1/120th of a second and it processes 1/120th of a second that many times. So at 30fps it will do 4 updates per frame. What I'm really looking for is a better model for updating my physics. As for a definition of responsiveness it is how quickly the simulation reacts to input from the user. Stutter is when the framerate remains constant but motion appears to stop or slow down for fractions of a second I assume this is caused by the physics engine taking longer than the timestep to compute the update.

Firstly, I want to pose the question: Why do you think you need to update logic 120 times per second? Once again countless games can offer a responsive and jitter-free experience without having to update this often. Including Starsiege: Tribes, the fastest game mentioned by anyone so far, which only updates 32 times per second.
Do you have a specific reason for this update resolution?
If your reason is just that “It makes things run more smoothly” then your problem lies elsewhere.
You should be experiencing fine control and physics at a mere 30 updates per second, and you should be using this as a base-line anyway because, since numerous other games are fine at this speed, yours should be too unless you are doing something wrong.

What you said about stutter is basically related to my #1 in my first post. The objects are jerky because you are not interpolating them between frames.
If you don’t interpolate the objects, your framerate won’t matter as much because you will be displaying the same objects in the same positions as last frame about 30% of the time or so.
I covered this topic here: http://lspiroengine.com/?p=378
Hit Ctrl-F and type “But How Can”
You will find a drawing that explains this concept, and the entire logic behind interpolation is within the same post as well.

Firstly, try to address this issue, because once again a higher update rate is usually just going to hide underlying problems.
Start with an update rate at 30 and try to solve this issue. As mentioned before, most games are able to get perfectly fine performance out of 30-ish update rates as long as the rest of their pipeline is solid, so getting yourself a nice smooth input rate and lack of jitter at 30 updates per second is a nice way to check that you are doing everything else fine.

Only increase your update rate once everything else checks out and it is only the option left. It does serve a use, but don’t do it prematurely or else all you are doing is hiding bugs.


L. Spiro

Edited by L. Spiro, 23 November 2012 - 12:51 PM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

Sponsor:

#22 ic0de   Members   -  Reputation: 808

Like
0Likes
Like

Posted 23 November 2012 - 01:21 PM

I figured I may as well post my code so people know exactly whats going on. I modified it to do some interpolation but I'm still getting some stutter.

physics code:

float dt = 1.0f/60.0f;
float prevtime, accumulator, frameTime;
int substeps;

void integrate(int pausedtime)
{
	 gameTimeInMS = SDL_GetTicks() - pausedtime; //find out how much time has been spent "in game" and not paused
	 frameTime = (gameTimeInMS - prevtime)/1000.0f;//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 >= dt ) //compute the amount of substeps
	 {
	 	 substeps += 1;
	 	 accumulator -= dt;
	 }

	 prevtime = gameTimeInMS; //store this time for the next update
}

void physstep(int pausedtime = 0)
{

integrate(pausedtime); //find out how much time needs to be simulated
dynamicsWorld->stepSimulation(dt, substeps); //do the physics computation

for(int i = 0; i < substeps; i++)
{

  //update the player
  player->update();

  rocket.update();

  for(int i = 0; i < numents; i++) //update all the movable entities in the game
  {
   ents[i]->update();
   collectGarbage(i); //recycle inactive ents
  }
}
substeps = 0;
}

main loop:

if(paused) //if paused don't simulate physics
{
	 guiProcessInput(&SDLev);
}
else //we aren't paused so lets simulate physics
{
	 physstep(pausedtime); //pass the amount of time spent paused to the physics engine so it can be compensated for
}
render(); //draw the scene

EDIT: fully commented now.

Edited by ic0de, 23 November 2012 - 01:45 PM.

you know you program too much when you start ending sentences with semicolons;


#23 L. Spiro   Crossbones+   -  Reputation: 12298

Like
-1Likes
Like

Posted 23 November 2012 - 01:32 PM

A few comments would help. They don’t bite.
Trying to figure out what your code’s goal is will take me a lot of time I am afraid I don’t have. A comment by each if/else and for () would be helpful.
Not just for me but for you in 10 years.


L. Spiro

[EDIT]
He added comments after my post.
[/EDIT]

Edited by L. Spiro, 23 November 2012 - 01:42 PM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#24 L. Spiro   Crossbones+   -  Reputation: 12298

Like
0Likes
Like

Posted 23 November 2012 - 01:49 PM

This is not specifically related to your current problem, but may be helpful overall.
You currently have a branch for when the physics simulation should update at X time or not.
It would instead be better to have the simulation update at X time, where X is either a full frame time or 0 if paused. This avoids a high-level branch. At this level, it is better to avoid such special-case conditions and instead just pass what is called a “virtual” time to the physics simulation.
I have mentioned it here: http://lspiroengine.com/?p=378
It is basically a timer that does not get updated with the real-world timer, and as long as its time-since-last-frame remains at 0, no objects using it will move. Hence pause is pause.


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#25 Hodgman   Moderators   -  Reputation: 27790

Like
1Likes
Like

Posted 23 November 2012 - 08:11 PM

First thing I noticed is that you're only using a millisecond accurate timer. For high speed animations at high frame rates, the error from that quantization will be significant (4% of a frame at 60Hz).

Someone mentioned earlier that bullet has interpolation built in, so that if you tell it to advance 1 and a half frames worth of time (e.g. 16.666*1.5 if @ 60Hz stepping), then it will perform one sim frame and produce correct visual results that have been interpolated an exta half a frame.

#26 L. Spiro   Crossbones+   -  Reputation: 12298

Like
1Likes
Like

Posted 23 November 2012 - 09:09 PM

You are making some common mistakes I have outlined here: Fixed-Time-Step Implementation.

The first one being that you should never handle absolute time with floating-point numbers. float is only useful for delta values—the time since the last update.
So, firstly, always start your game time from 0 and use unsigned long long (64-bit unsigned integer) to store it, with a resolution in microseconds (as mentioned by Hodgman, milliseconds are too slow). This is explained in more detail in my link.


Secondly your method for pausing is very much a hack. I used essentially the same thing long ago when I was just first starting out but luckily on my next project I realized how lucky I had been that it worked, and making it work correctly in all areas took a huge amount of effort.
Mentioned in my link are virtual timers.
Your time class (another problem is that you don’t have one of these) should maintain both the actual time and the virtual time. The virtual time is the time that does not advance when the game is paused, so when the class is told to update and advance time, if the game is paused it does not update its virtual timers. Since they don’t update when paused, the time now and the time of the last update are the same, so the delta is 0, so the physics simulation moves objects by t=0, or in other words they don’t move.

This is basically the industry standard on how to implement pausing in games.


The main issue is that you are using too many floating-point values.
Change these to 64-bit unsigned integers with a microsecond resolution and report back. You will likely see an improved stutter-free result only from this change.
Once again, this is all outlined in the link above.


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#27 ic0de   Members   -  Reputation: 808

Like
0Likes
Like

Posted 23 November 2012 - 09:19 PM

The main issue is that you are using too many floating-point values.
Change these to 64-bit unsigned integers with a microsecond resolution and report back. You will likely see an improved stutter-free result only from this change.
Once again, this is all outlined in the link above.


Is there any library you can suggest that use to measure really accurate time? bullet has a btClock class but that only gives time as an unsigned long int not an unsigned long long like you suggested.

you know you program too much when you start ending sentences with semicolons;


#28 Hodgman   Moderators   -  Reputation: 27790

Like
2Likes
Like

Posted 23 November 2012 - 10:44 PM

I use timer_lib.

#29 kauna   Crossbones+   -  Reputation: 2161

Like
0Likes
Like

Posted 24 November 2012 - 07:24 AM

L_Spiro :

A question to clarify things, if the game logic is running at 30 fps for example but the drawn frame rate is something like 60,
it is acceptable to wait ~33 milliseconds before you get visual response from the game that you input has had an effect?

Best regards!

[edit] When I said as soon as possible, I didn't mean something like "asynchronous handling of input"

Edited by kauna, 24 November 2012 - 07:52 AM.


#30 Hodgman   Moderators   -  Reputation: 27790

Like
0Likes
Like

Posted 24 November 2012 - 07:35 AM

kauna, it depends on the game.
It was mentioned earlier that when you send commands to the GPU, the driver is allowed to buffer them for several frames before executing them. e.g.
CPU             GPU
Draw Frame 1
Draw Frame 2
Draw Frame 3    Draw Frame 1
                Draw Frame 2
                Draw Frame 3
So even if you do process inputs and update the game immediately, you still might not receive a visual change for ~100ms if the driver feels like it!

To test this, you need a high-speed camera filming your screen and your input device, then use a robot to hit an input button suddenly. You can then count the frames between the button being pressed and a change appearing on-screen. Even in 60Hz games, sometimes this delay is as high as 66ms, and players don't notice too much.

Typically "twitch" action games, like Counter-strike, should put in a lot of effort into reducing this latency, while slower-paced games don't really have to worry.

Edited by Hodgman, 24 November 2012 - 07:35 AM.


#31 kauna   Crossbones+   -  Reputation: 2161

Like
0Likes
Like

Posted 24 November 2012 - 07:56 AM

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!

#32 Matias Goldberg   Crossbones+   -  Reputation: 3007

Like
2Likes
Like

Posted 24 November 2012 - 10:27 AM

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

Edited by Matias Goldberg, 24 November 2012 - 10:31 AM.


#33 ic0de   Members   -  Reputation: 808

Like
0Likes
Like

Posted 24 November 2012 - 11:39 AM

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();

Edited by ic0de, 24 November 2012 - 11:42 AM.

you know you program too much when you start ending sentences with semicolons;


#34 Cornstalks   Crossbones+   -  Reputation: 6966

Like
1Likes
Like

Posted 24 November 2012 - 12:11 PM

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.
[ 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 ]

#35 ic0de   Members   -  Reputation: 808

Like
1Likes
Like

Posted 24 November 2012 - 12:25 PM

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

you know you program too much when you start ending sentences with semicolons;


#36 Matias Goldberg   Crossbones+   -  Reputation: 3007

Like
0Likes
Like

Posted 24 November 2012 - 02:00 PM


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.

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

#37 Álvaro   Crossbones+   -  Reputation: 11906

Like
1Likes
Like

Posted 24 November 2012 - 02:19 PM

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.

#38 Cornstalks   Crossbones+   -  Reputation: 6966

Like
0Likes
Like

Posted 24 November 2012 - 02:43 PM

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...
[ 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 ]

#39 L. Spiro   Crossbones+   -  Reputation: 12298

Like
3Likes
Like

Posted 25 November 2012 - 09:02 PM

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

Edited by L. Spiro, 25 November 2012 - 09:11 PM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#40 AgentC   Members   -  Reputation: 1230

Like
0Likes
Like

Posted 26 November 2012 - 11:48 AM

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.

Every time you add a boolean member variable, God kills a kitten. Every time you create a Manager class, God kills a kitten. Every time you create a Singleton...

Urho3D (engine)  Hessian (C64 game project)





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS