Jump to content
Milan

Keyframe moving

Recommended Posts

Hey guys. 

 

I've started working on a little toolkit to make life easier for animators but I ran into a bit of an issue. The whole thing is written in Python with Qt iterface.

 

One of the functions is simply moving keyframes on a timeline. Say I have keyframe on f10, f20 and f30. When I run the function it should shift all of them by given amount. The problem is that I can't figure out how to actually move a keyframe using python.

 

I collect keyframes from a parameter (that gives me a list of hou.Keyframe objects). Then I assumed I can just iterate through them and set new frame number. This however doesn't actually move the keyframes and if I assing the changed keyframe to it's parameter using hou.Parm.setKeyframe(keyframe) it makes a new key, but leaves the old one there as well.

 

So the questions is, am I missing something very obvious (I've been do a lot of python scripting for maya before, so maybe I just need to get my 'houdini style thinking cap' on), or am I out of luck? I could just delete the old keyframe once I create the new one, but I can't actually find anywhere in the reference, how to delete a keyframe using python in hou. 

 

This is simplified version of the code I'm using

import hou

def getKeyedParms(selected, parmList):
    for node in selected:
        parmsTemp = node.parms()
        for parm in parmsTemp:
            parm = parm.getReferencedParm()
            keyframes = parm.keyframes()
            if keyframes:
                parmList[parm] = keyframes
    return parmList

def shiftKeys(parmList, shift):
    with hou.undos.group('Shift Keys'):
        curFrame = hou.frame()
        for parm in parmList:
            for keyframe in parmList[parm]:
                if keyframe.frame() >= curFrame:
                    newTime = keyframe.frame() + shift
                    keyframe.setFrame(newTime)

selected = hou.selectedNodes()
parmList = {}

parmList = getKeyedParms(selected, parmList)
shiftKeys(parmList, 5)

Any tips appreciated. 

 

Share this post


Link to post
Share on other sites

Hi Milan,
I'm not sure if it's best workflow but I solved this by deleting all keyframes with parm.deleteAllKeyframes() and then rebuilding them.
This is my add inbetween keyframe script that shifts keyframes right or left from current timeslider position.

## add inbetween
## Petr Zloty 2014

import hou

# get all keyframes on all selected nodes
def getKeyframes(oNodes):
    keyframes = {}
    for oNode in oNodes:
        oParms = oNode.parms()
        for oParm in oParms:
             if oParm.keyframes() != ():    #if keyframe exists
                keyframes[oParm] = oParm.keyframes()
    return keyframes

#keyframes = hou.playbar.selectedKeyframes()
#recompute new keys
def inbetween(keyframes, offset):
    for parm in keyframes.keys():
        for key in keyframes[parm]:
            if hou.frame() <= key.frame():  #apply only to keys right from time cursor
                key.setFrame(key.frame()+offset)

        parm.deleteAllKeyframes()   #delete old keys

    #save new keys
    for parm in keyframes.keys():
        for key in keyframes[parm]:
            parm.setKeyframe(key)
    return True

oNodes = hou.selectedNodes()
keyframes = getKeyframes(oNodes)
inbetween(keyframes, 1) #add inbetween
#inbetween(keyframes, -1) #remove inbetween
Edited by pezetko
  • Thanks 1

Share this post


Link to post
Share on other sites

Yeah I had that as a backup option if I find that it's actually impossible to move them. Not that it's a problem deleting all keys and assigning them again. It just seem really strange that we can't actually offset them. Again maybe it's just my old maya head talking.

 

btw: looking at your code, it's very similar to my snippet, however I have a feeling that yours won't work on locked assets (e.g. most of the rigs) when your selection is controllers with published parameters. I had to use Parm.getReferencedParm() to get around that. ;)

Share this post


Link to post
Share on other sites

You are right, thanks for the tip. I didn't have any need to use it on any locked rigs yet. Most of the animation is still done in Softimage or Maya here (for interactive playback speed).
That undo stuff is also nice.

Share this post


Link to post
Share on other sites

until Hou.Parm.stretch() and hou.Parm.stretchSubrange() get implemented, you can use their Hscript command counterpart

chkeymvhttp://www.sidefx.com/docs/houdini13.0/commands/chkeymv

 

so your shiftKeys() may look like this:

def shiftKeys(parmList, shift):
    with hou.undos.group('Shift Keys'):
        for parm in parmList:
            fRangeStart = hou.frame()
            fRangeEnd = parmList[parm][-1].frame()
            hou.hscript( "chkeymv -r %s %s %s %s %s" %(parm.path(), fRangeStart, fRangeEnd, fRangeStart + shift, fRangeEnd + shift) )

you can even use chkeymv to stretch the range or reverse, also have look at other ch* commands as they may already do stuff you want to implement 

like chls for getting animated channels, etc

Share this post


Link to post
Share on other sites

Great! 

 

That should do the trick. There are some other things I was looking for in ch* commands. I'll just need to give them a bit of icing to make them easy to use for animators. 

 

Cheers

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×