FAQ  •  Register  •  Login

Framerate-independent physics

Moderator: Inside3D Admins

<<

mh

User avatar

Posts: 2172

Joined: Sat Jan 12, 2008 1:38 am

Post Sun May 15, 2011 10:54 pm

Framerate-independent physics

I came across this article a short time ago: http://gafferongames.com/game-physics/f ... -timestep/

The full info on what this does and how it works is available there; meanwhile here's the Quake version:
  Code:
void Host_ServerFrame (void)
{
   static double accumulated = 0.0;
   double alpha;
   static double prevtime = 0.0;
   const double delta = (1.0 / 72.0);
   double new_frametime;

   accumulated += host_frametime;

   pr_global_struct->frametime = host_frametime;
   SV_ClearDatagram ();
   SV_CheckForNewClients ();

   while (accumulated >= delta)
   {
      host_frametime = delta;
      pr_global_struct->frametime = delta;

      SV_RunClients ();

      if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game))
         SV_Physics ();

      accumulated -= delta;
   }

   alpha = accumulated / delta;

   // assign the remainder of the timestep to a new interpolated time
   new_frametime = host_frametime * alpha + prevtime * (1.0 - alpha);
   prevtime = host_frametime;
   host_frametime = new_frametime;
   pr_global_struct->frametime = host_frametime;

   // send all messages to the clients
   SV_SendClientMessages ();
}
Like the fifth day of playing 24-hour Scrabble when you don't want to use any letters because each one means a world to you because you're so deranged.
<<

Baker

User avatar

Posts: 3170

Joined: Tue Mar 14, 2006 5:15 am

Post Sun May 15, 2011 11:21 pm

That article was a fun read.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
<<

qbism

User avatar

Posts: 788

Joined: Thu Nov 04, 2004 5:51 am

Post Mon May 16, 2011 12:36 am

Seems to work well in a bot DM running cl_maxfps 20, 72, and 999 (actual about 180).

Suggest trying delta = 1/min(cl_maxfps.value, 72) I know the point is framerate independent. But in software engine, physics rate should not really be more than framerate.

More elegant than the previous physics throttling solution. Interesting that SV_RunClients is now within the throttled loop.
<<

mh

User avatar

Posts: 2172

Joined: Sat Jan 12, 2008 1:38 am

Post Mon May 16, 2011 9:04 am

qbism wrote:More elegant than the previous physics throttling solution. Interesting that SV_RunClients is now within the throttled loop.

I picked that one up from the Q1 source - even more interesting that there was already similar code there in the #ifdef FPS_20 stuff. ;)
Last edited by mh on Mon May 16, 2011 9:12 am, edited 1 time in total.
Like the fifth day of playing 24-hour Scrabble when you don't want to use any letters because each one means a world to you because you're so deranged.
<<

mh

User avatar

Posts: 2172

Joined: Sat Jan 12, 2008 1:38 am

Post Mon May 16, 2011 9:11 am

qbism wrote:Suggest trying delta = 1/min(cl_maxfps.value, 72) I know the point is framerate independent. But in software engine, physics rate should not really be more than framerate.

I'm actually thinking that 72 FPS is much too high for Quake. Back in 1996 72 FPS would have been very rare indeed. and the default intended physics behaviour would have been designed around maybe 20-30 FPS.

Not sure what the impact of a variable (or user-settable) delta might be though. That one would need serious testing before committing to the change.
Like the fifth day of playing 24-hour Scrabble when you don't want to use any letters because each one means a world to you because you're so deranged.
<<

reckless

Posts: 1627

Joined: Thu Jan 24, 2008 12:04 pm

Location: inside tha debugger

Post Mon May 16, 2011 12:13 pm

hehe i wasnt sure which of them to replace so i tried both.

strange thing though if i use it on the one after the #else viewmodels dissapear ?
<<

r00k

Posts: 902

Joined: Sat Nov 13, 2004 10:39 pm

Post Wed May 18, 2011 5:06 am

