Houdini 19.0 Pythonスクリプト

Pythonステート 選択

SOPノードステートの動作の一部としてユーザがジオメトリを選択できるようにする方法。

On this page

Python Viewerステート

概要

SOPフィルターノードのワークフローでは、そのノードを動作させるコンポーネント(例えば、ポリゴンやポイント)をユーザに選択させることが多いです。 そのようなツールでは複数選択を許容/必須にする場合があり、例えば、“Copy to Points”ツールだと、コピーするジオメトリとコピー先のポイントを受け取ります。 選択したコンポーネントは、新しく作成されたノードの“Group”パラメータに入力します。

Pythonステートを使った独自ツールで選択に対応させる方法は3つあります:

手動型のスクリプトによる選択

これは、HOMスクリプトを使ってシェルフツールスクリプト(通常ではアセットに埋め込みます)でユーザに選択をお願いして、ユーティリティ関数を使ってノードを作成してから、そのノードのステートにする従来のHoudiniのワークフローです。

ツールスクリプトの書き方に関する詳細は、ツールスクリプトを参照してください。 アセットタイプのカスタムPythonステートを記述する方法の詳細は、Pythonのステートとノードを参照してください。

import stateutils
import soptoolutils

pane = stateutils.activePane()
# (ネットワークエディタ内でノードを配置するのではなく)ビューア内にいる場合は、セレクタースクリプトのみを実行します。
if isinstance(pane, hou.SceneViewer):
    # まず最初に、コピーするプリミティブ(s)を尋ねます。
    source = stateutils.Selector(
        name="select_polys",
        geometry_types=[hou.geometryType.Primitives],
        prompt="Select primitive(s) to copy, then press Enter",
        primitive_types=[hou.primType.Polygon],
        # プリミティブ番号を入力するパラメータ
        group_parm_name="sourcegroup",
        # この選択の接続先となる新しいノードの入力
        input_index=0,
        input_required=True,
    )
    # 次に、コピー先のポイントを尋ねます。
    target = stateutils.Selector(
        name="select_points",
        geometry_types=[hou.geometryType.Points],
        prompt="Select points to copy onto, then press Enter",
        group_parm_name="targetgroup",
        # 各選択を正しい入力に接続することを忘れないでください。 :)
        input_index=1,
        input_required=True,
    )

    # この関数は、Selectorオブジェクトのリストを受け取り、それぞれの選択をユーザに促します。
    container, selections = stateutils.runSelectors(
        pane, [source, target], allow_obj_selection=True
    )

    # この関数は、runSelectors()からのコンテナと選択を受け取り、
    # マージと作成先のコンテキストを考慮して新しいノードを作成します。
    newnode = stateutils.createFilterSop(
        kwargs, "$HDA_NAME", container, selections
    )
    # 最後に、このノードのステートにします。
    pane.enterCurrentNodeState()

else:
    # ビューア以外での操作に関しては、ローレベルの関数で代用します。
    soptoolutils.genericTool(kwargs, "$HDA_NAME")

ジオメトリセレクターのバインド

hou.ViewerStateTemplate.bindGeometrySelector()を使用することで、ビューアがカスタムSOPステートになった時に実行するSOPレベルの単一セレクターをバインドすることができます。 ユーザが選択を完了すると、Houdiniは、あなたのステートのonSelection()コールバックメソッドをコールします。

onSelection()メソッドでは、そのメソッドに渡される辞書からselectionアイテム(hou.GeometrySelectionオブジェクト)を取得することができます。 その辞書のnameから現行セレクターを取得することもできます。 その選択を受け取りたいのであれば、そのメソッドでTrueを返すことで、Houdiniはセレクターを終了して、あなたのステートの通常の処理に戻ります。 Falseを返すことで、その選択を拒否して、セレクターの実行を継続させることができます。

これは、ノードを使用しないステートで役に立ちます。例えば、表示ジオメトリからコンポーネントを選択し、それらのコンポーネントの情報を表示するステートがそうです。

Houdiniは、複数のジオメトリセレクターをステートにバインドすることができ、hou.SceneViewer.triggerStateSelector()を使って、個々のセレクターを開始/終了することができます。 バインド時に設定可能な名前によって、それらのセレクターがトリガーされます。

class MyState(object):
    def __init__(self, state_name, scene_viewer):
        self.state_name = state_name
        self.scene_viewer = scene_viewer

    def onSelection(self, kwargs):
        sel = kwargs["selection"]
        sel_name = kwargs["name"]
        if sel_name == "selector1":
            # 3つのポリゴンを含んでいる選択のみを受け入れます。
            are_prims = sel.geometryType() == hou.geometryType.Primitive
            are_all_polys = all(pt == hou.primType.Polygon for pt in sel.primitiveTypes())
            selection = sel.selections()[0]
            count = selection.numSelected()

            return are_prims and are_all_polys and count == 3

        count = 0
        if sel_name == "selector2":
            # selector2 support
            selection = sel.selections()[0]
            count = selection.numSelected()
        return count > 0

template = hou.ViewerStateTemplate(
    "mystate", "My State",
    hou.sopNodeTypeCategory()
)
template.bindFactory(MyState)

# selector #1
template.bindGeometrySelector(
    name="selector1",
    prompt="Select three polygons",
    quick_select=False,
    use_existing_selection=True,
    geometry_types=hou.geometryType.Primitives,
    primitive_types=hou.primType.Polygon,
    allow_other_sops=False
)

