Channel Pose Constraint with retime functionality

Hey there,

since a long time we see the need for a fast and intuitive way to retime objects. Houdinis default way is to use chops as the way to go. With the help of an channel and warp node, chops enables us to do exactly what we want. The downside of this approach is, that we need to care about units, sampling rates, start/end, etc. For a typical employee it takes some minutes to set everything up.

Our approach is much more simple and pragmatic. With the help of vtorigin and vrorigin we grab the world transforms of the target object, and retime the fcurves with the chf function. It’s as simple as that. Limited functionality, but no more worries about sampling or framerates. Here is a video that is demonstrating the script:


import toolutils
import hou

selected_node = ""
selected = hou.selectedNodes()

if selected:
    selected_node = selected[0]
    scene_viewer = toolutils.sceneViewer() 
    selected_objects = scene_viewer.selectObjects("Select the Object to Constrain. To finish press Enter. \n If nothing is selected, an Object will be generated.",allowed_types = ["*"])
    if selected_objects:
        selected_node = selected_objects[0]
        obj = hou.node("/obj")
        selected_node = obj.createNode("null", "globalTransform")
if selected_node:
    scene_viewer = toolutils.sceneViewer() 
    target_objects = scene_viewer.selectObjects("Select the Goalobject to Constrain to. To finish press Enter.",allowed_types = ["*"])
    if target_objects:
        target_object = target_objects[0]        
        hou.ui.displayMessage("Nothing Selected. Abort constraining")

if target_object:
    parm_group = selected_node.parmTemplateGroup()
    parm_folder = hou.FolderParmTemplate("extras", "Extras")
    parm_folder.addParmTemplate(hou.FloatParmTemplate("currentFrame", "Current Frame", 1))
    parm_folder.addParmTemplate(hou.FloatParmTemplate("target_t", "Target Translate", 3))
    parm_folder.addParmTemplate(hou.FloatParmTemplate("target_r", "Target Rotate", 3))
    selected_node.parm("target_tx").setExpression('vtorigin("", "' + str(target_object.path()) + '")[0]' )
    selected_node.parm("target_ty").setExpression('vtorigin("", "' + str(target_object.path()) + '")[1]' )
    selected_node.parm("target_tz").setExpression('vtorigin("", "' + str(target_object.path()) + '")[2]' )
    selected_node.parm("target_rx").setExpression('vrorigin("", "' + str(target_object.path()) + '")[0]' )
    selected_node.parm("target_ry").setExpression('vrorigin("", "' + str(target_object.path()) + '")[1]' )
    selected_node.parm("target_rz").setExpression('vrorigin("", "' + str(target_object.path()) + '")[2]' )
    selected_node.parm("currentFrame").setExpression('$FF' )
    selected_node.parm("tx").setExpression('chf("target_tx", ch("currentFrame"))' )
    selected_node.parm("ty").setExpression('chf("target_ty", ch("currentFrame"))' )
    selected_node.parm("tz").setExpression('chf("target_tz", ch("currentFrame"))' )
    selected_node.parm("rx").setExpression('chf("target_rx", ch("currentFrame"))' )
    selected_node.parm("ry").setExpression('chf("target_ry", ch("currentFrame"))' )
    selected_node.parm("rz").setExpression('chf("target_rz", ch("currentFrame"))' )