good news everyone

I’ve been meaning to post what’s below for about a week. I suppose it’s only going up now because at this moment I’m in the waiting room at the doctor’s office; took a bad spill down some stairs yesterday and everyone keeps telling me to go in and get checked out.

I don’t quote Dr. Farnsworth just any day: Mac users will be pleased to note that Snow Leopard 10.6.2 fixes almost all compatibility issues with Maya. And the graph editor no longer corrupts! So if you were waiting on Maya before upgrading, your wait is over. I haven’t tried 2010 (haven’t upgraded since there’s nothing new in it) but 2009 now works better than it did under Leopard. I think Dimos tried 2010, though, and dubbed it good.

But today I want to talk about music. Specifically: I finally bought an Axiom 49.

I bought one of M-Audio’s Oxygen 25-key keyboards years back. It was a solid piece of hardware despite being the entry-level unit, and traveled with me to and from Japan. I recently gave it to a friend who wants to start producing her own music with Garage Band. I’d like to say it was for wholly selfless reasons, but the truth is I wanted an excuse to get a keyboard with more octaves.

The Axiom 49 doesn’t disappoint. It’s not a keyboard you want to lug to a gig; it’s heavy as sin. However, it’s well-constructed and sturdy. I feel like I could fight off a zombie with it and still play a round of lounge jazz afterwards. Also, I dig how the drum pads feel and control. They’re pressure sensitive like the piano keys, and they’re lovely for hammering out tom hits or even for a quick lead pattern.

The best part is that it came with Ableton Live Lite 6, which was upgradeable to Live Lite 8 for free with their current ten-year promotion. I’d been thinking of getting the recently-released Intro version of Live 8, but this was close enough to help me decide if I needed the full version or not, saving me a hundred bucks.

I think that a lot of people out there would be fine with Live Lite. The one feature that I found a dealbreaker is that a single song can only have up to 6 effects in total across all instruments. (In Live Intro it’s 12.) The way I design my sounds, I hit that limit playing around on a single loop a few nights ago. It wouldn’t be a problem if I could freeze tracks or if the limit were for simultaneous effects in use, but even effects on tracks currently producing no sound count.

So I’ll be picking up the full version of Live pretty soon. I had a look at the Studio package but I’m dithering on whether pay the extra cost for a lot of samples I might not need at the moment, and I’m only interested in two of their custom software instruments.

The bonus of using Live: PureMagnetik has really cheap sample packs, and their guitar rig kits sound fricken’ awesome. I also can’t wait to use Sampler to make kits from sounds around town.

Tags: ,

our dvd was reviewed in wired!

How awesome is this: the DVD we made at work that was just published got a great review in Wired magazine. Check it out, and check out the link to buy a copy on Amazon so that we can keep making them. 🙂

Tags: , ,

good news everyone

I don’t quote Dr. Farnsworth just any day: Mac users will be pleased to note that Snow Leopard 10.6.2 fixes almost all compatibility issues with Maya. And the graph editor no longer corrupts! So if you were waiting on Maya before upgrading, your wait is over. I haven’t tried 2010 (haven’t upgraded since there’s nothing new in it) but 2009 now works better than it did under Leopard. I think Dimos tried 2010, though, and dubbed it good.

But today I want to talk about music. Specifically: I finally bought an Axiom 49.

I bought one of M-Audio’s Oxygen 25-key keyboards years back. It was a solid piece of hardware despite being the entry-level unit, and traveled with me to and from Japan. I recently gave it to a friend who wants to start producing her own music with Garage Band. I’d like to say it was for wholly selfless reasons, but the truth is I wanted an excuse to get a keyboard with more octaves.

The Axiom 49 doesn’t disappoint. It’s not a keyboard you want to lug to a gig; it’s heavy as sin. However, it’s well-constructed and sturdy. I feel like I could fight off a zombie with it and still play a round of lounge jazz afterwards. Also, I dig how the drum pads feel and control. They’re pressure sensitive like the piano keys, and they’re lovely for hammering out tom hits or even for a quick lead pattern.

The best part is that it came with Ableton Live Lite 6, which was upgradeable to Live Lite 8 for free with their current ten-year promotion. I’d been thinking of getting the recently-released Intro version of Live 8, but this was close enough to help me decide if I needed the full version or not, saving me a hundred bucks.

I think that a lot of people out there would be fine with Live Lite. The one feature that I found a dealbreaker is that a single song can only have up to 6 effects in total across all instruments. (In Live Intro it’s 12.) The way I design my sounds, I hit that limit playing around on a single loop a few nights ago. It wouldn’t be a problem if I could freeze tracks or if the limit were for simultaneous effects in use, but even effects on tracks currently producing no sound count.

