Abstract Factory Blog

Organizing Complexity

16 Nov 2012

Setting up a character is complex. The amount of data you are managing is in an ever growing quantity and thus organizing that data is equally important.

I’d like to show you my approach in handling this task. An approach that further separates the Driver (you, AI, dynamics, etc.) from the Driven (the resulting surface) or, in other words, the interface** from the implementation. One that is inspired by that of Object Oriented Programming.

To achieve this, I’ve applied a slightly alternative way of organizing data within an asset.

Utilizing the Outliner

Some of you may not be aware, but Maya’s Outliner supports unique indices for your items and allows you to modify those indices by middle-click dragging DAG items around. This is a great tool for helping you visualize the order of operations that your asset employs.

From an Object Oriented point of view, an Asset is an object with an input (some external influence), an interface (which is what the user sees and interacts with), an implementation (what makes an asset work) and an** output (**the result).

Depending on the asset, the input could be as simple as a vector coordinate in space or as complex as the full output from another rig, say if you had one rig designed to control another.

The important thing here is also that the only thing exposed to the User is the interface. Everything else is implementation detail. This frees up whomever designs the asset up to make any changes to the implementation, as long as the interface remains untouched.

The interface consists of mainly two parts.
o What the user can touch
What the user can see

The visualization are debugging tools for the user, they are the leafs of branches of data from somewhere form within of the implementation, exposing to the user what the user needs to see in order to gain a better understanding of what is making the output look the way it does. Modifying any of these will have no effect on the final outcome and are thus safe for the user to fool around with. Such as adding their own shaders for better visibility of certain parts of the character or even physically removing parts of the mesh. All can be restored by simply removing history on that end branch since it comes without history to begin with.

The implementation consists of step-by-step operations, encapsulated by modules, surrounded by an input and an output.

Introducing the concept of a “module” as a self-contained set of nodes, each with it’s own input and output. The input being whatever is about to be “skinned”, in this case, and the output being the resulting skinned surface. This allows you to step through your operations one by one, inspecting them with surgical precision and make edits or additions in a controlled and easily trackable manner. It also allows you to think of each part as a “black-box” and only consider it’s in and out connections.

There is something else to be noticed here. The order in which the items lie. There is a consistent layout of nodes in a top-to-bottom fashion. A flow which continues inside each module.

The module itself is also part of a larger whole and is dependent on the above module, feeding modules below with information. In fact, every node in this hierarchy follows the same set of rules.

1. Top to bottom order of operations
I.e. the allowed operations to be applied to each module must only come from modules above it. Thus I know that if I were do hit delete on anything below, all of the above would remain untouched. This way, I can easily keep track of what level of detail is added where and still maintain control of any and all operations I apply, in case anything breaks down or if new features are to be added.

2. Encapsulation
Operations inside of each module must happen only between the input and output.
I’m free to bring in as many external sources as I wish (assuming they come from a valid output or source) as long as I make use of them within the input/output span.

3. Single Responsibility Principle
Each node represents one and only one task. This means that at no point can a node have more than one set of operations applied, if it does it should be encapsulated into a module.

4. Minimally Complete

Each module should be as simple as possible, but no simpler. This is a back and forth struggle of adding features and letting positive side-effects pass through against keeping things simple and straight forward. Current strategy is to keep adding until you’re all out of ideas and then hop back in to trim the edges.

Working this way is rather tedious without the right set of tools. In the next post, I’ll provide you with some of the tools I use and explain a bit about why they are useful.

Some parts of this definition are still being worked on: