RigidBody interpolation and bezier/custom movements.

Hey there.

I want ot use RigidBody for my game to benefit from the accuracy of fixed timestep collision and movement with the smoothness of interpolated coordinates, but I’m having issue to have this interpolation with custom movements, like following a bezier path, as my movement became all shaky.

How can I make the rigidbody follow my bezier path and have the interpolation effect?

Something like with this script :

	float m_delay = 3f;
	float m_timer = 0f;
	void FixedUpdate()
	{
		m_timer += Time.fixedDeltaTime;
		transform.position = bezierPath.PositionAt(m_timer/m_delay);
	}

I’d like the rigidBody position to be interpolated with its last know position from the previous frame, so that the animation is smooth, but with the accuracy of the unity physics computing.

How do I do that?

Anyone to help me with this? Whatever I try, it keep moving shakly. I tried transform.position, I tried rigidbody.position, I tried rigidbody.MovePosition, I tried isKinematic, but still don’t work…

Is your object colliding with something while you are updating it’s position? Collisions and modifying position directly don’t mix. Collisions can react incorrectly when you do this. Impulse forces can be exaggerated, sometimes collisions might be missed entirely. To avoid those problems you need to move the object via the force methods: AddForce(), AddTorque(), etc. This, of course, makes following a path considerably more difficult. This is no longer a simple matter of interpolation. To solve this problem, you need to dive into control theory.

A PID controller can be used for path following and is not difficult to implement. When I get home tonight, I can post my PID method and show you how to use it for path following, though I believe I’ve posted it on these forums before.

Don’t the “isKinematic” solve the problem about collisions? My object is not meant to collide, but to trigger.

Yes, if isKinematic is enabled, then all external forces, including collision forces, are ignored. Can you post your Bézier code?

The Bezier is a path object composed of multiple node. The “PositionAt” method return a point on the path, using a value between 0 (start of the path) and 1 (end of the curve)

Here is the main parts of the path code :

Bezier2D.cs

using UnityEngine;
using System.Collections;

public class Bezier2D {
	public static Vector2 Point(Vector2 a, Vector2 b, Vector2 c, Vector2 d, float t)
	{
 		Vector2 C1 = ( d - (3f * c) + (3f * b) - a );
    	Vector2 C2 = ( (3f * c) - (6f * b) + (3f * a) );
    	Vector2 C3 = ( (3f * b) - (3f * a) );
    	Vector2 C4 = ( a );
		
		return C1*t*t*t + C2*t*t + C3*t + C4;
	}
}

SplinePath.cs

using UnityEngine;
using System.Collections;

public class SplinePath : MonoBehaviour {
	
	public Vector2 PositionAt(float t)
	{		
		if(transform.childCount == 0)
			return transform.position;
		
		if(transform.childCount == 1 || t < 0f)
			return transform.GetChild (0).position;
		
		if(t > 1f)
			return transform.GetChild (transform.childCount - 1).position;
		
		if(transform.childCount == 2)
		{
			SplineNode first = transform.GetChild (0).GetComponent (typeof(SplineNode)) as SplineNode;
			SplineNode last = transform.GetChild (1).GetComponent (typeof(SplineNode)) as SplineNode;
			
			if(first == null || last == null)
				return transform.position;
			return Bezier3D.Point (first.transform.position, first.Out, last.In, last.transform.position, t);
		}
		
		// Search method
		int numSections = transform.childCount - 1;
		int currPt = Mathf.Min(Mathf.FloorToInt(t * (float) numSections), numSections - 1);
		float u = t * (float) numSections - (float) currPt;
		
		
		SplineNode start = transform.GetChild (currPt).GetComponent (typeof(SplineNode)) as SplineNode;
		SplineNode end = transform.GetChild (currPt + 1).GetComponent (typeof(SplineNode)) as SplineNode;
		
		return Bezier2D.Point (
			new Vector2(start.transform.position.x, start.transform.position.y)
			, new Vector2(start.Out.x, start.Out.y)
			, new Vector2(end.In.x, end.In.y)
			, new Vector2(end.transform.position.x, end.transform.position.y)
			, u);
	}
}

SplineNode.cs

using UnityEngine;
using System.Collections;

public class SplineNode : MonoBehaviour {
	
	public Vector3 In
	{
		get {return transform.position + m_in;}
		set {
			m_in = value - transform.position;
			if(tangent)
			{
				m_out = -m_in;
			}
		}
	}
	
	public Vector3 Out
	{
		get{return transform.position + m_out;}
		set{
			m_out = value - transform.position;
			if(tangent)
			{
				m_in = -m_out;
			}
		}
	}
	
	public Vector3 LocalIn
	{
		get{return m_in;}
		set{
			m_in = value;
			if(tangent)
			{
				m_out = -m_in;
			}
		}
	}
	