So I’ll be picking up the full version of Live pretty soon. I had a look at the Studio package but I can’t justify the extra expense for a lot of samples I don’t need at the moment, and I’m only interested in two of their custom software instruments.

The bonus of using Live: PureMagnetik has really cheap sample packs, and their guitar rig kits sound fricken’ awesome.

this week in meetings

Work has been topsy-turvy; this week our partner company on one of the current projects is here from Germany so that certain ideas (both technical and otherwise) can be sorted out. It’s been a lot of fun, especially since one of the visitors represents the merchandising part of the project.

It’s interesting to catch even these small glimpses of how toys, characters, and story have to play symbiotic roles for a project to be successful. This is my first real exposure to such things, so I’ve mostly kept my head down and just listened.

But I have better news than what’s going on at work: I finally have my Permanent Resident card for Canada! I’ve been a permanent resident since 1990, well before the cards were used, and the road to getting a card has been a trial, so I’m ecstatic that it’s all done. The benefit is that I can finally leave the country and return without having to carry a million and one documents proving that I who I say I am. I also don’t have to waste hours on returning, explaining to someone with no sense of humor why I don’t have my card.

I sense a New York shopping spree in my future, after Animation Mentor graduation in January.

looking for new goals

It’s not official yet, but I handed in my last assignment at Animation Mentor and I should be able to access the Alumni server in a few weeks barring a failure in the final minutes. (I don’t think that’ll happen, though.)

I feel elated.

I’m not happy with my final short film. The basic problem was too many cooks in the kitchen. I couldn’t stick with my original idea, and what my ideas turned into was so far removed that I wasn’t clear on where the film was supposed to be going when I began Class 6. My mentor for Class 6 did a good job of helping me wrestle the short together, but I never lost the sense that I was doing an assignment instead of working towards something I wanted to say.

So here I am, at the end of it. I probably learned as much during Classes 5 and 6 as I did throughout the first four AM classes; Cal’s lectures in Class 5, where he supplimented our video lessons with experiences and notes of his own, were my favorite classes. I want to go over those notes again, because I think I want to get into Story as a discipline.

I’m feeling good. I’m thinking I’ll take some time off from animating in my own time, for at least a few weeks. Then, who knows?

playing in coffee

I’m slowly coming out of the fog of Maya, now that I’m done with using it for Animation Mentor, and I’ve been trying to get back into Cinema 4D. I just wanted to post this short COFFEE script snippet. This looks through all the animation curves on an object and spits out information on them.

var op = doc->GetActiveObject();
var curTime = doc->GetTime();

println("\nKey dump for ", op->GetName(), ":\n");

var t = op->GetFirstCTrack();
if (t == NULL)
	println("Error.");

var i = 0;
var j = 0;
var k;
var c;

while (t != NULL) {
	i++;
	c = t->GetCurve();
	println("\tTrack ", i, ": ", t->GetName(), " -- ",
	c->GetKeyCount(), " keys.");

	for (j = 0; j < c->GetKeyCount(); j++) {
		k = c->GetKey(j);
		var bt = k->GetTime();
		println("\t\t", j, ": v", k->GetValue(), ", t:", bt->GetFrame(30));
	}

	t = t->GetNext();
}

println("Number of tracks: ", i);

The sad part is this: you can’t add new keys to curves in COFFEE; you can only read what’s there. (EPIC FAIL, Maxon.) At least now I know how to get keys and how the BaseTime class works.

Weak References

Last year while I was working at Red Rover, I heard the term “weak reference” in reference to a technique for referencing objects in 3DS Max. The Max TD used them for a variety of things. I didn’t quite understand what he was talking about at the time, since the last version of Max I used was 2.5 and I never did rigging or coding for it then.

More recently I’ve come to the same technique on my own both in Maya and in Cinema 4D, and was reminded of the name for it by that same TD over beers a few weeks back.

Essentially, weak references are variables on objects that contain a pointer to an object, and not a reference to it’s name. In Maya, for example, you may see rigging scripts written by TDs referencing specific objects by name or saving names of objects as they’re created and using those names to connect attributes or add constraints. In a clean scene this works fine, as long as the rigger is meticulous in their naming scheme and runs different stages of the rigging script in proper order.

But what happens when Maya namespaces become involved? As soon as you reference in an asset, every object that makes up that asset gets a namespace prefixed onto it’s name. If you’ve written scripts that require specific names, they break. If your layout files aren’t perfect and the namespace is different between two or more shots (as Maya is wont to append a number, regardless of what you specify), useful tools like character GUIs and the like break and you’re left doing namespace surgery in a text editor.

