Building a multi-DCC exporter from scratch
On any given production, one of the first things the Tech Art Teams tend to build is an exporter. This is easily explained: of all the problems facing any given project, reliably and consistently transferring content between your DCC and your engine (whatever they may be), is one of the most valuable ones to solve early. Even as of the time of writing, in an industry where game engines become ever more all-encompassing, external DCCs continue to play a vital role in productions, after all.
Doing so ensures that even during early preproduction, your models and textures are exported through a known method that can be controlled - providing the opportunity for early validation and simple checks before content gets into the engine. In other words, this puts an immediate filter on your content pipeline from day 1, ensuring that all content produced thereafter passes through it.
In this short tutorial, we will be looking at building the foundations of a template Export framework. We will start by simply building an agnostic "base" class that performs our key operations, and implementing two unique and different use cases, which work in different DCCs. This is meant to illustrate that a modern Tech Art code base should be portable across all DCCs that support Python, with only DCC-specific leaf modules being different.
Building the base class
The above code snippet is totally agnostic - note how it does not even require an imported library, and will work in any python version or interpreter build. As such, this code is considered "portable", and can be used as a base class no matter where our code is run.
Note how we have three key methods:
- validate
- export
- run
Validate
This method is run before we call export(). It is expected to return True or False. If it returns the latter, the export() method will not be called, and our export process will be abandoned. This is an ideal place for the base framework to later be expanded with some descriptive logging and error handling.
In the base class, it is not possible to actually implement this method beyond simply returning True by default, as it will be determined by each implementation what "valid" means. By returning True, we also allow the developer to determine for themselves whether they even want to implement any validation.
Export
This method performs the actual export process, and as such is implemented as abstract, by raising a NotImplementedError in the base class. This ensures that the developer must implement the export() method in some form, or invoking the run() method will raise an error.
Run
This is the method we are actually going to call when starting our export process. This extra layer around the export method allows us to guarantee we always call validate() before the export process is triggered, thereby providing some standardization across all implementations out of the box.
Building an implementation
Note how in this implementation, we are importing a fictional my_dcc package, which in a real-world scenario, you would have to replace with an actual module, like substance_painter or pymxs (for 3ds max). Also note how currently, our base class is missing some key features:
- The ability to provide export options, thereby differentiating exporter behaviour per class instance
- The ability to store settings and retrieve them later
Let's take our base class and expand it. In our version, we're going to use a simple dictionary to provide options, to keep things simple as as portable as possible.
There are many ways to provide options to an exporter. In our example, we've chosen to go with the object-oriented approach of storing settings Exporter class instances. This means that in order to export more than one thing, we will have to create multiple instances of the class, each with different settings.
Base Class:
Implemented Class:
Note, in order to actually perform our export process, our code would look somewhat like this:
So far, so good, right? Already, there's a fair amount of behaviour in our exporter, and we've only got 2 methods in our implementation. The same would likely be true for most implementations of this exporter, regardless of the DCC. To illustrate, let's implement a very simple FBX mesh exporter for Autodesk Maya:
Now let's actually perform the export:
Running the above code in Maya (presuming you've organised your files correctly and setup the interpreter environment properly) will now export a mesh by the name of "Sphere001" if one such exists. Otherwise, it will simply not attempt the export process, and the scene's state will not be affected.
That's how you build a very simple exporter that works across multiple DCC's! All you need to do now is to build more implementations in more environments, depending on your project's needs.
Comments
Post a Comment
All questions about blog or article content are welcome. Questions about my employment or employer, past or present, will not be answered.