On this page |
概要
SOPフィルターノードのワークフローでは、そのノードを動作させるコンポーネント(例えば、ポリゴンやポイント)をユーザーに選択させることが多いです。 そのようなツールでは複数選択を許容/必須にする場合があり、例えば、"Copy to Points"ツールだと、コピーするジオメトリとコピー先のポイントを受け取ります。 選択したコンポーネントは、新しく作成されたノードの"Group"パラメータに入力します。
Pythonステートを使った独自ツールで選択に対応させる方法は3つあります:
-
選択の度にユーザーにお願いをする手動型のスクリプトによる選択。これは、既存のシェルフツールで行なわれている従来の方法です。私達は、このメソッドを使用することを強く推奨しています。
-
1つ以上のセレクターをバインドする方法。これは、手動型のスクリプトの選択に似ています。現在のところ、このメソッドは推奨していません。
-
単一の持続ジオメトリセレクターをバインドする方法。これは、アクティブなPythonステートに選択をお願いします。ユーザーが選択を完了した時に、
onSelection()
コールバックがTrue
を返すことで、その選択を受け取ることができます。
手動型のスクリプトによる選択
これは、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()メソッドの引数に関する情報は、そのヘルプを参照してください。