Weak references sidestep all this by giving you a permanent connection to an object regardless of name changes or namespace prefixes.

A good example is how I’m currently handling cameras in scenes. A decision was made early on, on the current project at work, to name cameras in layout files by the name of the shot / sequence. Normally this isnt a problem, but we’re using a renderer that’s not linked into Maya directly and therefore needs a command line batch exporter written. If all the cameras are named differently, and the camera’s animation has to be baked and exported as well, how do you go about picking the right object?

Using weak references, the problem becomes trivial. You create them as follows:

addAttr -ln "cameraObj" -at "message";

You’ve probably seen attribute connections of type message into IK handles and other things. The message attribute carries no data– that is, it never changes and causes no DAG recalculations. (This is doubly useful because you can connect the message attributes of two objects to message-typed user attributes in a cycle without causing a cycle error– more on that later.) However, the attribute can be used to get the name of the connected object like so:

listConnections object.messageAttribute;

It will return an array of strings. If you rename an object, you can get the object’s current name through the above command.

So where do you store these attributes? For the moment I’m using a trick I saw on the Siggraph ’08 talk by Blue Sky on procedural rigging: I create non-executing script nodes and store connections on them. In the camera example above, every scene has a master script node. On that node are a few attributes, including its “type” and a .message connection to the render camera. It’s them trivial to find the camera’s name:

string $sel[] = `ls -type "script"`;
for ($s in $sel) {
	if (`attributeQuery -node $s -ex "snCamera"`) {
		// this should be the one you need
		// normally I search for the type, but this is an example
		string $conn[] = `listConnections ($s + ".snCamera")`;
		// if it's only one connection incoming, then you're done.
		print("Camera is named " + ($conn[0]) + "\n");
	}
}

This technique can be extended to include all kinds of objects. It can also be very helpful for scripts like character GUIs that need to know what characters are present in a scene, and be able to change the positions of all those controls.

One final note on this for now: In Cinema 4D, every object and tag in a scene can be named the same. Searches for objects or tags by name are often fruitless because of this; if two objects or tags have the same name there’s really no easy way to tell which is which in a COFFEE script. What you can do, however, is create a user data variable that is of the Link type. This allows you to drag and drop an object into that variable’s edit field, and provides a permanent pointer to that object regardless of name. This is very useful in rigging; for example, you can always tell which joints in a leg are control joints, and which are bind joints, by creating links. You can also expose the links in XPresso and use the pointers as if you’d dragged an object onto the XPresso node window.

Jaspercation

I’ve never really taken vacations. There were a few done with the family as a kid, but we all know how those are– it’s not the same as when you choose destinations for yourself.

About a month and a half ago Trez asked if I could pop out to join her and her family for a vacation to Jasper. I had planned on being in Calgary for my birthday but she had other plans, so I made arrangements. I can’t express how glad I am that I did.

Part of it is that I haven’t really gotten to see Trez outside of weddings we were both attending or Kilbourne-related outings; while I enjoy both, neither are conducive to chatting with your best friend for a real length of time. This was different; all of us went for bike rides, swimming, and even managed a canoe row on Lac Moraine. I finally got to hang out with Franni’s hubby, and Trez and Franni’s parents, and felt the whole time like part of the family.

But that’s not all of it. I’ve been back to Alberta a few times now since returning from Japan. It’s different, don’t get me wrong — Calgary’s C-Train goes all the way past Crowfoot now, for frack’s sake — but I get there and feel the prairie wind on my face and the sun on my arms and see my darling Rockies to the West and I wonder how anyone lives anywhere else.

On Sunday afternoon while we were grabbing supplies for soap making, half the sky went dark and those large drops of rain you don’t get outside the prairies came down, fat and cold and lazy-slow. I swear it smells different out there, the rain, dustier and sharper than what we get in Toronto. Or maybe it’s just that my allergies never flared up despite how green everything was. Maybe it’s all in my head. In my head or not, it was like slipping into a warm bath after a long day. I chased the sun westward for three and a half hours and ended up the only place I’ve ever felt home.

So as I started typing this I was on the plane back to Toronto and I, yet again, wondered why I’m living in the East. Sure there are a lot of animation and game studios in Toronto and Montréal. Sure there are those who say that going back would be like living backwards, like regressing. Maybe they’re right. Thing is, as smart as living in Toronto is for me right now, smart hasn’t been winning out in my mind.

Okay, enough with all that. How about pictures? They’ll be up on my Flickr account soon enough; I had to edit through pics from Jamie’s wedding first. I’m actually two sets of photos behind now, with the shots from my and Cory’s birthdays.

