Baking animation to key per frame

   14153   17   4
User Avatar
Member
517 posts
Joined: Dec. 2013
Offline
Hi there,

I'm working on a project where I'll be FBX-ing out characters to Unity.

In the past when I've done this in XSI, I'd make a simple rig out of null objects and bake the main rig animation to that with a key per frame. Then ditch the main rig and export only the simplified version. This works great because I can make the main rig as full on as I want and Unity still just gets a simple version (that's less likely to break).

I'm trying to get this happening in Houdini and I can't find a way to bake animation to a null at a key per frame? Can anyone point me in the right direction with this?

Thanks,
Pete
User Avatar
Staff
476 posts
Joined: April 2014
Offline
In Houdini 15, you can bake the keyframes of a parameter with RMB on a parameter label in the parameter editor and then do “Channels and Keyframes/Bake Keyframes”.

The same command can also be triggered in the animation editor with RMB Bake Keyframes of selected segments.

You can also script it using HOM.Parm.keyframesRefit() to bake multiple parameters at the same time.

There's an RFE already logged to bake all the channels from the selected nodes.
User Avatar
Member
517 posts
Joined: Dec. 2013
Offline
Hey thanks Guillaume but that doesn't seem to work for this instance since the simple null rig doesn't have any actual animation on it so it thinks there's nothing to bake.
I tried adding scripts to the nulls transforms like this —> ch(“../object1/tx”) etc but that doesnt bake down either
User Avatar
Member
142 posts
Joined: Feb. 2012
Offline
Hey Pete,
I tried it using a null with (set to python language):
hou.node(“/obj/null_leaf/”).worldTransform().extractTranslates()
hou.node(“/obj/null_leaf/”).worldTransform().extractTranslates()
hou.node(“/obj/null_leaf/”).worldTransform().extractTranslates()

in the translates to get the world pos of the leaf node, but couldnt get the bake to do anything either
Showreel 2013 [vimeo.com]
User Avatar
Staff
476 posts
Joined: April 2014
Offline
Here's a scene to play with created with H15.0.350.

I used 2 techniques to create a shadow rig.

1) using CHOP_Object node to read an object transform in world space and write to unparented shadow nulls. I created a Null, added a CHOP manager inside its SOP network, and added a single Object CHOP node in it. You need to tweak the Target/Reference/Compute/Channel Range parameters. I did it in global space by make the reference /obj but it could work in local space in a hierarchy as well if you give it the parent as reference.

You can do the Baking from the Animation Editor, but for it to work you must make sure “Follow Scoped Channel References” is off. You can also turn on “Draw CHOP export in the Animation Editor RMB View submenu.” to see the chop export before baking. Make sure you override the range in the Bake Keyframes Dialog.

2) using ch() relative references on a shadow rig that has the same hierarchy.
What is tricky with relative references is the Animation Editor shows you the channels from the original objects. That is correct when you want your reference to act as a proxy, but we want to see the channels on the shadow nulls. For that case, the Scoped Parameter Lister has a setting called “Follow Scoped Channel References” which is on by default. If you turn it off, you'll notice your animation curves being drawn as dashed lines. Once you see the dashed lines, you can scope all the channels you want to bake, do CTRL-A to select all the segments, and do the Bake Keyframes command from the animation editor.

There's already an RFE to ease the process and bake expressions/chop from selected nodes in the netowrk editor. I know it is very tendious now as the feature was done mainly to bake keyframes in the context of selected segments.

Attachments:
bake_expressions_and_chop.hip (445.8 KB)

