This example illustrates how to retrieve and set transformations on object nodes.
Supporting files for this example are in
$HFS/houdini/help/hom/cookbook/object_xform, also found in the
cookbook/object_xform directory of
Load obj_xform.hip and you’ll see a series of boxes chained together in a transformation hierarchy. Translate and rotate a box object in the middle of the chain to see that the outputs of that box inherit the transformations.
Open up a Python shell window in Houdini and observe the effects on box_object4 in both the viewport and network editor as you enter the following:
# Store the hou.ObjNode for /obj/box_object4 into a Python variable. >>> box_object4 = hou.node("/obj/box_object4") >>> box_object4 <hou.ObjNode of type geo at /obj/box_object4> # Ask for box_object4's world transformation. This transformation matrix # includes the parm transformation (determined from the translate, rotate, # scale, etc. parameters on the object), pretransformations, parent # transformations, transformations on the containing object, etc. >>> xform = box_object4.worldTransform() >>> xform <hou.Matrix4 [[0.942106, -0.147233, -0.301261, 0], [0.134676, 0.988938, -0.062158, 0], [0.3070 8, 0.017987, 0.951514, 0], [-5.04816, -0.769449, -9.42593, 1]]> # Disconnect box_object4's input. box_object4 will move, since it no longer # inherits its input's transformations. If we print out its new transformation # matrix, we see that it's different. >>> box_object4.inputs() (<hou.ObjNode of type geo at /obj/box_object3>,) >>> box_object4.setFirstInput(None) >>> box_object4.inputs() () >>> box_object4.worldTranform() <hou.Matrix4 [[0.966956, 0, 0.254942, 0], [0, 1, 0, 0], [-0.254942, 0, 0.966956, 0], [0.885497 , 0, -3.01977, 1]]> # Restore box_object4's transformation to its previous value. We'll leave # its input disconnected, so we'll have unparented it but kept its position. # setWorldTransform will adjust the objects parameters to achieve the # desired end result, accounting for inputs, pretransforms, etc. >>> box_object4.setWorldTransform(xform)
Writing a Function to Unparent
Next, let’s package up the logic to unparent a node and keep its position into a function, and we’ll call that function on box_object4 from a shelf tool.
Reload obj_xform.hip so that box_object4 is parented again, and add the following code to a new shelf tool. Right-click on an empty area of the shelf, select New Tool, create a tool named “Unparent”, and add the following in the Script tab:
def unparentAndKeepPos(obj_node): """Unparent an object node, but keep it in the same position as it was when it was parented. """ xform = obj_node.worldTransform() obj_node.setFirstInput(None) obj_node.setWorldTransform(xform) unparentAndKeepPos(hou.node("/obj/box_object4"))
Unparenting the Selected Node
Let’s generalize the shelf tool to work with the viewport’s selected node instead of box_object4. To do that, we can use hou.SceneViewer.selectObjects to return the currently selected object. Here is the new shelf tool:
# The toolutils module ships with Houdini and is used to perform common # shelf tool operations. It can be found in $HFS/houdini/python2.5libs. import toolutils def unparentAndKeepPos(obj_node): """Unparent an object node, but keep it in the same position as it was when it was parented. """ xform = obj_node.worldTransform() obj_node.setFirstInput(None) obj_node.setWorldTransform(xform) # If an object is already selected, we'll use it. If nothing is selected, # we'll prompt the user to select something. If multiple objects are selected, # we'll use the last one, since that should correspond to the parameter pane # contents. viewer = toolutils.sceneViewer() obj_node = viewer.selectObjects(quick_select=True)[-1] unparentAndKeepPos(obj_node)
Reparenting the Selected Node
Next, let’s write another shelf tool that will reparent the selected node. It will prompt the user for the new parent node.
# The toolutils module ships with Houdini and is used to perform common # shelf tool operations. It can be found in $HFS/houdini/python2.5libs. import toolutils def parentAndKeepPos(obj_node, new_parent): """Parent an object node, but keep it in the same position as it was when it was unparented. """ xform = obj_node.worldTransform() obj_node.setFirstInput(new_parent) obj_node.setWorldTransform(xform) # We'll select the object to reparent in the same way the unparent tool works. # We'll prompt the user to select the new parent in the viewer. viewer = toolutils.sceneViewer() node_to_reparent = viewer.selectObjects(quick_select=True)[-1] new_parent = viewer.selectObjects(use_existing_selection=False, quick_select=True, prompt="Select new parent node")[-1] parentAndKeepPos(node_to_reparent, new_parent)