B-Splines

I been trying to make some camera animation stuff and for the purpose i been using the MoveCamera and CameraWaypoint scripts found here on the forum which is nice, but i found the problem of aligning the waypoints so tangents give smooth animation on turns and stuff has been abit painfull, so i decided to look into another way and stumbled upon B-Splines and from the looks of it that was what i wanted so i trew together these simple scripts which creates the b-spline setup from waypoints in the editor and it comes with editor gizmo visualization aswell.

I thought i would post it here as it might be usefull to other ppl aswell, so here goes:

Still on my TODO list:

  1. Good way to let camera follow the splines
  2. Implement rotation interpolation aswell along the splines or static focus.
  3. Error profing and testing

The implementation is basically a port of the C++ source found here:

Regards,
Marc

using UnityEngine;
using System.Collections;

public class BSpline : MonoBehaviour {

	public int n = 2; // Degree of the curve
	
	public BSplineControlPoint[] controlPoints; // The control points.
	
	private Vector3[] cachedControlPoints; // cached control points
	private int[] nV; // Node vector
	
	void Start()
	{
		cachedControlPoints = new Vector3[controlPoints.Length];
		
		CacheControlPoints();
		
		nV = new int[cachedControlPoints.Length + 5];
		
		createNodeVector();
		
	}
	
	// Recursive deBoor algorithm.
	public Vector3 deBoor(int r, int i, float u)
	{
		
		if(r == 0)
		{
			return cachedControlPoints[i];
		}
		else
		{
			
			float pre = (u - nV[i + r]) / (nV[i + n + 1] - nV[i + r]); // Precalculation
			return ((deBoor(r - 1, i, u) * (1 - pre)) + (deBoor(r - 1, i + 1, u) * (pre)));
			
			
		}
		
	}
	
	public void createNodeVector()
	{
		int knoten = 0;
			
		for(int i = 0; i < (n + cachedControlPoints.Length + 1); i++) // n+m+1 = nr of nodes
		{
			if(i > n)
			{
				if(i <= cachedControlPoints.Length)
				{
					
					nV[i] = ++knoten;
				}
				else
				{
					nV[i] = knoten;
				}
			}
			else {
				nV[i] = knoten;
			}
		}
	}
	
	private void CacheControlPoints()
	{
		
		for(int i = 0; i < controlPoints.Length; i++)
		{
			cachedControlPoints[i] = controlPoints[i].cachedPosition;
		}
		
	}
	
	void OnDrawGizmos()
	{
		
		if(controlPoints.Length <= 0) return;
		
		cachedControlPoints = new Vector3[controlPoints.Length];
		
		// Cached the control points
		CacheControlPoints();
		
		if(cachedControlPoints.Length <= 0) return;
		
		// Initialize node vector.
		nV = new int[cachedControlPoints.Length + 5];
		createNodeVector();
		
		
		// Draw the bspline lines
		Gizmos.color = Color.gray;
		
		Vector3 start = cachedControlPoints[0];
		Vector3 end = Vector3.zero;
		
		for(float i = 0.0f; i < nV[n + cachedControlPoints.Length]; i += 0.1f)
		{
			
			for(int j = 0; j < cachedControlPoints.Length; j++)
			{
				if(i >= j)
				{
					end = deBoor(n, j, i);
				}
			}
	
			Gizmos.DrawLine(start, end);
			start = end;
			
		}
	
	}
	
	
}
using UnityEngine;
using System.Collections;

public class BSplineControlPoint : MonoBehaviour {

	public Color color = Color.red;
	
	[HideInInspector]
	public Vector3 cachedPosition;
	
	void Start()
	{
		cachedPosition = transform.position;
	}
	
	void OnDrawGizmos()
	{
		
		cachedPosition = transform.position;
		
		// Draw control point
		Gizmos.color = color;
		Gizmos.DrawSphere(cachedPosition, 0.1f);
		
	}
	
}

Very nice.

Very cool indeed! Please consider adding it to the wiki;

http://www.unifycommunity.com/wiki/index.php

There is an existent Spline Controller, however upon cursory glance, each has it’s own merits.

Excellent Job

good work. keep it up. looking forward to see where you go with this.

cheers.

Thanks all.

I look a little more around in the books hovering at my selves and found this book: “Essential Mathematics for Games Interactive Applications” by James M. Van Verth and Lars M. Bishop.

It actually came with some c++ source for implementation of Uniform B-splines, so i went ahead and did some porting of that code to. Here i managed to actually make a mover that follows the spline aswell :smile:

Included in the zip are 3 C# scripts:

  1. UniformBSpline - The actual spline
  2. UniformBSplineControlPoint - Control point script.
  3. UnifromBSplineMover - The script will move the object its attached to along the spline assigned to the mover.