User Avatar
Member
517 posts
Joined: Dec. 2013
Offline
Thanks guys for checking that out.
And thanks so much for those sample scenes Guillaume!
I think I'll have to go with a Hierarchical version since that's what unity expects (for machanim). But I'm worried it will end up too troublesome doing that each time I need to update the animation
Maybe I'll have to look into scripting it, but I've never done that before in Houdini and I have a feeling its going to be scary.
User Avatar
Member
1265 posts
Joined: March 2014
Offline
One of those things(RFE Guillaume referred to) that seriously needs to be part of the toolset.
If SESI is serious about animation in H, they need to invest in tool development that would help us to do things quickly.
Werner Ziemerink
Head of 3D
www.luma.co.za
User Avatar
Staff
476 posts
Joined: April 2014
Offline
peteski
Thanks guys for checking that out.
And thanks so much for those sample scenes Guillaume!
I think I'll have to go with a Hierarchical version since that's what unity expects (for machanim). But I'm worried it will end up too troublesome doing that each time I need to update the animation
Maybe I'll have to look into scripting it, but I've never done that before in Houdini and I have a feeling its going to be scary.

OK, so here's another scene with some scripting in it.

The first thing I done was to add 2 python expressions to the Object CHOP inside the shadow nulls.

The expression on the Target Object automatically gets the correct path on the source rig by assuming the object names are the same on the source and shadow rigs.

The expression on the Reference Object looks at the parent or first input to get the correct local transform.

With that, you only need to to copy/paste a shadow null, reparent it and rename it the same as in the source rig.


After that, I created some buttons on the shadow rig root node to do the baking, delete all the keyframes and to toggle the chop export flags. The buttons are executing the code within the export_script multiline string parameter.

The script is using hou.Node.recursiveGlob() to search for all the Object nodes within the shadow rig. It then executes hou.Parm.keyframeRefit() on the transform parameters. It takes care of deleting the keyframes before the baking and to enable/disable the chop exports.

So the next step after that would be to put that script as a Pre-Render script on an FBX ROP node. ( I assume you are exporting to FBX for unity ). That way, the baking becomes a pre-export script, and you don't have to care about it anymore as a separated step.

Attachments:
bake_expressions_and_chop2.hip (323.7 KB)

User Avatar
Member
517 posts
Joined: Dec. 2013
Offline
Wow, thanks so much for posting that!
It hurts my brain a little to figure out how but I'm pretty new to Houdini so thats probably why.
I'll give it a try on a character and see how I go.

Thanks man.
User Avatar
Member
517 posts
Joined: Dec. 2013
Offline
Hey Guillaume,

I was testing out that script you made for baking and it seems like it's going to work for my project but I ran into a little issue, it seems that if there are any other objects (that I dont need to bake) in that subnet, it will end up with a totally reset transform. Like this -


is there a way I could include an if statement to only bake the objects with a CHOP net or something to avoid those others from being baked?
This setup is pretty simple since i'm just testing it out but I imagine there will end up being skinned elements and odds and ends within that subnet to be exported to Unity.


Thanks
Pete
User Avatar
Staff
476 posts
Joined: April 2014
Offline
Yeah! I'm really happy you were able to use the script.
There's a small bug in the script where it always writes keyframes with a value of 0.0 even for scale.

To check if a parameter has a CHOP override you can use hou.Parm.overrideTrack()
http://www.sidefx.com/docs/houdini15.0/hom/hou/Parm [sidefx.com]

I updated the code below to fix the scaling issue and to only do the work on params that have a CHOP export.



def setChopObjectExportFlag( n, f ):
chops = n.recursiveGlob('*/chopnet1/object1')
for c in chops:
c.setExportFlag( f )

def getObjNodes( n ):
return n.recursiveGlob('*',hou.nodeTypeFilter.Obj )

# Bake Keyframes button callback
# Recursively get all the object nodes
# Delete all the animation, re-enable the CHOP exports and Bake the CHOP to keyframes.
def bake_keyframes( n_path ):
enable_chop_exports(n_path)

print “Bake Keyframes”
n = hou.node(n_path)

objs = getObjNodes(n)
parm_names =

# Enable the export flags
setChopObjectExportFlag( n, True )

# Parms for the keyframesRefit.
refit = False
refit_tol = 0.0
refit_preserve_extremas = False
refit_bezier = True
resample = True
resample_rate = 1.0
resample_tol = 0.0
range = True
range_start = n.parm('bake_rangex').eval()
range_end = n.parm('bake_rangey').eval()
bake_chop = hou.parmBakeChop.KeepExportFlag

