Forum

CSQC entity update interpolation

Discuss programming in the QuakeC language.

Moderator: InsideQC Admins

CSQC entity update interpolation

Postby Urre » Tue Jan 04, 2011 12:52 pm

So, like, a while back I learned that I need to simulate having the same framerate as server on csqc, to get correct physics. I got that part working fine it seems, but I'm having trouble figuring out how to interpolate between the current and previous physics update.

Code: Select all
void() UpdateEntities =
{
   local float f;
   local vector v;
   local entity ent;

   sys_ticrate = getstatf(STAT_MOVEVARS_TICRATE);
   ent = nextent(world);
   while (ent)
   {
      if (ent.solid)
      {
         if (time > ent.timer_phys + sys_ticrate)
         {
            ent.origin_old = ent.origin_phys;
            while (time > ent.timer_phys + sys_ticrate)
            {
               ent.timer_phys = ent.timer_phys + sys_ticrate;
               ent.origin_phys = ent.origin_phys + ent.velocity*sys_ticrate;
               te_gunshot(ent.origin_phys);
            }
         }
         slowmo = cvar("slowmo");
         //f = vlen(ent.origin-ent.origin_phys)/sys_ticrate;
         //v = ent.origin + ent.velocity*frametime*(1/sys_ticrate);
         ent.timer_r = ent.timer_r + frametime*(1/slowmo);
         f=min(1, ent.timer_r);
         if (ent.timer_r > 1)
            ent.timer_r = ent.timer_r - 1;
         v = ent.origin_old+(ent.origin_phys-ent.origin_old)*ent.timer_r;
         trailparticles(ent, ent.traileffect, ent.origin, v);
         setorigin(ent, v);
      }
      ent = nextent(ent);
   }
};


It's a bit messed up since I started testing various stuff, but yes... I'm feeling lost, it should be something along the lines of old origin + difference between new and old, times a value increasing from 0-1...
I was once a Quake modder
User avatar
Urre
 
Posts: 1109
Joined: Fri Nov 05, 2004 2:36 am
Location: Moon

Postby Spike » Tue Jan 04, 2011 3:40 pm

your server tick rate might be a constant, but your client framerate is likely not.
slowmo is hacked in there? surely the client scales csqc's time global to match the server (true client time is in the cltime global, 'time' is meant to correspond to the time on the server which the client will attempt to interpolate its regular entities to, that is, csqc's time field will be between the two valid network messages used for interpolation at that point in time, you can thus sync client time to server time, or something).

interpolation is:
frac = (time - oldtime)/rate;
org = (new-old)*frac + old;

note that you still need to deal with lerpfracs for rendering.
the predraw callback is useful for stuff like that.

Or, if you're able to use unique modelindexes, you can use this builtin instead:
void(string modelname, void(float isnew) updatefnc, float flags) deltalisten = #571;
Then the engine will call 'updatefnc' for you each frame, with an interpolated 'self', with frame interpolation done, and everything ready to go - it just needs to be added to the scene so set a drawmask, without the hassle of the csqc shared ent protocol.
There's a 'nointerpolate' flag for predicting players if the server's origins are important.
Spike
 
Posts: 2892
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Postby Urre » Tue Jan 04, 2011 5:15 pm

It's the rendering part I'm concerned with. How is interpolation different from lerpfrac?
I was once a Quake modder
User avatar
Urre
 
Posts: 1109
Joined: Fri Nov 05, 2004 2:36 am
Location: Moon

Postby Urre » Tue Jan 04, 2011 6:46 pm

So I revised it to be what I figure it should be, without all the debug crap as previously. It actually gives pretty close to correct results, but it has this odd pop between each time it updates the physics origin, like the rocket hops back to the previous old origin before starting to interpolate from the new old origin. It's practicly only visible in slowmo.

Code: Select all
void() UpdateEntities =
{
   local float f;
   local vector v;
   local entity ent;

   sys_ticrate = getstatf(STAT_MOVEVARS_TICRATE);
   ent = nextent(world);
   while (ent)
   {
      if (ent.solid)
      {
         if (time > ent.timer_phys + sys_ticrate)
         {
            ent.origin_old = ent.origin_phys;
            while (time > ent.timer_phys + sys_ticrate)
            {
               ent.timer_phys = ent.timer_phys + sys_ticrate;
               ent.origin_phys = ent.origin_phys + ent.velocity*sys_ticrate;
               te_gunshot(ent.origin_phys);
            }
         }
         ent.timer_r = ent.timer_r + frametime*(1/sys_ticrate);
         if (ent.timer_r > 1)
            ent.timer_r = ent.timer_r - 1;
         v = ent.origin_old+(ent.origin_phys-ent.origin_old)*ent.timer_r;
         trailparticles(ent, ent.traileffect, ent.origin, v);
         setorigin(ent, v);
      }
      ent = nextent(ent);
   }
};
I was once a Quake modder
User avatar
Urre
 
Posts: 1109
Joined: Fri Nov 05, 2004 2:36 am
Location: Moon

Postby Urre » Tue Jan 04, 2011 7:26 pm

Okay it seems like I got it now, finally understood what you meant Spike, thanks!

Here's the code for anyone who's interested
Code: Select all
void() UpdateEntities =
{
   local float f;
   local vector v;
   local entity ent;

   sys_ticrate = getstatf(STAT_MOVEVARS_TICRATE);
   ent = nextent(world);
   while (ent)
   {
      if (ent.solid)
      {
         if (time > ent.timer_phys + sys_ticrate)
         {
            ent.origin_old = ent.origin_phys;
            while (time > ent.timer_phys + sys_ticrate)
            {
               ent.timer_phys = ent.timer_phys + sys_ticrate;
               ent.origin_phys = ent.origin_phys + ent.velocity*sys_ticrate;
            }
         }
         ent.timer_r = (time-ent.timer_phys)/sys_ticrate;
         v = ent.origin_old+(ent.origin_phys-ent.origin_old)*ent.timer_r;
         trailparticles(ent, ent.traileffect, ent.origin, v);
         setorigin(ent, v);
      }
      ent = nextent(ent);
   }
};


Obviously this only works if server framerate is constant. I think.

;)
I was once a Quake modder
User avatar
Urre
 
Posts: 1109
Joined: Fri Nov 05, 2004 2:36 am
Location: Moon


Return to QuakeC Programming

Who is online

Users browsing this forum: No registered users and 1 guest