Sweet!

I was just messing around with a frametime throttle for the particles the other day only to have irregular results. Higher maxfps, more particles are drawn and I was trying to calm this down.. without success.

Might be able to do something similar for particles....

ok off to read the article .... ;)
<<

mh

User avatar

Posts: 2172

Joined: Sat Jan 12, 2008 1:38 am

Post Wed May 18, 2011 9:41 am

r00k wrote:Sweet!

I was just messing around with a frametime throttle for the particles the other day only to have irregular results. Higher maxfps, more particles are drawn and I was trying to calm this down.. without success.

Might be able to do something similar for particles....

ok off to read the article .... ;)


Rocket trail particles are generated on the client every frame, so you need to either run CL_RelinkEntites at 72 FPS or (preferably) split off the particle generating code from it and run that at 72 FPS. Make sure that you check for cls.signon == SIGNONS before doing so, of course. And split off CL_LerpPoint so that it runs every frame rather than just at 72 FPS. And possibly a few other things I can't remember right now, but that's something I got working yesterday and it was painful with loads of implication elsewhere that you wouldn't expect.
Like the fifth day of playing 24-hour Scrabble when you don't want to use any letters because each one means a world to you because you're so deranged.
<<

Spike

Posts: 2063

Joined: Fri Nov 05, 2004 3:12 am

Location: UK

Post Wed May 18, 2011 11:48 am

higher = more? :o
for me, higher = none!
particles are spawned every 4qu using the original particle system. if you're generating a rocket trail from interpolated positions, if you have a high enough framerate the rocket will move less than the distance between two particles. because its not moved 4qu or so, you get no particle. for me, the cut off point is about 1k fps - no trails past that mark.
if its moving exactly 4qu instead of 7qu each frame then yes, you'll have more particles. you'll also get more if your framerate is slow enough to let the rocket move exactly 16qu.
The solution is to use better trail tracking - that is to store the distance moved beyond the previous particle so that the spawn rate is fully inclusive of that.

if your rocket trail code generates a particle at the *start* of every trail segment, then yeah, you'll always get at least $fps particles per second. the fix is the same even if the existing code is not.

unlike sv_phys, you need to do it per rocket, as they all have different speeds and trails are based upon distance, not time.
<<

r00k

Posts: 902

Joined: Sat Nov 13, 2004 10:39 pm

Post Thu May 19, 2011 7:56 am

Some attempts rendered no trail yes. altering host_frametime more particles. I wanted a consistent number of particles for trails no matter how fast or slow they moved. Like you said, distance might be a good baseline to create an algorithm around.
<<

mh

User avatar

Posts: 2172

Joined: Sat Jan 12, 2008 1:38 am

Post Thu May 19, 2011 4:07 pm

Well the baseline ID Quake code already generates them based on distance:
  Code:
