Houdini 11 Houdini Object Model HOM Cookbook

Overview

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.

Location

Supporting files for this example are in $HFS/houdini/help/hom/cookbook/surface_wires, also found in the cookbook/surface_wires directory of cookbook_files.tar.gz.

Viewing the SOPs Output

  • Load surface_wires.hip.

  • 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_wires1 SOP and bring up the Type Properties dialog.

  • Click on the Parameters tab to see the u_divisions, v_divisions, and wire_length parameters. 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()[0]
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)