Houdini 17.0 Pythonスクリプト

Pythonステート 選択

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

On this page

Pythonビューアステート

概要

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

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

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

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

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

単一セレクターのバインド

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

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

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

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"]
        # 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


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

template.bindGeometrySelector(
    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
)

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

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

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

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

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()メソッドの引数に関する情報は、そのヘルプを参照してください。

Pythonビューアステート

Pythonスクリプト

はじめよう

次のステップ

Pythonビューアステート

Pythonでビューアステートを記述することで、ビューポート内でノードのユーザー操作をカスタマイズすることができます。

導師レベル

リファレンス

  • hou

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

  • Alembic拡張関数

    Alembicファイルから情報を抽出するための便利な関数です。