	public Vector3 LocalOut
	{
		get{return m_out;}
		set{
			m_out = value;
			if(tangent)
			{
				m_in = -m_out;
			}
		}
	}
	
	static Color inNodeColor = Color.red;
	static Color outNodeColor = Color.blue;
	public bool tangent = true;
	
	[SerializeField]
	Vector3 m_in = new Vector3(0.5f, 0.5f, 0f);
	
	[SerializeField]
	Vector3 m_out = new Vector3(-0.5f, -0.5f, 0f);
}

Another example :

I’m trying to move a ship from a shoot’em up game through the rigidbody and trying to use the interpolation.

So I wrote this code in my PlayerShip script :

void FixedUpdate()
	{	
		Vector3 linearVelocity = Vector3.zero;
		
		if(Input.GetAxisRaw("Horizontal") < 0f)
		{
			linearVelocity.x = -speed;
		}
		else if(Input.GetAxisRaw("Horizontal") > 0f)
		{
			linearVelocity.x = speed;
		}
		
		if(Input.GetAxisRaw("Vertical") < 0f)
		{
			linearVelocity.y = -speed;
		}
		else if(Input.GetAxisRaw("Vertical") > 0f)
		{
			linearVelocity.y = speed;
		}
		
		if(linearVelocity.x != 0f  linearVelocity.y != 0f)
		{
			linearVelocity *= 0.707107f;
		}
		
		Vector3 newPosition = rigidbody.position + linearVelocity * Time.fixedDeltaTime;
		rigidbody.MovePosition(newPosition);
	}

Simply, depending on the direction the stick is moved to, we move the rigidbody position, with the isKinematic property to true and the Interpolation to Interpolate.

I followed the example from the doc : Unity - Scripting API: Rigidbody.MovePosition

The fact is in Interpolate, my ship move slower than it should, in Extrapolate it move faster… What did I do wrong?

Note I used fixedDeltaTime instead of deltaTime, but for both the movement is still too slow and shaky.

Still no ideas? :frowning:

Sorry for not replying sooner, I was a little busy.

Your code looks fine, I don’t see anything wrong with it. Now I think what you’re rubbing up against is just sync jitter.

You’re already aware that the physics loop and the game/display loop are essentially independent and run at different rates. The physics loop operates at a fixed rate, which is 0.02 seconds per iteration by default. The game loop, on the other hand, has no speed limitation and runs as fast as it can pump out frames unless it is specifically limited to a maximum frame rate in the application settings. If the physics loop is running slower than the game loop, then objects controlled by the physics engine may not be updated every frame. This can easily result in “vibrations” in those objects if your camera or other objects are being controlled in the game loop at a different update rate.

There are a few ways to reduce the effects of sync jitter. Ideally, the physics loop and game loop should operate at the same rate. You can change the physics engine’s fixed timestep in Edit->Project Settings->Time to be closer to the game loop’s expected time step. However, this is not always easy to predict beforehand, and reducing the fixed timestep increases the amount of work that the physics loop performs and this will reduce the game’s overall performance. Another thing you can do is adjust the game loop’s target frame rate by modifying Application.targetFrameRate. You may be able to find an acceptable balance between the physics engine’s rate and the game loop’s rate by adjusting these values.

Be mindful of the rate that the position and orientation of all objects in the scene, including the camera, are being updated at. For example… If your camera is translating or rotating in the Update() loop, but you have kinematic objects being updated in FixedUpdate(), and if the physics loop is slower than the game loop (frame rate), then those kinematic objects will probably suffer from jittering. In this case, move the kinematic object’s code into Update(), or move the camera’s code into the FixedUpdate() call and see if things improve.

I’ve noticed in experiments that Rigidbody.MovePosition() and MoveRotation() don’t work with RigidBody interpolation. I don’t know if this is a bug or if it is working as intended. Interpolation only appears to work if the object is being moved via force methods (i.e. AddForce(), AddTorque(), etc… ), in which case Rigidbody.isKinematic must be false.

I hope some of this advice is useful. I might throw together an app that demonstrates sync jitter, the reason it happens, and its solutions.

What I though, and it is what I did in my personal C++ game engine, is the following :

1049057--38966--$timestep.png

Update() update at each frame, but before, we do as many fixed update we need to cover the time the Update() took, and we interpolate between the last two fixed update frames. The alpha value resulting from the interpolation is used to interpolate the object between it’s position at t and its position at t-1.

I did it in my game engine, it was smooth, beautifull and the physics was precise. I’d like to reproduce the same behaviour in Unity. I though it was already working like that with the rigidbody, but apparently it’s not.

I joined the conversation on Unity Answer here :

If we could joint these two topics, it would help get more… help. :stuck_out_tongue: