CSQC entity update interpolation
Moderator: InsideQC Admins
5 posts
• Page 1 of 1
CSQC entity update interpolation
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.
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...
- 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
-

Urre - Posts: 1109
- Joined: Fri Nov 05, 2004 2:36 am
- Location: Moon
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.
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
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
-

Urre - Posts: 1109
- Joined: Fri Nov 05, 2004 2:36 am
- Location: Moon
Okay it seems like I got it now, finally understood what you meant Spike, thanks!
Here's the code for anyone who's interested
Obviously this only works if server framerate is constant. I think.

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
-

Urre - Posts: 1109
- Joined: Fri Nov 05, 2004 2:36 am
- Location: Moon
5 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 1 guest