void R_RocketTrail (vec3_t start, vec3_t end, int type)
.
.
.
   VectorSubtract (end, start, vec);
   len = VectorNormalize (vec);

   if (type < 128)
      dec = 3;
   else
   {
      dec = 1;
      type -= 128;
   }

   while (len > 0)
   {
      len -= dec;

Distance is obviously not working correctly in this case.

What I think may be the root of Spike's problem is that the default QW timer is integer millisecond, so at really high FPS it doesn't have sufficient precision for measurements to remain valid. As soon as you go over 500 FPS you're effectively getting a delta time of 0ms. No movement = no distance = no particles.

Pulling the generation rate back to 72 FPS allows precision errors to largely (but not totally) cancel out instead of accumulate. Another option might be to use the trick I posted elsewhere of using QPC (or any other higher resolution timer) to fill in the gaps between milliseconds.
Like the fifth day of playing 24-hour Scrabble when you don't want to use any letters because each one means a world to you because you're so deranged.
<<

qbism

User avatar

Posts: 788

Joined: Thu Nov 04, 2004 5:51 am

Post Thu May 19, 2011 5:14 pm

1. Gravity fix the engine.

2. Where possible, replace framerate dependent effects with time-dependent effects (Distance is time dependent, but not always possible to replace)

3. Set physics to 20 fps.

---->Profit!
<<

mh

User avatar

Posts: 2172

Joined: Sat Jan 12, 2008 1:38 am

Post Thu May 19, 2011 6:13 pm

OK, I was talking rubbish. I've managed to reproduce Spike's error, and it's nothing to do with timer precision. ;)

This description is for NQ, but I assume that QW does something reasonably similar.

On a frame when the server runs we get a full read on the client.
On a frame when it doesn't run we get no read on the client.
In both cases CL_RelinkEntities (which generates particle trails) runs.

If the client is running faster than the server, the entity remains on the client but it's new origin doesn't get updated. In order to generate a particle trail we need to:

- Copy current origin to old origin.
- Advance current origin by the lerp position determined by CL_LerpPoint.
- Generate particles between the two points.

However, if the client is running really really really fast, the difference between old origin and current origin will be negligible on successive client frames; at least for the purpose of generating particles.

Soooo... how about this?

- Check for particle trail effects in CL_ParseUpdate instead of in CL_RelinkEntities.
- if ((bits & U_ORIGIN1) || (bits & U_ORIGIN2) || (bits & U_ORIGIN3)) generate particles.
- use ent->msg_origins[0] and ent->msg_origins[1] as the start and end points (or should that be the other way around?)
Like the fifth day of playing 24-hour Scrabble when you don't want to use any letters because each one means a world to you because you're so deranged.
<<

mh

User avatar

Posts: 2172

Joined: Sat Jan 12, 2008 1:38 am

Post Thu May 19, 2011 6:32 pm

OK, that works perfectly. It's also good for different values of host_framerate (or host_timescale if you have it).

Get rid of all the R_RocketTrail calls from CL_RelinkEntities and pop this at the very bottom (after the if (forcelink) block) of CL_ParseUpdate:

  Code:
   // wait till here before parsing the particle trails as forcelink could update origins too
   if (((bits & U_ORIGIN1) || (bits && U_ORIGIN2) || (bits & U_ORIGIN3)) && ent->model)
   {
      // start used oldorg in the original code so it should use msg_origins[1] here
      if (ent->model->flags & EF_GIB)
         R_RocketTrail (ent->msg_origins[1], ent->msg_origins[0], 2);
      else if (ent->model->flags & EF_ZOMGIB)
         R_RocketTrail (ent->msg_origins[1], ent->msg_origins[0], 4);
      else if (ent->model->flags & EF_TRACER)
         R_RocketTrail (ent->msg_origins[1], ent->msg_origins[0], 3);
      else if (ent->model->flags & EF_TRACER2)
         R_RocketTrail (ent->msg_origins[1], ent->msg_origins[0], 5);
      else if (ent->model->flags & EF_ROCKET)
         R_RocketTrail (ent->msg_origins[1], ent->msg_origins[0], 0);
      else if (ent->model->flags & EF_GRENADE)
         R_RocketTrail (ent->msg_origins[1], ent->msg_origins[0], 1);
      else if (ent->model->flags & EF_TRACER3)
         R_RocketTrail (ent->msg_origins[1], ent->msg_origins[0], 6);
   }


Not sure what to do with R_EntityParticles yet; the function looks quite evil to my eyes. The particles are obviously only intended to last for one frame, but at high FPS they'll last for 10s or more frames. I'd add a pt_kill type which sets p->die to -1 and set their initial p->die to something high, then maybe spawn them from R_DrawEntitiesOnList, perhaps.
Like the fifth day of playing 24-hour Scrabble when you don't want to use any letters because each one means a world to you because you're so deranged.
<<

r00k

Posts: 902

Joined: Sat Nov 13, 2004 10:39 pm

Post Sun May 22, 2011 7:47 am

Actually, I chunked the EF_ dynamic lights in there too!

Return to Programming Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Icons provided by Aha Soft