Exporting .OBJ sequence from Houdini

While working with Houdini, I came across a project where I needed to export an animation as a serie of .obj files. Each .obj representing a frame of the animation.

In order to achieve that, I used a mix of node and python code to automate the process.

To showcase the process, this is the animation we are going to export:

Houdini Animation

Nothing fancy, this is not the purpose of this article ;D

Creating the Exporter HDA

The Exporter HDA will only consist of a python script responsible for moving the Houdini Timeline and export an .obj file at each frame. Creating an HDA for that gives us the opportunity to reuse that same behaviour for any kind of animation.

At the Objects level, we'll create a Subnetwork node and create an HDA from it. Right-Click on the node, "Create A Digital Asset". I called it "AnimObjExporter".

HDA Creation

Export HDA

We'll now go in the node 'Types Properties' and hide the default parameters:

Parameters

Parameter Interface

Let's expose our parameters interface. We'll need 4 parameters for our litle tool:

Export Node - The geometry node that we want to export.
Export Location - The directory in which the files will be written.
Frame Range - Animation range we want to export.
Export Button - Trigger the export.

Parameters Interface

Script implementation

We'll use a callback script called when 'Export' is pressed, in order to do that, we'll add this line on the callback:


hou.phm().export(hou.pwd())

Now in the Script tab add a Python module and this is where we'll code our export script.

We need to fetch parameters value and export the geometry node at each frame.
This is what this script is doing:


def export(node):
    export_node = hou.node(node.parm('export_node').evalAsString())
    
    if export_node is None:
        raise hou.Error('AnimObjExporter - Export Node not found...')
        return

    export_path = node.parm('export_folder').evalAsString()
    
    export_frame_range_min = node.parm('frame_rangemin').evalAsInt()
    export_frame_range_max = node.parm('frame_rangemax').evalAsInt()
    export_frame_count = export_frame_range_max - export_frame_range_min

    # reset current timeline...
    hou.setFrame(export_frame_range_min)
    # iterate over all frames and export it as static geometry.
    
    with hou.InterruptableOperation(
        "Exporting Frames As .Obj", open_interrupt_dialog=True) as operation:
        for cur_frame in range(export_frame_count):
            with hou.InterruptableOperation(
                "Exporting Frame As .Obj (%i/%i)" % (cur_frame, export_frame_count)
            ) as suboperation:
                
                hou.setFrame(cur_frame)
                path = export_path + 'frame' + '_' + str(cur_frame) + '.obj'
                export_node.cook()
                geo = export_node.renderNode().geometry()
                geo.saveToFile(path)

                percent = float(cur_frame) / float(export_frame_count)
                suboperation.updateLongProgress(percent)

The scene .hip file used to make this quick tutorial can be found here.