In other words, I entirely authored the HDA using Houdini’s Python API instead of creating it interactively through the UI.
Why, you ask? I’ll skip some details and will focus on the main points here—it’s all about improving the odds for maintenance, team collaboration, and consistency.
It’s when I had to rig all the birds in the movies The Adventures of Tintin and The Hobbit: An Unexpected Journey, that I came to fully appreciate how much authoring node networks through code was necessary not only in order to make the task efficient, but also to make it possible at all.
To drive the point home, I’ll pick the most obvious scenaraio. For that, you need to understand that birds have a hundreds of hero feathers that might require to be animated individually, not just simulated, meaning that a single feather’s rig would have to be duplicated many times, even more so when multiple birds must be rigged. In such a scenario, if I had to author these network of nodes making up the rigs solely through the application’s UI, how long would have it taken me to copy/past each rig and adjust them to the position and shape of heir corresponding feather? Worse, if a feature needed to be added later on, or a bug needed to be fixed, how would I have been able to address the required changes in a timely manner while reducing the chances for human errors to sneak in during the process?
What seems like an impossible task through an UI could be turned into a single for-loop in code. And with a single click, I could have my army of birds being all rebuilt to benefit from the latest updates in the rig.
Even when there isn’t a real need for reusing such networks, it’s always good to know that we have a full programming language’s arsenal at disposition if needed. The sky’s the limit.
File formats represented as ASCII have the advantage to play well with version control systems like Git, which are ubiquitous when working on a project, and even more so when part of a team.
Luckily, Houdini stores all of its HDAs using the CPIO file archive format, which means that both binary and ASCII representations are supported, similarly to USD. This allows to manage such ASCII files in a code repository, and to compile them to binary format during a build step, right before deploying them onto their final location.
However, unlike USD, the ASCII representation for HDAs is by no mean intended to be read or edited by humans. Which is unfortunate because in order to understand the implementation of an HDA, we need to open it into Houdini and inspect it through its UI.
More importantly, when an update to an HDA is wrapped into a Git commit, it can be a challenge to tell what has changed at all due to the diff being so... verbose and irrelevant? It’s such that even finding where the important changes were made can be an exercise in itself. Worse, versioning up an HDA means that all of its content (and CPIO’s boilerplate) is duplicated, so figuring out what has changed gets yet trickier.
In fact, it’s also impossible to find with certainty all the changes that were made when looking at that HDA within Houdini's UI, which is not ideal since being able to track and understand the changes made over time is quite valuable.
The cherry on the cake is that merge conflicts are not trivially resolvable. In fact, they’re better avoided altogether or else we could easily end up with a corrupted HDA. So, in the event where 2 maintainers were to make changes to a same HDA in parallel, and would then open merge requests, the only way to solve the conflicts would be to merge one branch first, and then ask the other developer to replay their changes using Houdini’s UI, potentially forgetting some bits and pieces in the process if their changes were involved.
Workarounding these underlying issues with the file format Being able to define the contents of a node network solely through Python code solves all these issues and
Another cool thing with coding is that it’s possible to build frameworks and enforce some sort of standards, or conventions. Do you want to create a set of parameters that can be reused across many nodes? Sure! How about always listing the attributes created by a node in a “Output” tab, and allowing users to rename them or disable them? Yep! Automatically cleaning up temporary attributes? Naming conventions? Localizing parameters to avoid relative references in wrangles and snippets? Yes, yes, and yes, of course!
You get it. Finally we can build an opiniated framework that takes care of the boilerplate and that makes sure that all of our nodes are implemented in a consistent fashion across the board.