June 14th, 2008
Man, I feel like I haven’t posted in a while. I’ve been very involved with the goings-on at work and on my personal projects, which are both very exciting right now. I suppose that is a measure of happiness, since I can think of many people who aren’t excited with their work, and would rather think on other things! I have been getting more email lately, and I’m sorry if I haven’t gotten to it all as well as I could have. I do like hearing from people that are curious about this or that subject, so I still encourage you to write.
Decentralization
One thing I think about fairly often is how humans tend to architect these monolithic processes and structures. We are obsessed with the be-all, end-all solution to a complex problem. This is very typical when matters like money or schedules are involved, as there is a tendency to impose a lot of control over such situations. The idea is that the more we control a process, or the people in the process, the higher chance of success the process will have. The more time I invest thinking about it, the more I come to the same conclusion. One simply has to look at the world around them (the natural world) and they will see that the universe is decentralized. All systems rely on smaller objects which are allowed to perform their own jobs without really caring about the bigger picture. The vasculature of fungi and plants, cell structures, honeycombs, our own bodies, ecosystems, and on to the massively macroscopic are all great examples. If we also look at the systems in our lives that are the most successful, we will find these same patterns. The Internet is a great example of success in decentralization, as it truly is a fibrous network of connections between many nodes through which our knowledge can flow freely. However, if you look at governmental bureaucracy or bureaucracy in your own workplaces, you will know it to be ineffective.
I’m not saying wanton decentralization needs to happen indiscriminately, only that we ought to heed the successful systems around us, and see how they did it. The more organic our execution is, the more success will we reap. The last thing we need are hurdles to rigidify the creation process. Strict pipelines and processes are a bane to us all — a process should be able to be iterated on, changed, or completely scrapped to suit the goals of the system.
Abstraction
One of the most useful tools for decentralization. When we can trust the components to know their job, and depend on them to do so, the rest of the machine can keep running smoothly. The more trust there is, the less checking needs to happen, the more productivity the system will churn out, and the more the components will feel anthropomorphically satisfied. The more an individual component can rely on itself, the better. This is true for programming, and it is also true for systems of people working together. I’m very proud and humbled by the atmosphere that I am able to work within. Trusting in the individual, transparency, interoperability of processes, and communication are in abundance.
Anyways, I’m on a ramble. The point is, the pattern I’m experiencing is of self-sufficient nodes contributing to a whole. Take that as you will! I am going to see where this all fits into my code/art…
Posted in The Big Picture | 4 Comments »
May 1st, 2008
Hooray Interpolation!
If you ever really want to confuse someone that is looking at your script controllers, just use cubic polynomials to control imaginary splines. All kidding aside, scripted bez. interp. is awesome in 3ds Max for several reasons:
- Its faster than using native Max splines
- It gives full control over the in and out vectors, which animators love
- It really breaks rigs out of the inorganic box of right angles and linear blends
The first point was the real shocker for me. The first time I noticed this was while rigging some bendy cartoon arms that were driven by actual splines. Stretchy bones were strung between helpers that were path constrained along certain percentages of this spline, with constant velocity turned on for appropriate behavior. There was a noticeable slowdown that really took the fun out of animating the rig, so I had to look into other methods. It turns out that this formula saves the day:
(1-t)^3*p0 + 3*t*(1-t)^2*p1 + 3*t^2*(1-t)*p2 + t^3*p3
Where: t is a value between 0 and 1, and p0, p1, p2, p3 are the four points to interpolate through. p0 and p3 are the start and end, while p1 and p2 are the out and in vectors to control the interpolation. Really these vectors are what you are manipulating anytime you work with paths in Photoshop, or manipulate type in any vector-based illustration software (bezier handles). I just plug in the appropriate values into a script controller and I get magically fast interpolation. And since p1 and p2 are the out and in vectors, controlling these values with some control objects that feel like bezier handles lets animators express themselves more intuitively. Features like these are really what makes rigs interesting to create, animate with, and to watch in performance. The audience might not know it, but deep inside I believe they are bored with watching static linear interps. occuring between nearly every relationship in the hierarchy. This definitely isn’t something new, but it is something that should be implemented more often by more technical artists. If only Max splines were fast enough to begin with… but I suppose we have to work within the package the project is maintained in, or get fed up enough to write some C++.
Posted in Skinning, MAXScript | 5 Comments »
March 16th, 2008
Choices, choices
There really are quite a few options when it comes to packaging scripts for deployment. You have the completely MXS-written installer, third party install packages (like NSIS), shell scripts, or deployment via another language like Python. I suppose it depends on the environment, but the most important decision breaker for me is how fast the package can be updated and repackaged. Ideally, any necessary updates should be able to be integrated instantly.
The simplest way to get this fully automated scheme running is just a specified location on the network that all scripts are saved at, and loading these when Max starts with a startup (in /stdplugs for first execution) script. The script directory on the network has a folder structure similar to the Max installation so the load script can simply copy everything directly. This would be completely transparent to the artist, but has a drawback: if you have a set of macroscripts with icons, those icons will fail to load. The macroscripts will still appear in their correct categories (as long as you fileIn), but will lack icons. I believe there may be a method in the colorMan interface in Max 9 that reloads icons, but I haven’t had a chance to look. Anyways, this is a decent method nonetheless for deployment in terms of time to update/repackage/reinstall.
Aside from the auto-load approach, you have various installer scripts and executables that can run outside or from within Max, but all must be loaded explicitly by the user. I’ve used NSIS to package my scripts into a nice .exe with guided installation, but I really find this too tedious for production. It takes far too much time to update the install script, copy files, build the .exe, etc. The process can be automated somewhat by having a script that generates the install script according to a faux-Max directory structure, but this is just another thing to “deal with.” This is generally how I feel about using a third party language like C# or Python to perform the installation. Unless there is already a studio-wide distribution of a particular language, its a hassle to install packages on people’s machines for the sole purpose of installing MAXScripts.
Recently what I’ve been favoring are shell scripts. They can be run at computer startup, or explicitly. What makes them particularly nice is the ability to control a VCS like Perforce to grab the latest scripts, and then perform a looped file copy for the installation. Since its just copying all files in all folders in a certain directory, it never has to be updated. I simply write my scripts, check them in, and keep working. When someone needs scripts, they just run the shell script.
This is what’s working for me at the moment, but if anyone has any alternate methods or points to add I’d love to hear them!
Posted in MAXScript | No Comments »
March 15th, 2008
Ever since I saw XSI’s sweet skin transfer tools (I forget the exact name), I knew 3ds Max needed something similar. We do have the Skin Utilities panel that will bake skin data into a mesh for transferring to another mesh, but sometimes this doesn’t cut it. One example of this is when particular vertices must inherit the exact weight and bone list of their source vertices. This sort of situation arises when meshes are separate but need to look continuous, like in games that require meshes to be split up for model swaps. There are just so many cases where a smarter skin transfer utility would save loads of time. The only problem has been finding the need for such a tool, since I am unlikely to need it unless I have a ton of similarly rigged situations that could benefit from such a system (like in a game or cinematic pipeline). Luckily, the other day I had an opportunity to write such a tool, and I’m very excited about it.
The skin transfer tool that ships with Max basically has a single drawback: the inability to perform a 1:1 transfer. Sure, you can use vertex snap to put verts very close to each other for a more optimal transfer, but in the end the tool will interpolate a tiny error value into the weight and the match won’t be perfect. Not to mention the fact that Max’s vertex snap isn’t actually perfect. This blew my mind when I first found it out. Try snapping a vert to another vert, select the object and single vertex, and run this code on each to compare (be sure to use Editable Poly objects for this code):
print (polyop.getvert $ (polyop.getvertselection $ as array)[1])
The script will print the selected vertex’s position for comparison. You’ll notice that they aren’t exactly the same! This just doesn’t cut it. When using Skin Utilities, at this point you would have to go in and manually type in the correct weights/bones for each vertex you wanted, and promptly explode in anger. No more! The tool will automatically and perfectly snap a selection of vertices to their nearest source vertices. Snapping a group of vertices is just one click. When the skin transfer routine is running, any vertices that are perfectly coincident will inherit a 1:1 weight/bone relationship from its source mesh. And what about the vertices you don’t want perfectly snapped?
For those verts, I have routine that will collect the three nearest source vertices and grab a distance-modulated weight/bone assignment. This means that completely different meshes can inherit as much or as little skin data from each other as the artist defines.
Posted in Skinning, MAXScript | No Comments »
March 15th, 2008
I get this question semi-often, so I thought I’d make a post about this name and its history…
Around 1999 I used to play a lot of Counter-Strike, and d3coy was my handle. Of course the name also served me well in Day of Defeat and TFC, among others. If you played with a d3coy that favored the AWP/Desert Eagle back during that time period, chances are it was me. When I first started playing, in anticipation to how much I knew I was going to get my ass handed to me, I named myself decoy. Somewhere along the line the “3″ made its way in there, either on accident or in an attempt to be “l33t.”
Anyways, that was a long time ago, and its the only handle I’ve used extensively. I’ve seen plenty of other d3coys out there, including d3koy, dekoy, etc. I’m not sure who had the name first, although I assume it probably has been used by someone or other since the 70’s, or something similarly ridiculous. The only way I’ve ever been able to connect the name to something even moderately professional has been the idea that the transpose of the first two letters in matrix form would create “3d.” But that’s one hell of a stretch.
Posted in Site Related | No Comments »