Paths Example: Dynamically Creating Object Nodes
Overview
This example takes an arbitrary piece of text and builds a set of letters that get moved from random starting positions to target end positions. The starting positions are randomly chosen from points on an object (/obj/start_locations) and the end positions are distributed along a curve (/obj/target_path). The example creates a path between the start and end locations, creates one object per letter, and makes the letter objects follow the path at offset time interfaces. Finally, another object (/obj/shuttle) follows the whole path, giving the appearance of shuttling the letters to their destinations.
Location
Supporting files for this example are in $HFS/mozilla/documents/hom/cookbook/paths, also found in the cookbook/paths directory of cookbook_files.tar.gz.
Running the Example
Load paths.hip and hit play. Examine the nodes inside /obj/net. Then, run hou.session.build("PythonRocks") in a Python shell, hit play again, and look at the new contents of /obj/net.
Exploring the Code
hou.session contents:
import randomdef randomStartLocation():"""Return a random start location for a letter. Note that, because arandom seed isn't specified, this function will return a differentvalue each time it runs."""geo = hou.node("/obj/start_locations").displayNode().geometry()point_num = random.randint(0, len(geo.iterPoints())-1)return hou.Vector3(geo.iterPoints()[point_num].position())def targetPathLocation(u):"""Given a normalized parametric value, return the corresponding positionalong the target path."""target_path = hou.node("/obj/target_path").displayNode()return hou.Vector3([hou.hscriptExpression('primuv("%s", 0, "P", %d, %f, 0)' %(target_path.path(), i, u))for i in range(3)])def addPositionToCurve(curve, position):"""Given a curve sop and a position, add the position to the sop's listof points."""position_str = ",".join(str(x) for x in position)coords = curve.parm("coords")coords.set(coords.eval() + " " + position_str)def build(text):"""Build the path for some arbitrary text."""# If /obj/net already exists, destroy it and recreate a new subnet.net = hou.node("/obj/net")if net is not None:net.destroy()net = hou.node("/obj").createNode("subnet", "net")net.moveToGoodPosition()# Create an object for the path, and put a curve SOP inside it.curve_geo = net.createNode("geo", "path_curve")curve_geo.setDisplayFlag(False)curve = curve_geo.createNode("curve")curve.setDisplayFlag(True)# Create objects for each letter in the text.for index in range(len(text)):# Compute the parametric positions along the curve where the letters# will start and stop moving.u_start = float(index) / len(text)u_end = (index + 0.5) / len(text)# Find the start and end positions of this letter, and add those# positions to the path.start_pos = randomStartLocation()end_pos = targetPathLocation(float(index) / (len(text)-1))addPositionToCurve(curve, start_pos)addPositionToCurve(curve, end_pos)# Create a geometry object for the letter, and put a font SOP inside# it. Append a transform axis sop to rotate the letter.letter = net.createNode("geo")font = letter.createNode("font")font.parm("text").set(text[index])font.parm("fontsize").set(3)xform_axis = letter.createNode("xformaxis")xform_axis.parm("rot").set(90)xform_axis.setFirstInput(font)xform_axis.setDisplayFlag(True)letter.layoutChildren()# Set the letter object to follow the path at the right times.letter.parm("pathobjpath").set(curve_geo.path())letter.parm("pos").setExpression("clamp($F/500, %f, %f)" % (u_start, u_end))letter.parm("pathorient").set(0)# Add a final location for the shuttle to go to.addPositionToCurve(curve, randomStartLocation())net.layoutChildren()
See also: hou.node, hou.ObjNode.displayNode, hou.SopNode.geometry, hou.Geometry.iterPoints, hou.Point.position, hou.Vector3, hou.hscriptExpression, primuv, hou.Node.parm, hou.Parm.eval, hou.Node.createNode, hou.Node.moveToGoodPosition, hou.SopNode.setDisplayFlag, hou.Node.setFirstInput, hou.Node.layoutChildren, hou.Parm.setExpression