a quick note on object snapping

A few weeks ago I got stuck while writing a foot snapping tool — the snapping code I used to use didn’t work on the rigs we inherited because there were a lot of pivot changes. I tried a bunch of more elegant ways to fix this but ended up doing the old standby:

delete `orientConstraint`;
delete `pointConstraint`;

Now, that solution wasn’t a satisfying one to me, so I kept looking for a better one.

Turns out there’s an easy fix. If you use getAttr on a transform node’s .worldMatrix, you get back the proper 4×4 set of float values that represents its final position in world space. Afterwards you can set the matrix of another object using xform. It’s pretty simple in either MEL or Python.


// this snaps one object to another using worldSpace matrix coordinates
string $sel[] = `ls -sl`;
float $m[] = `getAttr ($sel[1] + ".worldMatrix")`;
xform -ws -m $m[0] $m[1] $m[2] $m[3] $m[4] $m[5] $m[6] $m[7] $m[8] $m[9] $m[10] $m[11] $m[12] $m[13] $m[14] $m[15] ($sel[0]);

The MEL code is a bit ugly because of having to specifically reference each item in the array of floats, but it works. Here’s the Python equivalent. I keep it now as a button my shelf.


# uses matrices to snap one object to another
import maya
# yes, I put all my commands into the main namespace
from maya.cmds import *

sel = ls(sl=True)
mat = getAttr(sel[1] + ".worldMatrix")
xform(sel[0], ws=True, m=mat)

Katt's Mysterious 3D Lectures – Vector Application: A Better Rivet

You have the aim constraint under your belt. You can guess how a pole vector’s motion will change rotations with a look. You’re feeling a new sense of power and a desire to accomplish… things.

Now what?

Let’s start with something simple. Remember that old standby, the Rivet script, that I mentioned in my last post? Every good tutorial DVD I’ve bought over the years had it. Every rigger I’ve ever met uses it. As scripts go, it’s probably the most useful 2k on HighEnd3D.com.

But did you know it’s also broken?

Let me go back for a moment. A year ago, while I was working under a talented rigger who liked the Farenheit Digital system for creating nurbs ribbon rigs, was saddened by the fact that all licenses of Maya at our company were Maya Complete save two: his, and mine. This meant that the standard way of building ribbons, where you attach a Maya Hair follicle to the surface, wasn’t going to work as Maya Hair only comes with Unlimited. He mentioned something about using an aim constraint and a pointOnSurfaceNode or through the decomposeMatrix node to accomplish the same, although it didn’t work as well. So I was tasked with writing a python node plugin that accomplished the task. It worked well and quickly enough; 40 or so of them were live in the final rigs.

However I prefer to keep the number of non-standard nodes in rigs to a minimum. At my current place of work we realized a need for a follicle-like setup again, so I started researching.

At one point we’d thought we could solve the problem with the Rivet script. Rivet takes two edges, lofts them into a nurbs surface with history, then attaches to the surface a locator using a pointOnSurfaceInfo and an aim constraint. When the lofted surface is relatively square and doesn’t deform much, this works fine. When you try to use just the pointOnSurfaceInfo and aim constraint setup on a longer nurbs surface that deforms and bends, however, we found that the locators do not behave properly. Past a certain amount of twisting, the locators would rotate off in odd directions.

I played with the script and found that the pointOnSurfaceInfo node was feeding the surface normal into the aim constraint as the aim vector, with one of the tangent vectors as Up. Because of this, the aim constraint was causing the locator to flip. The way aim constraints work makes up vectors into suggestions, not rules. It also makes the third axis a product of the other two, as I showed in my last post.

In the end it was a simple fix: instead of using the surface normal (which wasn’t an illogical choice), I fed both surface tangents into the aim constraint and let the third axis, the normal, be the derived one. Since the tangent u and v vectors are always orthogonal regardless of how much you distort the surface, and since they always run in the right directions along the surface, you can be certain that the surface normal — a third orthogonal vector — will still end in the right place. (I bet the surface normal is derived from the cross product of the two tangent vectors anyway, internally.) No need for a custom node or to force the loading of decomposeMatrix; so far I haven’t seen any problems with this setup.

Steps for those who want to try this at home:

1) Create a pointOnSurfaceInfo node attached to your nurbs surface. Set it’s U and V parameters to get the output to the right place on your surface.

2) Use the createNode command to make an aimConstraint node.

3) Plug the pointOnSurfaceInfo’s tangentU into the aimConstraint’s target[0].targetTranslate, and the tangentV into the constraint’s up vector.