How to move a kinematic rigidbody smoothly?

I’m about to write my own physics instead of using the build-in system because of this. Quick responses are highly appreciated.

EXAMPLE
Copy the script below and attach it to a plain GameObject in an empty scene.

WHAT YOU SEE
Object 1: Moving by setting transform.position from Update.
Object 2: Moving by calling rigidbody.MovePosition from FixedUpdate (isKinematic+Extrapolate).
Object 3: Moving by calling rigidbody.MovePosition from FixedUpdate (isKinematic).

Object 1: Moves smoothly.
Object 2: Moves not so smoothly.
Object 3: Moves like my grandmother.

QUESTION
How to move a kinematic rigidbody smoothly? Is it possible at all in Unity? And if not, why?

using UnityEngine;

public class JitterExample : MonoBehaviour
{
 GameObject object1, object2, object3, object4;
 
 const int MOVE_SPAN = 5;
 const float SPEED = 2f;
 
 
 void Start()
 {
 object1 = GameObject.CreatePrimitive( PrimitiveType.Cube );
 object1.name = "Object1";
 
 object2 = GameObject.CreatePrimitive( PrimitiveType.Cube );
 object2.name = "Object2";
 object2.AddComponent<Rigidbody>();
 object2.rigidbody.isKinematic = true;
 object2.rigidbody.interpolation = RigidbodyInterpolation.Extrapolate;
 
 object3 = GameObject.CreatePrimitive( PrimitiveType.Cube );
 object3.name = "Object3";
 object3.AddComponent<Rigidbody>();
 object3.rigidbody.isKinematic = true;
 
 Camera.main.orthographic = true;
 Camera.main.orthographicSize = 5;
 Camera.main.transform.position = new Vector3( MOVE_SPAN * SPEED * 0.5f, 0, -5 );
 
 RenderSettings.ambientLight = Color.black;
 }
 
 
 void Update()
 {
 object1.transform.position = new Vector3( Mathf.PingPong( Time.time, SPEED ) * MOVE_SPAN, 2, 0 );
 }
 
 
 void FixedUpdate()
 {
 object2.rigidbody.MovePosition( new Vector3( Mathf.PingPong( Time.time, SPEED ) * MOVE_SPAN, 0, 0 ) );
 object3.rigidbody.MovePosition( new Vector3( Mathf.PingPong( Time.time, SPEED ) * MOVE_SPAN, -2, 0 ) );
 }
 
 
 void OnGUI()
 {
 GUILayout.Label( "WHAT YOU SEE" );
 GUILayout.Label( "	Object 1: Moving by setting transform.position from Update." );
 GUILayout.Label( "	Object 2: Moving by calling rigidbody.MovePosition from FixedUpdate (isKinematic+Extrapolate)." );
 GUILayout.Label( "	Object 3: Moving by calling rigidbody.MovePosition from FixedUpdate (isKinematic)." );
 GUILayout.Space( 20 );
 GUILayout.Label( "QUESTION" );
 GUILayout.Label( "How to move a kinematic rigidbody smoothly?" );
 }
}

The simple answer is: Don’t use FixedUpdate. FixedUpdate was never ment to provide a smooth call rate. It just “fixes” framerate fluctuations to have a statistically constant call-rate. (another use for my FixedUpdate simulator :smiley: ).

FixedUpdate is important for non-linear calculations (like acceleration) because such calculations can’t be scaled with deltaTime. All linear stuff (which is the most stuff) should be done in Update and “fixed” with Time.deltaTime.

If you really need to move it in FixedUpdate (for interactions with normal rigidbodies) you might want to increase the FixedUpdate rate (lower the fix-timestep).

I don’t know if it existed in 2012, but there is also the .Interpolate option, which interpolates between the current and the previous position of the rigidbody.

However, for me, that did not help either. I’m currently running into similar problems using rigidbodies, where I slow down the time of an object. I execute an update function that calculates acceleration/velocity/position whenever the local time exceeds the physics update interval. I apply the position using MovePosition. However, the rigidbody does not interpolate properly between frames, because it thinks the object pauses between frames.

Since the rigidbody moves the gameobject (and this messes with interpolation), I have detached the physics object from the visual object, so I can do the interpolation myself. I don’t know whether this is good or bad design, but I do feel like this is not entirely the way Unity was meant to be used. It works just fine, though.

48528-detached-structure.png

The interpolation source code as was requested:

protected virtual void LateUpdate()
{
	if (!_positionComponent) return;

	switch (PositioningMethod)
	{
	case EPositioningMethod.ExtrapolateWithVelocity:

		// if no move component, don't do interpolation
		if (!_moveComponent)
			goto case EPositioningMethod.UpdateWithPositionComponentTransform;

		_extrapolateWithVelocity();

		break;

	case EPositioningMethod.InterpolateWithPreviousPosition:

		if (!_moveComponent)
			goto case EPositioningMethod.UpdateWithPositionComponentTransform;

		_interpolateWithPrevPosition();

		break;

	case EPositioningMethod.UpdateWithPositionComponentTransform:

		transform.position = _positionComponent.transform.position + _offset;

		break;

	case EPositioningMethod.UserDefined:
		break;

	case EPositioningMethod.InitWithPositionComponentTransform:

		// just set position once
		if (!_initPosition)
		{
			transform.position = _positionComponent.Position + _offset;
			_initPosition = true;
		}
		break;
	default:
		// default case is no smoothing (but still setting position)
		goto case EPositioningMethod.UpdateWithPositionComponentTransform;
	}
}

void _interpolateWithPrevPosition()
{
	float timeToInterpolate = View.GetUnscaledFixedDeltaTime();
	if (_moveComponent.Position + _offset != _lastFixedPosition)
	{
		_lastCurrentPosition = transform.position;
		_lastFixedPosition = _moveComponent.Position + _offset;
		_t = 0;
		//transform.position = _lastFixedPosition;
	}
	else
	{
		if (_t < timeToInterpolate)
			_t += View.GetDeltaTime();
		if (_t > timeToInterpolate)
			_t = timeToInterpolate;

		transform.position = Vector3.Lerp(_lastCurrentPosition, _lastFixedPosition, _t / timeToInterpolate);
	}
}

void _extrapolateWithVelocity()
{
	if (_moveComponent.Position + _offset != _lastFixedPosition)
	{
		_lastFixedPosition = _moveComponent.Position + _offset;
		transform.position = _lastFixedPosition;
	}
	else
		transform.position += _moveComponent.Velocity * View.GetDeltaTime();
}

My question was answered on the forum. Sorry I forgot to link the two posts:

http://forum.unity3d.com/threads/142516-Kinematic-rigid-bodies-does-not-move-smoothly-with-MovePosition

I ended up solving the problem by increasing the fixed update rate, thereby taking a considerable performance hit.