22
Feb
12

ICE and Scripting

Hi, unfortunately I didn’t have a lot of free time to prepare this week’s post so there won’t be a tool available for download. I am still going to teach you some neat tricks if you’re willing to learn though.

This will be a half ICE / half script kinda deal again. We’ll learn something that I will one day implement in one big and really useful tool that will forever replace the current Deform Motion tools that are available in softimage because, let’s face it…they’re pretty bad! We won’t build the complete tool just yet, it’s quite an undertaking and I still need to clean up some code to make it all lighter and cleaner but I do have a prototype working that’s been production-proven so expect to see that appear at some point in the future.

The main goal of this exercise will be to try to copy animation FCurves from an animated object to some ICE FCurves because without a custom ICE node that reads FCurve data, that’s pretty much your best bet to access animation from ICE.

Alright, let’s start! We will build a really simple compound that doesn’t really do anything by itself. Now that you know how to import nodes and connect them together and make a compound, I’ll just show you the final result:

So what I’ve done is expose the 3 FCurve profiles so that they’re accessible from the outside of the compound, I’ve also grouped the In values in a single port using a passthrough node (you could also have used a scalar node instead of the pass through). The 3 outputs will reconstruct a 3D vector and that vector is our compound’s output.

That’s it! That’s all we need to build our proof of concept script. This one won’t be all that reusable, this is just to learn how things work so that we can later on use the concepts from this exercise in a more complex context. With this in mind, our variables won’t be as flexible as they usually are.

xsi = Application

null = xsi.Selection(0)
pntcloud = xsi.Selection(1)

Since this is only for testing purposes, we’ll set some rules for ourselves and follow them. We will always select the animated object first (in my case I use a null so I named my variable ‘null’) then the object that contains the ICETree (in my case, a pointcloud).

We’ll only cover the position FCurves in this post for the sake of simplicity so let’s grab the FCurves for the 3 position parameters.

posx = null.Kinematics.Local.Parameters('posx').Source
posy = null.Kinematics.Local.Parameters('posy').Source
posz = null.Kinematics.Local.Parameters('posz').Source

So now, we have the actual FCurves stored in variables, what we need now is the FCurve profiles from the ICETree. This is where things get a bit tricky. To access ICE nodes, you first need to grab the ICETree, then use a rather unpleasant succession of NestedObjects to find what you’re looking for. The nice thing about NestedObjects though is that you can just look at the explorer, use the names as they are written there, and you’ll most likely get what you’re looking for (see the example below)

tree = pntcloud.ActivePrimitive.ICETrees(0)
ports = tree.NestedObjects('Descendant Nodes').NestedObjects('Parameter FCurves').NestedObjects('Exposed Ports').NestedObjects

That gets us all the exposed data from our compound (don’t forget to export and re-import it, sometimes the port numbers get rearranged during the process). To find out where the FCurves from our compound are located within those exposed ports, we can use a temporary piece of code:

for index, port in enumerate(ports):
	print 'port #%s:  %s' % (index, port)

The %s that are used here tell the script to replace those characters by the values referenced outside the string. In my case, this is what I get when I print out my ports:

# port #0:  pointcloud.pointcloud.ICETree.Parameter_FCurves.Y
# port #1:  pointcloud.pointcloud.ICETree.Parameter_FCurves.X
# port #2:  pointcloud.pointcloud.ICETree.Parameter_FCurves.Z
# port #3:  pointcloud.pointcloud.ICETree.Parameter_FCurves.Vector
# port #4:  pointcloud.pointcloud.ICETree.Parameter_FCurves.Time

Using this, I now know that:

x = ports(1).Value
y = ports(0).Value
z = ports(2).Value

With 3d objects, you can usually copy FCurves directly, however ICE doesn’t allow us to simply paste our stored FCurves so we’ll need to rebuild them from scratch. Don’t worry though, this process is really fast. To build an FCurve you need 3 things, the key values, the frame at which they can be found, and the tangents associated with those keys.

Let’s build a function that will handle that part. Since we have the FCurves already, we can easily extract the keys from them, and from those keys, we can find out on what frames they are set and what tangent values they hold.

def pasteFCurve(source, target):
	keys = []
	tangents = []

	for key in source.Keys:
		keys.append(key.Time)
		keys.append(key.Value)
		tangents.append(key.LeftTanX)
		tangents.append(key.LeftTanY)
		tangents.append(key.RightTanX)
		tangents.append(key.RightTanY)

	target.SetKeys(keys)
	target.SetKeyTangents(tangents)

That’s it, let’s reassemble everything and we’ll end up with something like this:

xsi = Application

null = xsi.Selection(0)
pntcloud = xsi.Selection(1)


def pasteFCurve(source, target):
	keys = []
	tangents = []

	for key in source.Keys:
		keys.append(key.Time)
		keys.append(key.Value)
		tangents.append(key.LeftTanX)
		tangents.append(key.LeftTanY)
		tangents.append(key.RightTanX)
		tangents.append(key.RightTanY)

	target.SetKeys(keys)
	target.SetKeyTangents(tangents)

posx = null.Kinematics.Local.Parameters('posx').Source
posy = null.Kinematics.Local.Parameters('posy').Source
posz = null.Kinematics.Local.Parameters('posz').Source

tree = pntcloud.ActivePrimitive.ICETrees(0)

ports = tree.NestedObjects('Descendant Nodes').NestedObjects('Parameter FCurves').NestedObjects('Exposed Ports').NestedObjects

x = ports(1).Value
y = ports(0).Value
z = ports(2).Value

pasteFCurve(posx, x)
pasteFCurve(posy, y)
pasteFCurve(posz, z)

If you followed the steps above, you should end up with a script that will take the position FCurves from your animated null and copy them to your compound. This may seem useless now, but in a few weeks I might make you change your mind!

Sorry about the lack of production-ready tool this week, I’ll try to make it up next time

-Phil


1 Response to “ICE and Scripting”


  1. 1 Jules Stevenson
    September 20, 2012 at 10:55 am

    This totally just saved me hours. Much appreciated sir. Jules


Leave a comment


Enter your email address to follow this blog and receive notifications of new posts by email.

Join 5 other subscribers