This example defines a Python SOP that copies its input, assigns a rainbow of colors to the input surface, and creates wires coming out of the surface that are uniformly distributed along it.
Supporting files for this example are in
$HFS/houdini/help/hom/cookbook/surface_wires, also found in the
cookbook/surface_wires directory of
Viewing the SOPs Output
Select the /obj/grid_object1/surface_wires1 node.
Play with the U and V divisions and wire length parameters.
Exploring the SOPs Implementation
The Surface Wires Python SOP is stored in PythonSops.otl. Right-click on the
surface_wires1SOP and bring up the Type Properties dialog.
Click on the Parameters tab to see the
wire_lengthparameters. These parameters were created exactly the same way you would for a normal digital asset.
Click on the Code tab to see the Python code that Houdini runs when the SOP cooks.
# When an instance of this Python SOP cooks, Houdini will have set hou.pwd() # to the Python SOP instance. Access the hou.Geometry object for this SOP. # Since we're calling from hou.SopNode.geometry from a Python SOP # implementation, we'll have write access to the geometry. geo = hou.pwd().geometry() # Create a Cd (color) point attribute. color_attrib = geo.addAttrib(hou.attribType.Point, "Cd", (1.0, 1.0, 1.0)) # Assign each point a unique hue value, with constant saturation and value. num_points = len(geo.iterPoints()) color = hou.Color() for point in geo.points(): fraction = float(point.number()) / num_points color.setHSV(((fraction * 255), 1, 1)) # The attribute stores RGB values, so ask for the color in RGB format. point.setAttribValue(color_attrib, color.rgb()) # This sop requires that the first primitive is a surface. surf = None if len(geo.iterPrims()) != 0: surf = geo.iterPrims() if not isinstance(surf, hou.Surface): raise hou.Error("The first primitive must be a surface") # Evaluate the surface at uniformly distributed positions. For each # point we evaluate, create a line facing outwards from the surface, # and give it the color at the surface. u_divisions = hou.evalParm("u_divisions") v_divisions = hou.evalParm("v_divisions") wire_length = hou.evalParm("wire_length") for u_index in range(u_divisions + 1): u = float(u_index) / u_divisions for v_index in range(v_divisions + 1): v = float(v_index) / v_divisions # Compute the position of the surface, and add the normal # vector (scaled by 2) to define the two points of the line. pos0 = hou.Vector3(surf.positionAt(u, v)) pos1 = pos0 + surf.normalAt(u, v) * wire_length # Compute the color of the polygon and create it. It will # be open, since it's a line. color = surf.attribValueAt(color_attrib, u, v) poly = geo.createPolygon() poly.setIsClosed(False) # Create the points, set their position and color, and # add them to the polygon. for pos in pos0, pos1: point = geo.createPoint() point.setPosition(pos) point.setAttribValue(color_attrib, color) poly.addVertex(point)
Creating a new Python SOP
Note that if you want to create your own Python SOP, you can do so by selecting File → New Operator Type and picking “Python Type” as the operator style.