Steve Exploring Stuff: 2012


CAINav v0.4: The Nuclear Option

CAINav v0.4.0 has been released.  There are a whole lot of enhancements and changes.  This post includes an overview, plus information on some of the enhancements. 

Download | Documentation (Improved getting started and advanced sections.)


First the bad news.  Well, 'bad' is not really the correct term.  For new users it's all happy happy joy joy.  For users upgrading from v0.3, will be pain pain suffering, then happy happy joy joy.

Remember all those warnings about CAINav being in alpha?

The pain centers around changes to the API and Unity extensions.  As I added features for v0.4 I quickly realized that there was no way to move forward and also make for a clean and easy upgrade.  So I chose the nuclear option. Kaboom went the API. Everyone will be affected.

Summary of Enhancements

The major enhancements for v0.4 include the following:

  • Conversion from float[3] arrays to Vector3 structures.
  • Easy tiled navigation meshes. (I.e. Large area meshes.)
  • Area and flag assignment during the build process.
  • Support for off-mesh connections in the build process.
  • Support for background/multi-threaded builds.
  • A standard end-to-end build process that is highly extendable.
  • For Unity users, almost all advanced build features are available to non-coders. (I.e. Scene designers.)
  • A new API for the PathCorridor class.  (Easier to use with better performance.)
  • An upgrade to Recast Navigation r338.

"But," you may ask, "aren't many of these feature already available in v0.3?" Yes they are.   But in v0.3 you had to fully understand the intricacies of the navigation mesh build process and write your own code to make use of the features.  The v0.4 build process makes things a whole lot easier.

Conversion from float[3] Arrays to Vector3 Structures

This is the API change that will impact every user.

Recast Navigation is based on float[3] vectors.  I originally chose to keep using float[3]'s throughout the core, switching to structures only in the Unity ease-of-use extensions; and then, only when it did not impact memory and performance too much. That was a design mistake that is rectified in v0.4.  float[3]'s are completely gone from the API.

For Unity users, everything uses UnityEngine.Vector3 structures. You'll also note that all the U3D* classes are gone. They are no longer needed.

.NET-only users get the simple org.critterai.Vector3 structure.  This structure is implemented in a way that will allow many users, with only an hour or so of work per version upgrade, to swap your own vector structure into CAINav, getting the same ease-of-use as Unity users. See Advanced Topics > .NET: Swapping in Native Vectors in the documentation for details.

This change is 99% good.  The API is much much cleaner and performance is significantly better.  One standard path following scenario showed a 30+% increase in performance.  Hard to believe, but I couldn't find any flaws in the test methodology. It is also really nice not to have to deal with vector array references all over the place.

There are two downsides.

Users who code for interoperability between both Unity and .NET applications can no longer use the same libraries for both targets.  (Not byte-code compatible.)  Also, source code that needs to run on both targets will need some extra code. Something like this:

using Vector3 = org.critterai.Vector3;
using Vector3 = UnityEngine.Vector3;

The other downside is serialization.  Multiple sets of libraries means that normal .NET serialization is of limited use.  In fact, I'll be removing the ISerializable interface from all classes starting in v0.5.  Byte[] serialization will be the standard format moving forward.

For those who are upgrading, most of it is just mind numbing grunt work. Converting variables from float[3]'s to Vector3's, dealing with the change from reference to value types, simplifying code structure, etc. The big gotcha is the stride of vector arrays. Be careful there, since you'll be changing from a stride of 3 to a stride of 1. That's the only bit that caused me any real pain.

A New Navigation Mesh Build Process

The IncrementalBuilder, which provides the standard navigation mesh build process, has been completely revamped. See Getting Started Topics > An Introduction to NMGen in the documentation for a full overview. The two main changes have to do with the input to the builder, and post-processing.

The incremental builder now accepts two main data objects, an InputGeometry object that specifies triangle and area assignment information, and a ProcessorSet object that contains all the post-processors that will be applied to the build. There is also a variation of the builder designed for creating meshes that will be part of a multi-tile navigation mesh.

The input geometry object allows you to assign areas (surface type) on a per-triangle basis.

The post-processors are what give the the incremental builder its flexibility. If you want to modify the standard build, just use one of the pre-defined processors, or implement a new custom processor.

For example, to stamp areas into the mesh, you can apply AreaBoxMarker, AreaConvexMarker, and AreaCylinderMarker processors. Any object that implements the INMGenProcessor interface can be used to modify the build.

Creating navigation mesh tile data from the NMGen data has always been a bit of a bother. Several new utility methods and classes make it easier. (See the getting started documentation.)

Big Changes to the Unity Build Process

In v0.3 and earlier, the navigation mesh build was broken up across multiple components residing in the scene. The new build process is centered on a single asset stored in the project, not the scene. The behavior of this asset is then modified by other assets as needed.

All standard build assets are editor-only. They don't have any impact on scene size and the code is no longer included in the Unity project build. There is little to no bloat caused by navigation mesh build and configuration.

Almost all advanced build features such as tiling, area assignment, and off-mesh connections are available to non-coders through GUI editors. You can even do partial rebuilds of multi-tile meshes and background builds of large area meshes.

The Getting Started Topics > Getting Started with Unity in the documentation covers the new features.

This build process is highly flexible because of the input build. As with the IncrementalBuilder, the input build can be altered by all sorts of pre-defined and custom processors.

Now for the bad news for those who need to upgrade. As you can see, this is an entirely new build process. There will be a lot of work to upgrade existing projects to the new structure. One bit of good news: The navigation mesh save/load buttons can be used to save your old navigation meshes to disk, then load them into the new data assets as part of your upgrade process.

Bye Bye to the Unity Navigation Extensions

Creating navigation extensions is problematic. There are so many ways to implement navigation. Do you need light weight pathfinding for a large number of agents? Or do you need complex pathfinding with steering and collision avoidance? Do you need navigation planning only at the scene level? Or do you need a navigation system that persists information between scenes? The core navigation functionality supports these different models, but the v0.3 extensions are kind of clunky and limited. So I've removed them from v0.4. If need something to help you get started, check out the Sample Pack. It includes an example implementation in the Crowd Demo.

At some point in the future I may add navigation extensions back into the mix, but probably only as optional packages.


There are various other enhancements and changes included in v0.4, but that's it for now. Good luck, and sorry about all the moth carcasses.