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"))' )

Instance/copy objects with nulls

Hey there,

when dealing with real commercial productions it is, at some point, necessary to place object instances by hand. There for you have four options in Softimage.

  1. A hard copy of the object
  2. A clone of the object
  3. Put it in a Model and use an model instance
  4. Use ICE to distribute instances in combination with Nulls that have an PPG with an integer attribute to detect the instance.

Point four is the workflow I like the most, because it is super flexible. After the placement it is possible to change all attributes e.g. with a random size or position. Now the question is, how do I adapt my known workflow to Houdini? Exact the same way I do it in SI. Fist we need to create a null object with an integer attribute “instNR” for instance number, some instances and a geometry that holds the geometry.

Lets dive into geometry level. First I have tried to build a setup the classical way. With maaaany attribute create sops. 

“Going from top to bottom you see that I create all attributes I need to transfer the data from the null objects: i@instNR, f@pscale, v@scale, v@euler_rot, 4f@orient. In the point vop I convert the euler rotation to a quaternion rotation. This is needed because the copy sop is using quaternions. With the path attribute of the object_merge sop we can access all attributes like this: ch(@objname + “/../instNR”). The only attribute we have to samp is the Instance Number. The syntax in the copy sop is like this: point(“../Input_GEO_OUT1”, $PT, “pinstNR”, 0). The switch node can now access this attribute like this: stamp(“../copy_InstancesToPoints”, “pinstNR”, 0). This is all we need to get it working.

Much slicker is to do all attribute manipulation in an attribute wrangle.

That’s all. Easy to setup and effective. The only thing to notice here is, that this is a copy NOT a instance workflow. To really instance objects I recommend this tutorial. this workflows here can easily combined with this workflow. Here InstanceObjectsWithNulls you can download the example hip file.

Animating objects along curves

Hi again,

in this small tutorial I try to explain a workflow I’m using frequently, when I have to animate streams of objects. Here is a example for what I’m talking about:



Procter & Gamble
Dash 2 in 1
Saga Film
The Marmalade

As you can see different instances of flowers move along an curve. To get this working I make use of the u coordinate of curves and map it to an point array I’m generating. Next I guide you through how you do this in Houdini.

First hit tab do generate a new geometry, dive in add an add sop to generate the fist point. Next add a duplicate sop to duplicate the point as often as you want. With this done let’s create some attributes. We need Shape, Orientation and Scale. Give the Shape a integer, the Orientation a vector and the Scale a float type. To randomize the Orientation randomize the different channels with this function “fit(rand($PT),0,1,-360,360)” – this will give us a rotation between -360 to 360 in the different channels. For the expression of the shape we will add a function later. Optional we can create a fourth node to randomize the color. Just generate a Attribute Randomize node give it the Cd attribute and connect it to the stream. Great, that’s the fist one of the three base streams.


Let’s create the second stream. This will be the curve our points will fly on. Draw and curve, resample it and add a polyframe sop to get a Normal (N) and TangentU (tangentu) attribute.

Now we’ll do the fun part – Create a Point VOP to combine the two streams. Dive in and wire everything as shown on the picture below. As you can see see, our network got three inputs: Start, End and add. As the names of the parameters say, they will define the start and end point of our flying points. The add parameter is there to animate the points. The range will be between 0-1, which is a great range to remap with the u coordinate.

At this point it should look like this:

Ok so following build the third stream! Add a sphere, box, torus and connect them to a switch. Connect the switch to a transform node an take this as the primitives to copy input of a copy sop. Now take a Attribute Delete sop, connect the Point VOP to it and delete the point attribute N, tangentu and tangentv. This is impotent when working with the copy sop because it tracks the N attribute. I personally like to transfer the real rotation through the copy sop – so deleting is just fine. From this follows a OUT Null to keep things organized and to have always the same node to grap attributes from. Connect the null to the copy sop and do some stamping.

particleShape point(“../OUT_Values”, $PT, Shape,0)

OrientationX point(“../OUT_Values”, $PT, Orientation,0)

OrientationY point(“../OUT_Values”, $PT, Orientation,1)

OrientationZ point(“../OUT_Values”, $PT, Orientation,2)

Scale point(“../OUT_Values”, $PT, Scale,0)

Afterwards stamp the variables in the transform sop. To do so we can use this functions.

RotateX stamp(“../copy_ObjectsToPoints”, “OrientationX”, 0)

RotateY stamp(“../copy_ObjectsToPoints”, “OrientationY”, 0)

RotateZ stamp(“../copy_ObjectsToPoints”, “OrientationZ”, 0)

Unifrom Scale stamp(“../copy_ObjectsToPoints”, “Scale”, 0)

For the correct setup we need to streamline the switch and the shape variable. First get the Shape attribute in place. fit01(rand($PT),0,(opninputs(“../switch1”))) gets the number of imputs of the switch sop. In the switch sop set the item selector to stamp(“../copy_ObjectsToPoints”, “particleShape”, 2). To understand what’s going on go to the geometry spreadsheet. There should be a Shape variable that goes from 0-2, which is the number of elements that are connected to the switch. The switch knows from the copy sops particleShape variable which element to pick.

With all this done we got this result. It is already what I wanted. Control over the object movement and shape. The next step will be the variation of the different channels, to get a more irregular shape.

Before starting to randomize the position we need to store the pointpostion on the curve, as reference point for the rotation manipulation that will follow later. Create an attribute wrangle right after the Point VOP on the right side. type in this code:

vector @PCrv;
@PCrv = @P;

 This will generate a Variable PCrv what represents the curve postion. Following we need a Randomize Attribute VOP to give the points an initial position variance. This looks like this:

Fine. Lets randomize the point position along the u coordinate. There for add a Point VOP after the Randomize Attribute SOP. Dive in and build the setup like this. The setup shown below is just a random vector per point that will be ramped trough the u coordinate of the curve. I have promoted the add2 (Seed), multyply2 (random multiply), mix1 (effect blend) and the ramp.

That’s it for the position. Now let’s create another Point VOP for the rotation. Don’t become scarred it’s not as hard as it seems. We see three sections. A align orientation to curve tangentu section. Here I crate a euler rotation of the tangent vector that can be blended with the original rotation we set in the beginning. The lower part is to set the amount of rotation along the u variable. It is working exactly as in the last Point VOP. In the “Roate_along_CrvP” section I’m rotating the Points and orientations around the curve position point I’ve stored in the Attrib Wrangle earlier. I have promoted degtorad1 (the degrees to rotate), mix1 (blending between tangent vector and init roation), mix2 (effect blend) and the ramp.

Last but not least I have done the same thing for the scaling of the objects. Lay down another Point VOP and setup the network as shown below. I have promoted parm1(Seed), fit1 (size range), mix1 (effect blend) and a ramp

To finish, it is always nice to remove some more attributes that are not used. In the Attribute Delete SOP type in this list “N tangentu u PCrv tangentv”. At the end my tree looked like this.

With the final setup, a movement of many objects would look like this.

As a resume – We saw how to animate objects along a path and control effectively all parameters. For real production purposes it would be necessary to customize everything just a little bit more, depending on the requests of the job.


If you are interested in the setup. Here is a HIP file for Houdini 15. Thanks for reading.