SFM/Animating with Python

From Valve Developer Community
Jump to: navigation, search

Note! This information is very hack-y, and quite possibly wrong

Warning:This information is for advanced users only. Errors in Python scripting can seriously mess up your SFM session. In addition, the content on this page has been developed by someone with very little experience messing around with Source, SFM, and graphics programming in general. This stuff could very well irreparably mess up your scene. The dragons found here are basically the Python Script Command's dragons, but drunk AND pissed-off. Proceed with utmost caution.

How animation works

Animation is controlled by 'controls' and curves that denote how these controls change over time in SFM. Turns out, these curves are stored in the objects themselves, and you can see the data in the Element Viewer.

For instance, let's mess around with the animation curves of the Heavy. Load up the heavy model, then examine it in the Element Viewer. You can see the curves for the happybig motion, for instance, under heavy1->controls->happybig->channel->log->layers->float log, where you'll see the times and values array, which will give you the values that define the keyframes for the animation curve. Cool, right? But how do we mess with them?

Messing with some curves

Note: there's probably a better way to do this - there's some functions exposed here:

C:\Program Files (x86)\Steam\steamapps\common\SourceFilmmaker\game\sdktools\python\2.6\win32\Lib\site-packages\vs\movieobjects.py

CDmeFloatLogLayer stuff is around 17677, and probably gives the better way to set animation...

First, we need to select the control:

animSet = sfm.GetCurrentAnimationSet()

rootGroup = animSet.GetRootControlGroup()

happyBig = rootGroup.FindControlByName( 'happybig', True )

Now that we have the happyBig control, we can access the values. We use layers[0] to pick the 'float log' item, since it has a space in it so python doesn't want to let you select it by name.

print happyBig.channel.log.layers[0].values[0]

This gives you the value of the first point on the curve, which happens at happyBig.channel.log.layers[0].times[0]

Modifying values is straightforward - give it a float, and you're good to go

happyBig.channel.log.layers[0].values[0] = .5 #like this, for instance

Modifying time values is a bit trickier, since time is stored as a DmeTime_t type, and so assigning an integer to a time point won't work, so we use this code:

happyBig.channel.log.layers[0].times[0] = vs.DmeTime_t(10000)

Note, time there is in 1/10,000ths of a second.

In order to add in new keyframes, we can just insert new values. We'll want to make sure that we add both a time and a value, like this:

indexToInsertBefore = 1 # or whatever. You'll probably change that programatically

newValue = 0.5

newTime = vs.DmeTime_t(15000)

happyBig.channel.log.layers[0].values.insert(indexToInsertBefore, newValue)

happyBig.channel.log.layers[0].times.insert(indexToInsertBefore, newTime)

If we want to delete values, we'll have to use the del keyword - again, you'll want to delete it from both lists:

elementToDelete = 1

del happyBig.channel.log.layers[0].values[elementToDelete]

del happyBig.channel.log.layers[0].times[elementToDelete]