http://forums.inside3d.com/viewtopic.php?t=2387
But after adding, you'll twice as much want movement interpolation to complete the circle.
How good is MH's software renderer interpolation? It is very, very fast ...
Anyway, software animation interpolation smooths the model animations, but the movement interpolation smooths the movement.timedemo demo1
No animation interpolation @ 320x200 fullscreen my machine: 285 FPS
With animation interpolation @ 320x200 fullscreen my machine: 281 FPS
Movement Interpolation - Tutorial Begin ...
And this is pretty much verbatim derived from MH's DirectQ engine.
1. cl_main.c
Go to CL_RelinkEntities ... I have the necessary additions marked with #ifdef SUPPORTS_SOFTWARE_ANIM_INTERPOLATION
Code: Select all
// if the object wasn't included in the last packet, remove it
if (ent->msgtime != cl.mtime[0])
{
#ifdef SUPPORTS_SOFTWARE_ANIM_INTERPOLATION
CL_ClearInterpolation (ent);
#endif
ent->model = NULL;
continue;
}
Code: Select all
f = frac;
for (j=0 ; j<3 ; j++)
{
delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];
if (delta[j] > 100 || delta[j] < -100)
f = 1; // assume a teleportation, not a motion
}
#ifdef SUPPORTS_SOFTWARE_ANIM_INTERPOLATION
if (f >= 1) CL_ClearInterpolation (ent);
#endif
// interpolate the origin and angles
for (j=0 ; j<3 ; j++)
{
ent->origin[j] = ent->msg_origins[1][j] + f*delta[j];
d = ent->msg_angles[0][j] - ent->msg_angles[1][j];
if (d > 180)
d -= 360;
else if (d < -180)
d += 360;
ent->angles[j] = ent->msg_angles[1][j] + f*d;
}
}
// if (!(model = cl.model_precache[ent->modelindex]))
// Host_Error ("CL_RelinkEntities: bad modelindex");
#ifdef SUPPORTS_SOFTWARE_ANIM_INTERPOLATION
CL_EntityInterpolateOrigins (ent);
CL_EntityInterpolateAngles (ent);
#endif
// rotate binary objects locally
if (ent->model->flags & EF_ROTATE)
Code: Select all
int trivial_accept;
struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split
int modelindex;
#ifdef SUPPORTS_SOFTWARE_ANIM_INTERPOLATION
float frame_start_time;
int lastpose, currpose;
int lastframe;
// fenix@io.com: model transform interpolation
float translate_start_time;
vec3_t lastorigin, currorigin;
float rotate_start_time;
vec3_t lastangles, currangles;
#endif
} entity_t;
Code: Select all
#ifdef SUPPORTS_SOFTWARE_ANIM_INTERPOLATION
void CL_EntityInterpolateOrigins (entity_t *ent)
{
qboolean no_interpolate=false;
float timepassed = cl.time - ent->translate_start_time;
float blend = 0;
vec3_t delta = {0, 0, 0};
if (ent->translate_start_time == 0 || timepassed > 1)
{
ent->translate_start_time = cl.time;
VectorCopy (ent->origin, ent->lastorigin);
VectorCopy (ent->origin, ent->currorigin);
}
if (!VectorCompare (ent->origin, ent->currorigin))
{
ent->translate_start_time = cl.time;
VectorCopy (ent->currorigin, ent->lastorigin);
VectorCopy (ent->origin, ent->currorigin);
blend = 0;
}
else
{
blend = timepassed / 0.1;
if (cl.paused || blend > 1) blend = 1;
}
VectorSubtract (ent->currorigin, ent->lastorigin, delta);
// use cubic interpolation
{
float lastlerp = 2 * (blend * blend * blend) - 3 * (blend * blend) + 1;
float currlerp = 3 * (blend * blend) - 2 * (blend * blend * blend);
ent->origin[0] = ent->lastorigin[0] * lastlerp + ent->currorigin[0] * currlerp;
ent->origin[1] = ent->lastorigin[1] * lastlerp + ent->currorigin[1] * currlerp;
ent->origin[2] = ent->lastorigin[2] * lastlerp + ent->currorigin[2] * currlerp;
}
}
void CL_EntityInterpolateAngles (entity_t *ent)
{
float timepassed = cl.time - ent->rotate_start_time;
float blend = 0;
vec3_t delta = {0, 0, 0};
if (ent->rotate_start_time == 0 || timepassed > 1)
{
ent->rotate_start_time = cl.time;
VectorCopy (ent->angles, ent->lastangles);
VectorCopy (ent->angles, ent->currangles);
}
if (!VectorCompare (ent->angles, ent->currangles))
{
ent->rotate_start_time = cl.time;
VectorCopy (ent->currangles, ent->lastangles);
VectorCopy (ent->angles, ent->currangles);
blend = 0;
}
else
{
blend = timepassed / 0.1;
if (cl.paused || blend > 1) blend = 1;
}
VectorSubtract (ent->currangles, ent->lastangles, delta);
// always interpolate along the shortest path
if (delta[0] > 180) delta[0] -= 360; else if (delta[0] < -180) delta[0] += 360;
if (delta[1] > 180) delta[1] -= 360; else if (delta[1] < -180) delta[1] += 360;
if (delta[2] > 180) delta[2] -= 360; else if (delta[2] < -180) delta[2] += 360;
// get currangles on the shortest path
VectorAdd (ent->lastangles, delta, delta);
// use cubic interpolation
{
float lastlerp = 2 * (blend * blend * blend) - 3 * (blend * blend) + 1;
float currlerp = 3 * (blend * blend) - 2 * (blend * blend * blend);
ent->angles[0] = ent->lastangles[0] * lastlerp + delta[0] * currlerp;
ent->angles[1] = ent->lastangles[1] * lastlerp + delta[1] * currlerp;
ent->angles[2] = ent->lastangles[2] * lastlerp + delta[2] * currlerp;
}
}
void CL_ClearInterpolation (entity_t *ent)
{
ent->frame_start_time = 0;
ent->lastpose = ent->currpose;
ent->translate_start_time = 0;
ent->lastorigin[0] = ent->lastorigin[1] = ent->lastorigin[2] = 0;
ent->currorigin[0] = ent->currorigin[1] = ent->currorigin[2] = 0;
ent->rotate_start_time = 0;
ent->lastangles[0] = ent->lastangles[1] = ent->lastangles[2] = 0;
ent->currangles[0] = ent->currangles[1] = ent->currangles[2] = 0;
}
#endif
Code: Select all
// automatic animation (torches, etc) can be either all together or randomized
if (model)
ent->syncbase = (model->synctype == ST_RAND) ? (float)(rand()&0x7fff) / 0x7fff : 0.0;
else
forcelink = true; // hack to make null model players work
#ifdef SUPPORTS_SOFTWARE_ANIM_INTERPOLATION
// if the model has changed we must also reset the interpolation data
// lastpose and currpose are critical as they might be pointing to invalid frames in the new model!!!
CL_ClearInterpolation (ent);
// reset frame and skin too...!
if (!(bits & U_FRAME)) ent->frame = 0;
if (!(bits & U_SKIN)) ent->skinnum = 0;
#endif
Code: Select all
#ifndef GLQUAKE
#define SUPPORTS_SOFTWARE_ANIM_INTERPOLATION
#endif
Related:
Software Quake MDL Frame Interpolation
Nasty interpolation bug - and fix!
[edit = removed cvar remnant]