Freedom of Motion Alpha 1

by Taylor Hadden | 16:30

FoM Alpha 1 SmallIt has been a while since my previous post, but in the silence I’ve been working. Freedom of Motion has now broken into the earliest stages of Alpha and I have something to properly show off.

The current movement features include running, jumping, rolling, sprinting, sliding, climbing up ledges, wall jumps, and wall running. Additionally, the world is built using a custom voxel terrain engine, and you are able to freely edit the included testing world or build your own. Full details are provided in the readme.

Of course, this is still the earliest of Alphas, so there aren’t any objectives, and you should fully expect things to break or simply not work without warning. That said, this forms a solid jumping-off point for further development of the game, and I’m excited about its potential.

Without any further ado, here are download links to Freedom of Motion Alpha 1:

Thanks for reading, and please leave any and all feedback below!

Voxels, Octrees, and Collision

by Taylor Hadden | 21:18

Today’s subject is collision. There are a number of ways one could setup a collision and physics system with voxel data. I could build my own full physics solution, but I really don’t need (or want) to. Unity has its own physics system; the question is then how to interface with it.

Like last time, we’re talking about a single cubic chunk of voxel data. I already have the mesh data used to display the chunk, so Unity’s Mesh Colliders could turn that mesh data into collision, but Mesh Colliders have some pretty severe performance issues when used in bulk. Other developers have also mentioned that the procedural generation of a Mesh Collider can take a long time. I want to have effectively limitless terrain with good draw distances, and I also want my terrain chunks to react to user changes quickly, so Mesh Colliders for terrain are right out.

That leaves building a collision set to represent the voxel data out of collider primitives (box, sphere, and capsule colliders). One option is to place one Box Collider for every cube in the chunk. This results in several thousand colliders however, and we can do better.

An Illustration of Octrees

I mentioned this in my last post, but this voxel terrain is being stored in octrees, which is a data structure that can store eight sub-versions of itself. We can use this data structure to generate a much more efficient collection of Box Colliders. For simplicity’s sake, let’s look at the cube without the mesh, just viewing the Box Collider borders:

Cube Collision Full

This Box Collider represents the root octree of the voxel data. An octree knows its own center and size (the distance between opposite faces) and also holds onto a piece of voxel data.

Now, say we want to remove the top right corner. To do this, the octree constructs eight children, each positioned in a corner and with a copy of the original octree’s block data. Then, the octree in the top right is told that it is empty. At this point, the series of Box Colliders are regenerated:

Cube Collision 8th

First Division

Cube Collision 16th

Second Division

Cube Collision 32nd

Third Division

This operation can be repeated until we hit the minimum size of the octree structure. Since the octree uses integers for size and positioning, that value is 1. The smallest block I want is a half-meter, so the Mesh and Collision Generators are set to translate a “1” in octree space to a “0.5” in world space, but this is freely adjustable.

Generating Colliders

The actual process of generating the colliders is quite simple. You just need to loop through the octrees and place a Box Collider where the solid octrees are. This dramatically cuts down on the number of colliders used per chunk when compared to simply placing a collider for every block.

Fourth Division

Fourth Division

I’ve broken this process up into two discrete operations: the object that loops through the octrees (called a Crawler) and the object that translates this information into the actual Unity objects (the “Generator”). The CollisionGenerator class has no idea about the octree or how the data is stored. It only requires a VolumeCrawler interface. Meanwhile, the OctreeVolumeCrawler class implements that VolumeCrawler interface and provides a sequence of volumes defined by their minimum and maximum points.

This separation is an important programming pattern that means I can, for example, decide to completely change how the voxel data is held in memory. So long as I write a class that implements the VolumeCrawler interface that can handle the translation of the data, the CollisionGenerator will continue to work perfectly. Having each process segmented out into its own class that is only loosely connected to others makes code more reusable and easier to understand.

Some Code

Let’s now take a look at the actual bits of code that are being used here (I apologize in advance to those who prefer their braces on individual lines). First up is the VolumeCrawler interface:

public interface FoGVolumeCrawler {
	/// <summary>
	/// Loads in the next volume
	/// </summary>
	/// <returns>If there is data available</returns>
	bool Next();

	/// <summary>
	/// Resets the crawler information to the start
	/// </summary>
	void Reset();

	/// <summary>
	/// The minimum corner of the volume
	/// </summary>
	FoGPosition min { get; }

	/// <summary>
	/// The maximum corner of the volume
	/// </summary>
	FoGPosition max { get; }
}

In developing this framework, I’ve been keeping it as separate from Unity as possible. That meant, for example, making my own Position struct consisting of X, Y, and Z integers. Next, let’s take a look at the OctreeVolumeCrawler. I won’t include the WorldOctree code as it’s exceptionally long, but I’ve added comments to the appropriate function calls.

public class OctreeVolumeCrawler : VolumeCrawler {

	private WorldOctree masterOctree;

	private IList&lt;WorldOctree&gt; octrees;
	private int index;

	private Position _min;
	private Position _max;

