Booniverse
16Dec/115

Waypoints & Catmull-Rom Splines

Thought I'd share some more code. Yay, right?! This time, I've been working on turning a series of Vector3 coordinates (waypoints) into a Catmull-Rom spline. The code works by providing an array of Vector3, an output array (also of Vector3) and specifying the number of curve samples, per span, to return in the output array.

Catmull-Rom splines employ an algorithm which takes four points (p0, p1, p2, p3) and a normalised distance parameter (0 to 1). The first and last points (p0 and p3) are used to define curvature, while the normalized distance parameter is used to calculate a position on the resulting curve between p1 and p2.

What this means in practice is that the code below will appear to ignore the first and last waypoints in the array. To include them in the final curve, duplicate them at the start and end of the array. For example, given the points A, B, C, D and E, your array should look like: A, A, B, C, D, E, E. This will give you a resulting curve which starts at point A, ends at point E and passes through points B, C and D on the way.

Here's a picture demoing the linear input path (cyan) and the resulting Catmull-Rom spline output path (red).

Technically, no curve is actually generated. The main method returns a second linear path, albeit with more (smoothed) waypoints. With enough samples-per-span (the image above has 10 samples) the Vector3 output array will describe a visually smooth curve. The code is included below:

/// <summary>
/// Takes an array of input coordinates used to define a Catmull-Rom spline, and then
/// samples the resulting spline according to the specified sample count (per span),
/// populating the output array with the newly sampled coordinates. The returned boolean
/// indicates whether the operation was successful (true) or not (false).
/// NOTE: The first and last points specified are used to describe curvature and will be dropped
/// from the resulting spline. Duplicate them if you wish to include them in the curve.
/// </summary>
public static bool CatmullRom(Vector3[] inCoordinates, out Vector3[] outCoordinates, int samples)
{
	if (inCoordinates.Length &lt; 4)
	{
		outCoordinates = null;
		return false;
	}
 
	List results = new List();
 
	for (int n = 1; n &lt; inCoordinates.Length - 2; n++)
		for (int i = 0; i &lt; samples; i++)
			results.Add(PointOnCurve(inCoordinates[n - 1], inCoordinates[n], inCoordinates[n + 1], inCoordinates[n + 2], (1f / samples) * i ));
 
	results.Add(inCoordinates[inCoordinates.Length - 2]);
 
	outCoordinates = results.ToArray();
	return true;
}
 
/// <summary>
/// Return a point on the curve between P1 and P2 with P0 and P4 describing curvature, at
/// the normalized distance t.
/// </summary>
 
public static Vector3 PointOnCurve(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
	Vector3 result = new Vector3();
 
	float t0 = ((-t + 2f) * t - 1f) * t * 0.5f;
	float t1 = (((3f * t - 5f) * t) * t + 2f) * 0.5f;
	float t2 = ((-3f * t + 4f) * t + 1f) * t * 0.5f;
	float t3 = ((t - 1f) * t * t) * 0.5f;
 
	result.x = p0.x * t0 + p1.x * t1 + p2.x * t2 + p3.x * t3;
	result.y = p0.y * t0 + p1.y * t1 + p2.y * t2 + p3.y * t3;
	result.z = p0.z * t0 + p1.z * t1 + p2.z * t2 + p3.z * t3;
 
	return result;
}

There are probably quite a few ways this code could be optimised (feel free to point them out if you've stopped by!) but I'm only using this code during the level's initialization stage, so optimisation is not really all that important for me. The next stage will be to investigate means of normalizing the curve sampling to provide equidistant samples rather than distances being based on curvature and waypoint separation. It's not all that critical as I can reliably construct the paths to ensure a more-or-less equidistant array of waypoints and prevent visible variations in sample density, but it's still something I'd like to solve. At any rate, I hope this is useful to someone.

Filed under: Code, Game Dev, Unity 5 Comments
12Dec/115

Win7 and Wacom: Not Good Bedfellows

ARGGGGHHHHHHHHH. Let me say that again: ARGGGGHHHHHHHHH.

So I just spent the better half of two hours trying to get my Wacom Intuos 3 playing nice with my fresh Windows 7 install. I haven't blogged about it at all (mostly because I would like my blog to be at least somewhat interesting to people who haven't recently been lobotomised) but last week I reformatted my PC due to a security concern*. The end result, of course, is that it will take me another 6 months to get my PC back to operational capacity. Reformatting kind of feels like burning your house down to clear the dust.

One aspect of the reformat is that it'll take me a long time to realise just how much non-replaceable bits and pieces I've sent into the digital nether. These things tend to surprise me in an awfully gut-wrenching way, like patting your pockets and realising with horror that you left your 6 month old child sitting in the middle of the Pacific Motorway somewhere between Sydney and the Central Coast three weeks prior, but at least you have your wallet.

Then there's the less distressing kind of revelations, such as having accidentally deleted all of your hardware drivers leaving you to have to pull your case apart because you can't recall the model or even the brand of most of your components. And then of course, there's getting your Wacom Intuos to play nice with Windows 7.

Fortunately, I remembered that the Wacom drivers, post somewhere-around-about-9-to-18-months-ago, stopping working nicely with Photoshop: There seems to be some kind of persistent bug with pressure sensitivity occasionally skipping out in favour of maximum stroke weight, like trying to paint whilst being randomly tasered. Unfortunately, as I said before, I went ahead and very smartly deleted all of my drivers in the reformat.

Then there's all the crap Windows puts in the way of your tablet actually being artistically advantageous: Tablet input panels, pen flicks (whatever the hell they are), that infuriating little ripple effect every time you touch the pen to the tablet, and my favourite, that fractional second of delay in input where Windows is wondering if you're going to hold it down long enough to be a right-click. Once again: ARGGGGHHHHHHHHH.

Now, the whole point of making this blog entry is so that, in 12 months time when I need to reformat again** I won't have to hunt for this information once more. Here it is:

STEP 1 : Turn off Tablet PC Components

1. Start > Control PanelPrograms
2. Turn Windows Features On or Off
3. Uncheck Tablet PC Components and restart

STEP 2: Disable Hold-to-Right-Click

1. Start > Control Panel > Hardware and Sound > Pen and Touch
2. Select Press and Hold
3. Click Settings and uncheck  Enabled Press and Hold for Right Clicking

Sounds simple? Wondering what I'm bitching about? Well excuuuuse me for expecting Tablet PC and Pen Input options to be conveniently listed under Tablet PC and Pen Input Options.

Addendum: The latest driver release from Wacom (September 2011) does in fact fix the intermittent Photoshop pressure problem. It also appears to automatically disable the Hold-for-Right-Click option, but I'm not sure about the ripple animation or the pen input tab, so I'm sticking with my preferred method of turning it all off!

If you're running a Wacom with Windows 7, I highly suggest you follow the steps outlined above to stop Windows from screwing unnecessarily with your input.

* Not midget-porn related. Back in your seats.

** Also not midget-porn related.

Filed under: Random 5 Comments