The mover even comes with a play once, ping pong and loop setting that actually works 8)

You can define the time it should take to travel the spline aswell.

You can also define the color of the spline path in the editor making it easy for you to differentiate between different spline paths.

TODO:

  1. Error testing
  2. Im not entirely convinced that the object is travelling at constant speed along the spline path, but for now it can do what i was after.

For now the project it put on hold, but feel free to improve.

Suggestions apreciated.

Regards,
Marc

84119–3266–$bsplines_105.zip (2.41 KB)

Hi Marc,

I’m having trouble getting this to work. I created a new project and attached UniformBSpline.cs to an empty in the scene. I then created a series of empties and attached UniformBSplineControlPoint.cs to each. Then I added a box to the scene and attached UniformBSplineMover.cs to that. I then set up the variables in the scripts. I can see that each of the control points are displayed in the editor as a red dot. But I don’t see a spline and when I run the project the box just goes to the first control point. What am I setting up incorrectly?

Thanks!

Oops forgot to initialize some variables in the UniformBSpline script. Find startTime and endTime and initialize them like this, then it should work.

startTime = 0.0f;
endTime = 1.0f;

I updated the uploaded files to.

I think I’m setting it up incorrectly, here’s a screenshot of how I have the scene organized. I’m not seeing the b-spline and the mover (box) isn’t following a b-spline.

Nope you set it up correctly. If you open the UniformBSpline script file, you will see that there are two public varaibles named startTime and endTime that have the [HideInInspector] tag. Either remove that tag and set their values to

startTime = 0.0f;
endTime = 1.0f;

or add the values to the script and remove the component and add it again, for the changes to update (or maybe reset the component)

It should work then.

I have an example project lying about, but its running on a beta version of unity, so i better not post it yet :smile:

Ok, I’ve got it working now, thanks Marc.

It definitely looks like the object is accelerating / decelerating from / to the end points (which looks very nice actually). A couple things I think would be nice additions would be object rotation / orientation and “continuous” curve (ie. a circle) option. I might try to convert this to JS since I’m a bit more comfortable with that.

Very nicely done Marc and thanks for your help!

Just a couple of observations about this:-

  • Quadratic (ie, degree == 2) curves have two main problems: the curve between any three consecutive points lies in a single plane and the acceleration of the curve doesn’t behave in a controllable way (yes, you are right, the motion is not constant speed, in fact it is quite physically realistic). Simply setting the degree to 3 will solve these problems.

  • The recursive technique is intended mainly as a method for drawing curves and doesn’t really lend itself very well to animation. To animate along a path, it is usually easier to use the parametric formula and pass in a value from 0 to 1, indicating where along the length of the curve you want to be. It is also easier to determine the speed and direction of the curve at the chosen point with the parametric approach.

If you want a good reference for this (and many other graphical techniques), Foley and van Dam’s “Computer Graphics: Principles and Practice” is the book I would recommend.

Thanks for the tip, didnt know that.

This is what the uploaded scripts are using (and why i actually ported those) :smile:

Thanks, will see if i can find that somewhere.

Resurrecting this thread. How would I make my object travel the path at a constant/controllable speed?

With this code as it stands, there isn’t any way to do it. The easiest way would be to use the Velocity function, but this isn’t fully implemented - it just returns Vector3.zero every time.

I calculate the velocity vector to set the direction of my craft to be pointing in the direction its moving.

private IEnumerator Move()
	{
		
		for(float t = 0.0f; t < 1.0f; t += Time.deltaTime * (1/time))
		{
			transform.position = path.Evaluate(t); 
			
			currentPosition = this.transform.position;
			previousPosition = path.Evaluate(t-(Time.deltaTime * (1/time)));
			dir = currentPosition - previousPosition;
			dir.Normalize();
			this.transform.forward = dir;

			yield return 0;
		}
		
		transform.position = path.Evaluate(1.0f);
		
	}

So I guess dir is my velocity vector. I am just not sure how to use this.

I am making a racing game (aircrafts) and trying to do AI using this code. I have a nice spline setup across the track. Ideally I would want to control the speed of the AI craft and maybe make it so its not exactly on the path but X units to the right or left of it randomly so it doesn’t always take the same path.

Having Control over the speed is ideal. I am not sure how to at the AI element to it other than randomness.

Thanks for the contribution! I can see a roller coaster simulation using this.

Very nice.

-rightpurdy

how can i do ping pong and loop setting ???

thanks :sweat_smile: :sweat_smile:

Up… :sweat_smile: :sweat_smile: :sweat_smile: :sweat_smile:

in fact, I am interested on a loop as well. This is my second try on a spline path and it’s working better than the first… but not enough :slight_smile:
Can anyone help here?