# selector #2
template.bindGeometrySelector(
    name="selector2",
    prompt="Select a primitive",
    quick_select=True,
    geometry_types=hou.geometryType.Primitives
)

hou.ViewerStateTemplate.bindGeometrySelector()メソッドの引数に関する情報は、そのヘルプを参照してください。

オブジェクトセレクターのバインド

hou.ViewerStateTemplate.bindObjectSelector()を使用することで、ビューアがカスタムOBJステートになった時に実行するOBJレベルの単一セレクターをバインドすることができます。 ユーザが選択を完了すると、Houdiniは、あなたのステートのonSelection()コールバックメソッドをコールします。

onSelection()メソッドでは、そのメソッドに渡される辞書からselectionアイテム(hou.Nodeオブジェクトのリスト)を取得することができます。 その選択を受け取りたいのであれば、そのメソッドでTrueを返すことで、Houdiniはセレクターを終了して、あなたのステートの通常の処理に戻ります。 Falseを返すことで、その選択を拒否して、セレクターの実行を継続させることができます。

Houdiniは、複数のオブジェクトセレクターをステートにバインドすることができ、hou.SceneViewer.triggerStateSelector()を使って、個々のセレクターを開始/終了することができます。 バインド時に設定可能な名前によって、それらのセレクターがトリガーされます。

class MyOBJState(object):
    def __init__(self, state_name, scene_viewer):
        self.state_name = state_name
        self.scene_viewer = scene_viewer

    def onSelection(self, kwargs):
        cameras = kwargs["selection"]
        print "Number of cameras selected: ", len(cameras)

        return True


template = hou.ViewerStateTemplate("myOBJstate", "My OBJ State", hou.objNodeTypeCategory())
template.bindFactory(MyOBJState)

# カメラオブジェクトだけを選択するセレクターを追加します。
template.bindObjectSelector(
    prompt="Select camera object(s) and press Enter",
    quick_select=False,
    use_existing_selection=True,
    allowed_types=('*cam*',))

hou.ViewerStateTemplate.bindObjectSelector()メソッドの引数に関する情報は、そのヘルプを参照してください。

エントリーセレクターのバインド

現在のところ、このメソッドは推奨されていません

理論的には、上記のスクリプトのstateutils.Selectorオブジェクトとstateutils.runSelectors()と同様に、hou.ViewerStateTemplate.bindSelector()を使って複数のコンポーネントセレクターをステートにバインドすることができます。 ステートは、これらのセレクターを介して実行され、そのステートのonGenerate()コールバックでノードを作成することができます。

しかし、私どもは、それらの選択を手動でスクリプト化し、上記で説明しているようにユーティリティ関数を使ってノードを作成することを推奨しています。

Volatile選択のハンドル

Volatile選択(つまり、selectステートを介した選択)は、Viewerステートによって単にonSelectionハンドラーを実装するだけで可能です。 これは、指定したカテゴリのViewerステートセレクターをバインドする際に通常実装するものと同じハンドルです。 しかし、Volatile選択に対応させるために何もセレクターをバインドさせる必要はありません。 選択ハンドラーに関する詳細は、ここを参照してください。

Sキーを押してVolatile選択を終了させると、選択されているエレメントを入力としてonSelectionがコールされます。 オプションでonStartSelectiononStopSelectionのハンドラーを実装することで、Volatileセレクターが開始または終了する時にそれをコールすることができます。

既存選択のハンドル

ステートになった時に現行選択にアクセスすることができます。 ステートになった時に既に選択が存在していた場合、Houdiniは、その選択されたエレメント(s)をonSelectionハンドラーに渡して、自動的にその選択を使用するようになります。

Volatile選択と同様に、既存選択をハンドルするためにセレクターをバインドする必要はなくて、単にonSelectionを実装するだけで十分です。 1つ以上のセレクターがバインドされている場合、Houdiniは、auto_startセレクターまたはuse_existing_selector=Trueで設定された最初のセレクターを使用するようになります。

Secure選択サポート

セレクターが開始した時に、セレクターを現行ビューアの Secure選択 に準拠させるのかしないのかを設定することができます。 Secure選択は、例えば、ユーザがハンドルをクリックしたつもりが不意に選択を変更してしまわないようにするのに役立ちます。

セレクターは、以下のSecure選択オプションのどれかを使って登録することができます:

  • Obey: セレクターが現行ビューアのSecure選択設定に準拠します。これがデフォルトのオプションです。

  • On: セレクターが開始すると、セレクターが現行ビューアのSecure選択をOnに設定します。このオプションを使用すると、ステートを出た時に以前のビューアのSecure選択設定が復元されます。

  • Off: セレクターが開始すると、セレクターが現行ビューアのSecure選択をOffに設定します。このオプションを使用すると、ステートを出た時に以前のビューアのSecure選択設定が復元されます。

  • Ignore: このオプションを使用すると、セレクターはビューアのSecure選択設定を無視し、常にエレメントを選択することができます。

Secure選択が有効な時、アクティブセレクターは受け身モードなので、ユーザは現行選択を変更することができません。 Secure選択が無効な時、ユーザは現行選択を変更することができます。

詳細は、以下を参照してください:

Python Viewerステート

Pythonスクリプト

はじめよう

次のステップ

リファレンス

  • hou

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

導師レベル

Python Viewerステート

Pythonビューアハンドル

プラグインタイプ