Wednesday, June 12, 2013

Thunder Moon Mini Post Mortem: #Softimage in the asset pipeline (Technical)

Softimage is one of those powerful high end 3D tools that can be used for all kinds of things. Over the years people have used it to help make movies, ads, content for videogames, all sorts of other things. It's also one of the tools at the center of our asset production pipeline. Here are some of my experiences with Softimage in the context of the exporter & pipeline I created for the game engine behind Thunder Moon. 

I wrote an exporter for Softimage that produces files in an intermediate binary format (.ecf, for Engine Content File) that is processed by tools specific to my game engine to make the final data loaded by the game. Pretty typical stuff I suppose, but I wanted to mention that for me, I found it easier and more useful to make my own exporters than to write parsers for FBX or Collada (which I put a lot of effort into trying to do, not just guessing here). Those formats are either proprietary or pretty dang complicated to deal with and by writing my own exporter to my own binary format I regained control of the situation and the problem of how to get data from Softimage to the game became much more straightforward. 

There were some challenges getting all the UV data and shader data out of Softimage, but in the end it all worked out well enough. It's able to export models and animations, together or separately, in a way that really helps smooth out the process of getting assets into the game because of how they can be worked on together or separately, with the game able to load and manage assets in groups that make logical sense. For instance, the main character model is one standalone asset, and animations for this character are created in separate files  because there were far too many to put into a single file without it becoming a maintenance issue. More simple models, such as weapons, generally have both the mesh and the animations created in a single scene and they are all exported together. This kind of flexibility has been very helpful in keeping what sometimes seems like an overwhelming number of assets under control. 

One challenging part of the exporter was dealing with the real time shaders because the pipeline supports arbitrary shaders and will export all the parameter settings. The APIs for this work well enough but there seems to have been some undocumented changes over the past few versions. For instance, SI2014 seems to have a few new shader parameters associated with RT shaders that are automatically created by Softimage, which my exporter discovers and exports like it does any other global glsl variable despite me not actually having these variables in the code. This was a small issue for me because the game runs using parallel HLSL shaders and expects to be able to set all parameters that were exported. Since these “ghost” variables do not exist in either the glsl or hlsl source, I had to put special case code to handle this recent change. Of all the things I wish Softimage would open up the source to and let us tinker, this would be it. One thing that worked well here was to make a “property dictionary” that had was basically a set of dictionaries, one for each data type, all keyed by string, which let me export an arbitrary amount of loose data without having to change the file format. This was essential for dealing with different shaders that usually had different parameters to push to the game engine.

The game supports rigid bodies made of composite shapes. The exporter knows how to produce physics data for the models being exported. Originally, these were set up with the Softimage rigid body objects but I had to stop using them because of crashes that would occur when attempting to get data out of them with the C++ api (I think it was GetPatriarch or something like that). I reported these bugs and proceeded to work around the defect since there was no telling how long it would take before Autodesk to fix it. I now do something a little different, which works better for me anyway. I use a collection of meshes that are each constrained to a bone in the character or model. The hierarchy of these meshes, combined with custom properties for essentially “rigid body root” and “rigid body part” allow me to define a collection of rigid bodies for an asset. When exported, each RBR is composed of all the RBPs underneath it, with any sub-RBR’s defining a new rigid body. The RBR property has various parameters to define the rigid body as a whole such as total mass and various game metadata, and the RBP has parameters that mainly define that shape of that part of the composite rigid body. Shape being a sphere, capsule, box, or mesh etc, the actual final geometry being derived by the local axis and the points the mesh is composed of. It took a little work to get the shape generators to properly contain these control points but it wasn’t too big of a deal and this approach allows me to circumvent the limited set of primitive objects provided by Softimage’s physics system. Thunder Moon uses this rigid body exporter setup to create the bits and pieces that fly around when certain objects are destroyed, such as the main character and turret. The custom properties also allow for additional metadata specific to my game engine’s physics such as friction parameters and so forth.

Speaking of additional metadata, there are a number of custom properties the exporter knows how to deal with. “Locators” is one of them, these are "nulls" (basically, empty transforms in the character hierarchy) that have been tagged with the “Locator” property. These allow the game to find named transforms relative to the animated hierarchy of deformers. Locators exist in the hierarchy of deformers and their data propagates all the way to the game runtime, but these matrices are not included in the set of matrices that are constantly updated for the characters – they are updated on demand when they are occasionally needed. This allows for any number of locators to be set up for an asset without incurring continuous overhead. This is used for particle emitter points and attachment points, among other things.

As you can see, for better or worse I've coupled the asset pipeline to Softimage. If I want to switch to another package in the future, I’ll need to do the same sort of exporter there. This would be a lot of work and is easily the biggest downside of taking this approach to the pipeline. Before deciding to commit to this, I really tried to make the other formats work but I just couldn't convince myself I would get the kind of user experience I wanted for the artists (which so far, is just me, but I'd like that to change someday!). The way it is set up now, I can hit export and have everything related to the asset get sent out with a minimum of human error. There is no massaging of meshes to make them deal with quirks of the file format. All animation sources are included in the exported data. It works with referenced models, and can export meshes and animations separately or together, whichever makes sense for the asset. It knows how to deal with subdivided meshes. It all just works, and by eliminating the manual steps in the export I have avoided a lot of “oops I forgot” type of problems I've seen in the past with other pipelines.

Originally, I had set up the exporter to be something that ran as a service in the background on a PC, constantly listening to network requests to export an asset. The idea was that if the content pipeline changed, or if an asset file was changed, the build system would trigger exports of everything that depended on it. This actually worked, and was really quite fast, but in practice it just turned out to be easier to make a list of all assets the game uses and make a single batch file and run it when that happened (which wasn't very often, and hardly ever happens now). Typically, triggering a manual export when “done” building/tuning an asset is how it works now. It’s just simpler at so many levels this way. Rather than having the pipeline deal with Softimage *.SCN files, it just deals with the engine *.ECF files. This is good for another reason; since the ECF format is something I made, I can make other tools that create these files and not have everything coupled to Softimage. I haven't done this yet, but it does open the door to more specialized custom tools such as level and character editors, among other things.

In a sense, it’s kind of like having written my own FBX or DAE format. Perhaps in the end it might be better to have just parsed either of those, but I don’t think so. They are both great for pushing data between 3D apps at a high level, and I often use them for that. I think it’s likely either of them could theoretically work as an intermediate format, there is probably a way to get the extra metadata I need, but the downsides of working with them just didn’t make sense for me. With FBX being closed format and given my experiences with waiting sometimes over a year for show stopping bugs to get fixed, the potential for that to happen is unacceptable. Collada is better in that regard but the parsers I could find were difficult to work with. Both of these formats have export steps that require things to be remembered and performed manually, correctly, every time. As I looked into both of these, I realized I was essentially making a layer between Softimage -> FBX -> ECF -> Game when I could just go Softimage -> ECF -> Game and skip the step of dealing with either of them, avoiding any limitations they may have and reducing chances of human error in the process.

I’m hoping to do a Windows version of the game at some point. Thunder Moon, and the engine behind it, has been designed from the outset to be moddable by the players. If & when that happens, I plan to provide this exporter to players to help them get their assets into the game.