in Networked Physics/Assets/Scripts/JitterBuffer.cs [136:251]
public bool GetInterpolatedAvatarState( ref AvatarState[] output, out int numOutputAvatarStates, out ushort resetSequence )
{
numOutputAvatarStates = 0;
resetSequence = 0;
// if interpolation frame is negative, it's too early to display anything
double interpolation_frame = initial_frame + time * Constants.PhysicsFrameRate;
if ( interpolation_frame < 0.0 )
return false;
// if we are interpolating but the interpolation start frame is too old,
// go back to the not interpolating state, so we can find a new start point.
const int n = 16;
if ( interpolating )
{
long frame = (long) Math.Floor( interpolation_frame );
if ( frame - interpolation_start_frame > n )
interpolating = false;
}
// if not interpolating, attempt to find an interpolation start point.
// if start point exists, go into interpolating mode and set end point to start point
// so we can reuse code below to find a suitable end point on first time through.
// if no interpolation start point is found, return.
if ( !interpolating )
{
long current_frame = (uint) Math.Floor( interpolation_frame );
for ( long frame = current_frame + 1; ( frame > current_frame - n ) && ( frame >= 0 ); frame-- )
{
JitterBufferEntry entry = GetEntry( (uint) frame );
if ( entry != null )
{
double avatar_sample_time = ( frame - initial_frame ) * ( 1.0 / Constants.PhysicsFrameRate ) + entry.packetHeader.avatarSampleTimeOffset;
if ( time >= avatar_sample_time && time <= avatar_sample_time + ( 1.0f / Constants.PhysicsFrameRate ) )
{
interpolation_start_frame = frame;
interpolation_end_frame = frame;
interpolation_start_time = avatar_sample_time;
interpolation_end_time = avatar_sample_time;
interpolating = true;
}
}
}
}
if ( !interpolating )
return false;
Assert.IsTrue( time >= interpolation_start_time );
// if current time is >= end time, we need to start a new interpolation
// from the previous end time to the next sample that exists up to n samples ahead.
if ( time >= interpolation_end_time )
{
interpolation_start_frame = interpolation_end_frame;
interpolation_start_time = interpolation_end_time;
for ( int i = 0; i < n; ++i )
{
JitterBufferEntry entry = GetEntry( (uint) ( interpolation_start_frame + 1 + i ) );
if ( entry != null )
{
double avatar_sample_time = ( interpolation_start_frame + 1 + i - initial_frame ) * ( 1.0 / Constants.PhysicsFrameRate ) + entry.packetHeader.avatarSampleTimeOffset;
if ( avatar_sample_time >= time )
{
interpolation_end_frame = interpolation_start_frame + 1 + i;
interpolation_end_time = avatar_sample_time + ( 1.0 / Constants.PhysicsFrameRate );
break;
}
}
}
}
// if current time is still > end time, we couldn't start a new interpolation so return.
if ( time > interpolation_end_time )
return false;
// we are in a valid interpolation, calculate t by looking at current time
// relative to interpolation start/end times and perform the interpolation.
float t = (float) Clamp( ( time - interpolation_start_time ) / ( interpolation_end_time - interpolation_start_time ), 0.0, 1.0 );
JitterBufferEntry a = GetEntry( (uint) ( interpolation_start_frame ) );
JitterBufferEntry b = GetEntry( (uint) ( interpolation_end_frame ) );
for ( int i = 0; i < a.numAvatarStates; ++i )
{
for ( int j = 0; j < b.numAvatarStates; ++j )
{
if ( a.avatarState[i].client_index == b.avatarState[j].client_index )
{
AvatarState.Interpolate( ref a.avatarState[i], ref b.avatarState[j], out output[numOutputAvatarStates], t );
numOutputAvatarStates++;
}
}
}
resetSequence = a.packetHeader.resetSequence;
return true;
}