	public OctreeVolumeCrawler(WorldOctree octree) {
		masterOctree = octree;
		Reset();
	}

	public bool Next() {
		if (octrees == null) {
			octrees = new List&lt;WorldOctree&gt;();
			// WorldOctree.Solids() returns a list of all solid octrees in the hierarchy.
			octrees = masterOctree.Solids();
		}

		if (index &lt; octrees.Count) {
			// WorldOctree.center is the center Position of the Octree.
			Position center = octrees[index].center;

			// WorldOctree.size is the width of the Octree between two opposite faces.
			int halfSize = octrees[index].size / 2;
				if (!octrees[index].IsLeaf()) {
				_min = center - halfSize;
				_max = center + halfSize;
			}
			else {
				_min = center;
				_max = center + 1;
			}


			index++;
			return true;
		}

		return false;
	}

	public void Reset() {
		octrees = null;
		index = 0;
	}

	public Position min {
		get {
			return _min;
		}
	}

	public Position max {
		get {
			return _max;
		}
	}
}

Finally, we can look at the CollisionGenerator itself.

public class CollisionGenerator {

	private float blockSize;

	public CollisionGenerator(float blockSize) {
		this.blockSize = blockSize;
	}

	public void Generate(VolumeCrawler crawler, GameObject chunkRoot) {
		int i = 0;
		float startTime = Time.realtimeSinceStartup;

		// The existing box colliders
		BoxCollider[] boxColliders = chunkRoot.GetComponents<BoxCollider>();
		// The index of the existing box colliders
		int index = 0;

		while (crawler.Next()) {
			Vector3 min = new Vector3(crawler.min.x, crawler.min.y, crawler.min.z) * blockSize;
			Vector3 max = new Vector3(crawler.max.x, crawler.max.y, crawler.max.z) * blockSize;

			BoxCollider collider = null;
			if (index < boxColliders.Length) {
				// Retrofit an existing collider
				collider = boxColliders[index];
				index++;
			}
			else {
				// Add a new one once there are no more existing ones.
				collider = chunkRoot.AddComponent<BoxCollider>();
			}

			collider.center = (min + max) / 2;
			collider.size = max - min;

			i++;
		}

		// Remove any old box colliders
		while (index < boxColliders.Length) {
			Object.Destroy(boxColliders[index]);
			index++;
		}

		float timeSpent = Time.realtimeSinceStartup - startTime;
		Debug.Log(i + " collision volumes created in " + timeSpent + " seconds");
	}
}

There are two important things to mention about this class. The first is that it attempts to reuse any existing BoxColliders attached to the GameObject. This is a major time saver, as generally any single action is only going to add or remove a handful of colliders. Reusing the ones that are already there means we don’t get hit trying to Destroy() and instantiate new ones every time we want to update a chunk. With this very simple optimization, I was able to cut the time it takes to regenerate the collision by nearly a factor of 10. Time is very important in this process. Any code that interacts with Unity has to play on the main thread, and an operation that takes a long time in that thread will make the game appear to “hang” until the process is finished. The second thing to note is that this collision is regenerated during FixedUpdate() on the Unity side. I found that this fixed a problem of sometimes falling through the collision while it was being regenerated.

I hope that was informative. If you have any questions, leave a comment, and I will do my best to answer. The next step in development is building outwards and creating the structures to manage the several hundred chunks that will make up the player’s view of the world.

The First Cube

by Taylor Hadden | 17:40

So I figure I have to start documenting this process eventually. For the past several months, I’ve been working in my (small amount of) free time on a set of first person movement model, but I’m going to talk about that at a later time. The thing that I’m going to talk about today is a cube.

CubeNice and boring, no? Well like I said, I have to start this process sometime, and at its most basic is a good place to begin. This cube is actually generated dynamically at runtime. The layout of the cube is determined by a voxel octree, which is a type of data structure that dynamically subdivides only as is necessary. That means that for this entire 32x32x32 cube (a total of 32,768 blocks!), only one piece of voxel information is needed.

This means that large geological features, such as massive mountain ranges, can seriously save on the number of individual blocks actually stored and held in memory. Of course, with highly detailed terrain where no two adjacent blocks are the same (still unlikely), you’re going to be storing unique data for each block. The actual performance implications of that will be a battle for another day, however.

Cube-Wireframe

The wireframe of the cube

This octree data structure is then fed into a piece of code that translates the voxel information into a mesh. At that point, Unity takes over and does the grunt work of actually displaying the cube. The mesh generator in these images is configured to use half-meter cubes (it only builds the external faces), but it can be setup to use any cube size to represent the data.

At the moment, I am just generating very simple two-triangle planes for the sides of the cubes, but I plan on introducing more complexity when appropriate for the surface type. For example, a dirt wall isn’t going to be perfectly smooth, and using a rougher piece of geometry for that dirt wall in addition to its texture will greatly add to its sense of physicality.

Cube-Detail

A look at some very basic detail.

For the moment though, I can generate cubes. It’s not much, but it’s a stepping stone. Next time, I’m going to talk more about the usefulness of octree data when it comes to generating collision volumes.