Houdini 20.0 Pythonスクリプト

Pythonによるジオメトリノード(SOP)の定義

On this page

概要

  • Pythonを使って新しい、または再利用可能なジオメトリノードを定義したいのであれば、以下の“新しいノードタイプの作成”を参照してください。

  • 一回限りの変更をスクリプト化したいのであれば、Python SOPを使うことで、新しいノードタイプを作成することなく、ジオメトリ上のPython snippetを実行することができます。

Note

Python SOP内にノードパラメータを設定しないでください。 これによって、壊れた依存関係が生成されてしまい、たくさんの問題を引き起こしてしまいます。

新しいノードタイプの作成

  1. File ▸ New Asset を選択します。

  2. Operator Definitionpythonに、 Network TypeGeometry に設定します。

  3. Save To Library に、新しいノードタイプを保存するOTLライブラリファイルを設定します。

  4. Accept をクリックします。

    Edit Operator Type Propertiesウィンドウが表示されます。

  5. Edit Operator Type Propertiesウィンドウのオプションを使って新しいノードタイプのインターフェースを定義します。

  6. Code タブをクリックして、Pythonスクリプトを編集することでSOPの動作を定義します。

Tip

Type Propertiesウィンドウを閉じた後にスクリプトを編集したい場合、ノードのインスタンスをクリックして、 Type Properties を選択します。

コードの記述

ノードの入力のジオメトリを取得するには、以下のコードを記述します。

geo = hou.pwd().geometry()

hou.pwd()関数は、現在処理されているNodeを返し、geometry()hou.Geometryオブジェクトを返します。Python SOPの1番目の入力にSOPが接続されていれば、Houdiniは、Pythonコードを実行する前にその入力のSOPのジオメトリをPython SOPのジオメトリにコピーします。

Tip

1番目以外の入力からジオメトリを取得するには、Nodeinputs()メソッドを使用して、入力ノードを取得し、そのノードのgeometry()メソッドを使用することでジオメトリを取得することができます。

this_node = hou.pwd()
inputs = this_node.inputs()

# 2番目の入力からジオメトリを取得します
# (first input=0, second input=1, third=2など)
second_input_geo = inputs[1].geometry()

ジオメトリオブジェクト(この例ではgeo)に対してメソッドをコールすれば、出力するジオメトリを修正することができます。ジオメトリを制御する方法は、hou.Geometryオブジェクトのドキュメントを参照してください。

例えば、ポリゴンをジオメトリに追加するには、以下のコードを記述します:

poly = geo.createPolygon()
for position in (0,0,0), (1,0,0), (0,1,0):
    point = geo.createPoint()
    point.setPosition(position)
    poly.addVertex(point)

“filter”ノードよりも“source”ノードを作成したい場合は、単にType PropertiesでMaximum Inputsを0に設定すればいいだけです。hou.pwd().geometry()をコールすると追加可能な空っぽのジオメトリが返されます。

SOPを中断可能にする

指定した入力ジオメトリが膨大なために、ノードの処理に時間がかかる場合、 ⎋ Escを押してその処理を中断したい場合があります。SOPを中断可能にするには、定期的にhou.updateProgressAndCheckForInterrupt()をコールする必要があります。例えば、 ⎋ Escを押すと、このSOPの処理が停止します:

geo = hou.pwd().geometry()

# 各ポイントの移動量を調べるために、"t"パラメータを評価します。
translation = hou.Vector3(hou.parmTuple("t").eval())

for point in geo.points():
    # ポイント毎に新しい位置を設定します。
    point.setPosition(point.position() + translation)

    # ユーザがEscapeを押したかどうかを確認します。
    if hou.updateProgressAndCheckForInterrupt():
        break

SOPのエラーと警告

Python SOPに例外が発生すれば、ノードがエラーとして赤く表示されます。ノードをクリックすることで、そのエラーのスタックトレースを見ることができます。

ユーザ側にPythonスタックトレースを表示させないようにエラーメッセージを生成するには、hou.NodeErrorの例外を発生させてください。例えば、

raise hou.NodeError("Invalid parameter settings")

を実行すると、"Invalid parameter settings"のエラーメッセージでノードが赤く表示されます。同様に、ノードの警告を追加するには、hou.NodeWarningのインスタンスを発生させます。

新しいアトリビュート用ローカル変数の作成

hou.Geometry.addAttribには、Houdiniが、新しく追加したアトリビュート用のローカル変数を作成するかどうか設定するパラメータがあります。直接varmapアトリビュートを修正する必要はありません。

SOPコードのプロファイリング

PythonのcProfileモジュールによってPython SOPをプロファイリングすることができます。

Tip

UbuntuをOSに使用している場合、Ubuntuでは標準ライブラリがpstatsを持っていないので、aptitudeを使ってpython-profilerをインストールします。

トップレベルでたくさんのステートメントを記述するのではなく、関数内で作業が完結するように、あなたが作成したSOPにスクリプトを記述します。例:

def cook():
    poly = geo.createPolygon()
    for position in (0,0,0), (1,0,0), (0,1,0):
        point = geo.createPoint()
        point.setPosition(position)
        poly.addVertex(point)

cook()

cProfileをインポートし、あなたが作成した関数を直接コールせずにcProfile.runctxを使ってコールします:

def cook():
    poly = geo.createPolygon()
    for position in (0,0,0), (1,0,0), (0,1,0):
        point = geo.createPoint()
        point.setPosition(position)
        poly.addVertex(point)

cProfile.runctx('cook()', globals(), locals())

これにより、ノードが処理される時に、スクリプトのランタイムの要約がPythonシェルに表示されます。

SOPの一部をC++で記述する

SOPの一部をC++で記述する簡単な方法は、C++を使ったhouモジュールの拡張を参照してください。

デジタルアセット外でコードを保存する

バージョン管理システムでソースコードを管理するために、デジタルアセット外にソースコードを保存したい場合があります。Type Propertiesダイアログを使って、アセットのパラメータをセットアップし、Pythonソースコードをotlファイルに挿入することができます。

以下の関数を使えば、外部ファイルからPythonソースコードを読み取り、それをデジタルアセットに反映することができます:

def loadPythonSourceIntoAsset(otl_file_path, node_type_name, source_file_path):
    # Pythonソースコードを読み込みます。
    source_file = open(source_file_path, "rb")
    source = source_file.read()
    source_file.close()

    # OTLファイルからアセット定義を探します。
    definitions = [definition
        for definition in hou.hda.definitionsInFile(otl_file_path)
        if definition.nodeTypeName() == node_type_name]
    assert(len(definitions) == 1)
    definition = definitions[0]

    # アセットのPythonCookセクションにソースコードを保存します。
    definition.addSection("PythonCook", source)

Pythonスクリプト

はじめよう

次のステップ

リファレンス

  • hou

    Houdiniにアクセスできるサブモジュール、クラス、ファンクションを含んだモジュール。

導師レベル

Python Viewerステート

Pythonビューアハンドル

プラグインタイプ