HOM Python SOP Example: Surface Wires

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 . 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)