k0_start = hou.Keyframe( 0.0, range_start )
k0_end = hou.Keyframe( 0.0, range_end )
k1_start = hou.Keyframe( 1.0, range_start )
k1_end = hou.Keyframe( 1.0, range_end )

for obj in objs:
for parm_name in parm_names:
p = obj.parm( parm_name )

# No track, do nothing
if p.overrideTrack == None:
continue

p.deleteAllKeyframes()

# Add dummy keyframes on start and end.
if p in :
p.setKeyframe(k1_start)
p.setKeyframe(k1_end)
else:
p.setKeyframe(k0_start)
p.setKeyframe(k0_end)

p.keyframesRefit( refit,refit_tol,refit_preserve_extremas,refit_bezier, \
resample,resample_rate,resample_tol, \
range,range_start,range_end, \
bake_chop )

# Disable the export flags
setChopObjectExportFlag( n, False )

# Delete Keyframes button callback
def delete_keyframes( n_path ):
print “Delete Keyframes”
n = hou.node(n_path)

objs = getObjNodes(n)
parm_names =
for obj in objs:
for parm_name in parm_names:
p = obj.parm( parm_name )
p.deleteAllKeyframes()

# Enable Chop Export button callback
def enable_chop_exports( n_path ):
print “Enable CHOP Exports”
n = hou.node(n_path)
setChopObjectExportFlag( n, True )

# Disable Chop Export button callback
def disable_chop_exports( n_path ):
print “Disable CHOP Exports”
n = hou.node(n_path)
setChopObjectExportFlag( n, False )
User Avatar
Member
517 posts
Joined: Dec. 2013
Offline
Hey thanks heaps for updating that but I still seem to be having the same issue with it
I was wondering if maybe I've update the script in the wrong way. I copied your changes and pasted them into the property window.


Here's my scene, if you have a second maybe check it out - http://www.peterleary.com/ForumFiles/CharacterTest_02-5u6Cda4qBQ.hiplc [peterleary.com]

Thanks,
Pete
User Avatar
Staff
476 posts
Joined: April 2014
Offline
My bad.

Change:

if p in :


to:

if parm_name in :
User Avatar
Member
517 posts
Joined: Dec. 2013
Offline
Hey thanks!
This looks pretty cool now! I'll let you know how I go!
User Avatar
Member
73 posts
Joined: Dec. 2013
Offline
Hi guys!

Old post I know, but for the moment is the only one I have found with a similar problem like mine.

I have this null that was send it to me from maya, it has the animation of the head of that character, I attach the particles to that null so I can have the right movement of it.

But when I'm gonna bake them out and send them to Maya, is not baking the null motion.

Any idea on how to fix that?

Thanks!

Attachments:
help.png (403.6 KB)

CG Generalist / FX Artist
http://www.jleandrovfx.com [www.jleandrovfx.com]
Jason Leandro.
User Avatar
Staff
476 posts
Joined: April 2014
Offline
Hi Jason, how are you exporting your particles to Maya?
Do you want to get a null with animation in Maya, and have the particles parented to it or have a single particle cache with the null animation baked in?

My guess is it might be that you are exporting the particles from directly out of the SOP node and that it doesn't pickup the parent object transform.
User Avatar
Member
73 posts
Joined: Dec. 2013
Offline
Guillaume
My guess is it might be that you are exporting the particles from directly out of the SOP node and that it doesn't pickup the parent object transform.

Yes I'm exporting out of SOPs, I'm using a simple ROP Alembic.

I want a single particle cache with the null animation baked in.

Thanks for the reply Guillaume!
CG Generalist / FX Artist
http://www.jleandrovfx.com [www.jleandrovfx.com]
Jason Leandro.
User Avatar
Member
73 posts
Joined: Dec. 2013
Offline
Oh! Ok I found how to do it, I needed to Bake it out from OUT context not in SOPS.

Thanks Guillaume!
CG Generalist / FX Artist
http://www.jleandrovfx.com [www.jleandrovfx.com]
Jason Leandro.
  • Quick Links