On this page |
概要
SOPフィルターノードのワークフローでは、そのノードを動作させるコンポーネント(例えば、ポリゴンやポイント)をユーザーに選択させることが多いです。 そのようなツールでは複数選択を許容/必須にする場合があり、例えば、"Copy to Points"ツールだと、コピーするジオメトリとコピー先のポイントを受け取ります。 選択したコンポーネントは、新しく作成されたノードの"Group"パラメータに入力します。
Pythonステートを使った独自ツールで選択に対応させる方法は3つあります:
-
選択の度にユーザーにお願いをする手動型のスクリプトによる選択。これは、既存のシェルフツールで行なわれている従来の方法です。私達は、このメソッドを使用することを強く推奨しています。
-
持続ジオメトリセレクターをバインドする方法。これは、アクティブなPythonステートに選択をお願いします。ユーザーが選択を完了した時に、
onSelection()
コールバックがTrue
を返すことで、その選択を受け取ることができます。1個だけでなくたくさんのジオメトリセレクターを追加することができます。 -
持続オブジェクトセレクターをバインドする方法。ジオメトリセレクターと同様ですが、代わりにオブジェクトを選択します。1個だけでなくたくさんのオブジェクトセレクターを追加することができます。
-
1つ以上のエントリーセレクターをバインドする方法。これは、手動型のスクリプトの選択に似ています。現在のところ、このメソッドは推奨していません。
-
Volatile選択をハンドルする方法。ビューアステートがアクティブになった時にVolatile選択にアクセスすることができます。
-
既存選択をハンドルする方法。ビューアステートがアクティブになった時に既存選択にアクセスすることができます。
手動型のスクリプトによる選択
これは、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.pystate", "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
ステートを介した選択)は、ビューアステートによって単にonSelection
ハンドラーを実装するだけで可能です。
これは、指定したカテゴリのビューアステートセレクターをバインドする際に通常実装するものと同じハンドルです。
しかし、Volatile選択に対応させるために何もセレクターをバインドさせる必要はありません。
選択ハンドラーに関する詳細は、ここを参照してください。
S
キーを押してVolatile選択を終了させると、選択されているエレメントを入力としてonSelection
がコールされます。
オプションでonStartSelection
やonStopSelection
のハンドラーを実装することで、Volatileセレクターが開始または終了する時にそれをコールすることができます。
既存選択のハンドル
ステートになった時に現行選択にアクセスすることができます。
ステートになった時に既に選択が存在していた場合、Houdiniは、その選択されたエレメント(s)をonSelection
ハンドラーに渡して、自動的にその選択を使用するようになります。
Volatile選択と同様に、既存選択をハンドルするためにセレクターをバインドする必要はなくて、単にonSelection
を実装するだけで十分です。
1つ以上のセレクターがバインドされている場合、Houdiniは、auto_start
セレクターまたはuse_existing_selector=True
で設定された最初のセレクターを使用するようになります。