Advertisement

Whats a reasonable timestep

Started by November 23, 2012 05:14 AM
38 comments, last by UnshavenBastard 12 years, 2 months ago
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

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

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

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

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

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

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.
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. [color=#000080]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

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

Advertisement

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.
I use timer_lib.
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"
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.

This topic is closed to new replies.

Advertisement