Jump to content
  • Advertisement
Sign in to follow this  
Medo Mex

Frame Independent Problem

This topic is 818 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi Guys,

 

I'm using QueryPerformanceCounter() to get the elapsed time in seconds in a float variable.

 

Then I multiply the elapsed time with the velocity as the following in entity Update(float timeElapsed) function:

void Update(float timeElapsed)
{
velocity *= timeElapsed;
setPosition(getPosition() + velocity); // Now, update the entity position based on velocity
velocity = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
...
...

I can notice that the entity movement speed is not the same when the frame rate drop, for example If I enable VSync during rendering to drop the frame rate to 60, the entity move faster than when the frame rate is 130

 

Any idea what could be causing this problem?

Edited by Medo3337

Share this post


Link to post
Share on other sites
Advertisement

How do you calculate the velocity in the first place? Normalize it before multiplying it with the delta time and see if that makes it move at the same speed regardless of the frame rate. If that helps then it means that the calculations of the velocity themselves depend on the frame rate.

Share this post


Link to post
Share on other sites


I'm using QueryPerformanceCounter() to get the elapsed time in seconds in a float variable.

 

How exactly are you using QPC to get the elapsed time?

 


I can notice that the entity movement speed is not the same when the frame rate drop

 

Whenever your framerate drops the time elapsed increases which is the expected obviously. In your example, when the elapsed time varies, so do an entity speed. A solution to that is use a fixed time step, which won't guarantee that your frame rate is the same every time, but will integrate your position in a more deterministic way. Read this article:

 

http://gafferongames.com/game-physics/fix-your-timestep/

 

Could you paste your game loop here?

Share this post


Link to post
Share on other sites

@GuyWithBeard: Even after I normalize the velocity, I still have the same problem.

 

@Irlan Robson:

 

In class construction:

LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
secondsPerCount = 1.0 / (double)freq.QuadPart;

Every frame:

void FrameUpdate()
{
     LARGE_INTEGER liCurrTime;
     QueryPerformanceCounter(&liCurrTime);
     currentTime = (double)liCurrTime.QuadPart;
     if (lastTime == 0)
     {
         lastTime = currentTime;
     }

     double timeElapsed = (currentTime - lastTime) * secondsPerCount;

     lastTime = currentTime;

     // Code here to do all the game updates...
     // ...
     // ...
}
Edited by Medo3337

Share this post


Link to post
Share on other sites
Whatever behaviour you're trying to achieve, normalizing the velocity wouldn't help at all.

Your game loop is correct. Try disabling the v-sync to make sure your problem isn't related to the CPU and check the results. Also, you should rely on elapsed microseconds or miliseconds per frame rather than FPS for measurement accuracy.

Share this post


Link to post
Share on other sites

@Irlan Robson:

@GuyWithBeard:

I notice that I don't have this problem if the entity is not assigned to the physics engine.

 

I'm using Bullet Physics and doing simulation as the following:

m_DynamicsWorld->stepSimulation(elapsedTime);

Share this post


Link to post
Share on other sites

function Update(float timeElapsed)
{
velocity *= timeElapsed;
setPosition(getPosition() + velocity); // Now, update the entity position based on velocity
velocity = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
...
...


The problem isn’t with the timers, but rather the units. The code is demoting velocity from units per second to units. For example:

1. Set velocity to 10 units per second (u/s).
2. Multiplying velocity by elapsed time in seconds (s) gives you a distance in units (u).
3. The result is then fed back into velocity-- reinterpret_casting from u to u/s, as it were. (BAD!)
4. Multiplying the new velocity in units with a the elapsed time gives you u*s units. (NO!)
5. Repeat steps 3-5, but with u*s^N units for velocity each iteration.


Be mindful of the units of your operands whenever you do any sort of math:
float3 distance_traveled = velocity * timeElapsed;  // u/s * s -> u
setPosition( getPosition() + distance_traveled );   // u + u -> u
If your intention was to have damping:
const float DAMPING = 0.8f;        // (scalar) reduces velocity 20% every 1 second (roughly) 
velocity *= DAMPING * timeElapsed; // u/s * scalar -> u/s
float3 distance_traveled = velocity * timeElapsed; // u/s * s -> u 
setPosition( getPosition() + velocity * timeElapsed ); // u + u -> u
Edited by fastcall22

Share this post


Link to post
Share on other sites


Whatever behaviour you're trying to achieve, normalizing the velocity wouldn't help at all.

 

Well it helps in the sense that it narrows the problem down. I never meant he should leave the normalization in there (obviously).

 

Since the problem is still there after normalization, it means that the velocity value is fine (or at least it means that there is a problem somewhere else, ie. the delta time value).

Share this post


Link to post
Share on other sites

Now, it's clear that the problem is caused by the physics engine, since the movement is frame independent only if I disable the physics engine or if I don't assign the entity to the physics engine.

 

Here is what I'm doing in the physics engine each frame:

1. Iterate through all the body dynamics and update their transformation based on the entities transformation

2. Simulate physics using: m_DynamicsWorld->stepSimulation(elapsedTime);

3. Iterate through all the body dynamics and update the entities transformation based on the rigid bodies transformation.

Edited by Medo3337

Share this post


Link to post
Share on other sites

for a proper implementation of fixed timestep al la gaffer, you get ET, add it to your accumulator, then while the accumulator >=DT, you run one update and subrtract DT from the accumulator. so velocity will never be multiplied by ET, only perhaps by DT and/or some constant to make it run at the correct speed with fixed timestep. where DT is the fixed time step per update.

 

what you want to do is go with the final algo listed in the gaffer article. right now it looks like  your using the 4th or 5th algo out of the six or so listed.  he shows the evolution of the algo from naive brute force implementation up through fully functional with all  cases covered. so only the last algo in the article works correctly with no flaws. what you're doing now looks like one of the algos just before the last one in that article.

 

here's timer code you can use to double check yours:

 

// timers
DWORD Ztimer[10];
LARGE_INTEGER Ztimer_freq,Ztimer2[10];
 

init:

QueryPerformanceFrequency(&Ztimer_freq);

 
// start timer a
void Zstarttimer(int a)
{
Ztimer[a]=GetTickCount();
QueryPerformanceCounter(&Ztimer2[a]);
}
 
// returns elapsedtime of timer a in millisecs
int Zelapsedtime(int a)
{
LARGE_INTEGER c,f;
float g,h;
QueryPerformanceCounter(&c);
f.QuadPart=c.QuadPart-Ztimer2[a].QuadPart;
g=(float)f.QuadPart;
h=(float)Ztimer_freq.QuadPart;
g*=1000.0f;
g/=h;
return((int)g);
}
 
// returns elapsed ticks of timer a
int Zelapsedticks(int a)
{
LARGE_INTEGER c,f;
QueryPerformanceCounter(&c);
f.QuadPart=c.QuadPart-Ztimer2[a].QuadPart;
return((int)f.QuadPart);
}
Edited by Norman Barrows

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!