Houdini 20.0 Pythonスクリプト

Pythonステート Nodelessステート

ビューアや検査ツールのように、特定のノードタイプに依存しないステートを実装する方法。

On this page

概要

(独自のViewer Stateを実装する基本的な方法は、Pythonステートを参照してください。)

いくつかのステートは元からアセットに関連付けられていて、アセットのパラメータを操作することで動作しますが、 ノードを使用しない 非常に便利なステートを記述することができます。このようなステートはPythonスクリプトのAPIを使って、既存のノード/ジオメトリを検査したり、Houdiniの他の設定を操作することができます。

例:

  • マウスポインタ下のポリゴンのPrimitiveアトリビュートすべての値を表示するステート。

  • マウスを左右にドラッグするとタイムラインをスクラブすることができるステート。

  • ユーザが独自の方法でビューを操作することができるステート。

How to

  1. ステートをインストールして実行する。

    特定のノードタイプに依存しないステートに関しては、Houdiniを起動した時に自動的にそのステートが登録されるように、$HOUDINIPATH/viewer_states/下にモジュールとしてステートコードをインストールするのが良いでしょう。

    アセットでNodelessステートを定義するのも良いでしょう。アセット内にステートを埋め込む方法を参照してください。

  2. ステートを起動するためのシェルフツールスクリプトを記述する。

    Note

    以下のスクリプトは、SOPレベルの検査ステートをセットアップします。 この種類の検査ツールは本来ならオブジェクトレベルで作成しますが、SOPレベルで動く検査ツールも非常に役立ちます。

    シェルフツールスクリプトでは、ビューアが既にSOPレベルなのかどうかをチェックすることができ、SOPレベルでなかった場合は、中で動作させるジオメトリオブジェクトを選択するようにユーザに促すことができます。

    import stateutils
    
    # SOPステートを実行するためには、まず最初にビューアが必ずSOPレベルにある必要があります。
    viewer = stateutils.findSceneViewer()
    network = viewer.pwd()
    if network.childTypeCategory() != hou.sopNodeTypeCategory():
        # まだオブジェクトの中に入っていない場合は、中で動作させるオブジェクトがどれなのかをユーザに尋ねます。
        objects = viewer.selectObjects(
            prompt='Select object',
            quick_select=False,
            use_existing_selection=True,
            allow_multisel=False,
            allowed_types=['geo']
        )
        if objects:
            # selectObjectsメソッドはリストを返します。ここでは、そのリストの1番目のアイテムのみを取得します。
            network = objects[0]
            # オブジェクトの中に入ります。
            viewer.setPwd(network)
        else:
            # ユーザがオブジェクトを選択せずにEnterを押してしまった場合。
            raise hou.Error("You must select an object to use this tool")
    
    # ビューアの現在のステートをmystateに設定します。
    viewer.setCurrentState("mystate")
    

    ノードを使用しないツールをアセットと一緒に埋め込んでしまっている場合は、そのアセットの Tools タブ内でこのシェルフツールを作成することができるので、そのアセットがインストールされた時にユーザが利用可能になります。

  3. setCurrentState()を使ってステートをアクティブにすると、そのステートのonGenerateメソッドがコールされます。このメソッドを使用することで、必要に応じてプロンプトを表示してビューアをセットアップすることができます。

    class MyState(object):
        def __init__(self, scene_viewer, state_name):
            self.scene_viewer = scene_viewer
            self.state_name = state_name
    
        def onGenerate(self, kwargs):
            # ユーザにプロンプトを表示します。
            self.scene_viewer.setPromptMessage("Hover over primitives to show info")
    
            # グループ選択ボックスを可視にします。
            self.scene_viewer.setGroupListVisible(True)
    

ビューポートメソッド

Houdiniはステートクラスをインスタンス化した時に、イニシャライザに対してhou.SceneViewer参照を渡します。 hou.SceneViewer.curViewportを使用することで、現在の ビューポート の参照を取得することができます。

(ビューポートは、ジオメトリを特定の向きで表示するビューです。デフォルトのビューアはPerspectiveビューを表示した単一ビューポートですが、ユーザは、Top, Front, Right, Perspectiveのビューポートを表示した“4画面ビュー”のように色々なビューポートの配置をセットアップすることができます。)

hou.GeometryViewportオブジェクトには、ビューの変更だけでなく、マウスポインタ下の内容を検査するのに役立つメソッドがあります。

例: スクラブツール

このOBJレベルのステートは、ビューア内でドラッグすると、タイムラインを前/後に動かすことができます。コンテキストメニューを使用することで、相対ドラッグなのか絶対位置なのかを選択することができます。

import hou


class ScrubState(object):
    def __init__(self, scene_viewer, state_name):
        self.state_name = state_name
        self.scene_viewer = scene_viewer
        self._base_x = self._base_frame = None

    def onGenerate(self, kwargs):
        self.scene_viewer.setPromptMessage(
            "Drag left/right to scrub along timeline"
        )

    def onExit(self, kwargs):
        self.scene_viewer.clearPromptMessage()

    def _scrub_abs(self, x):
        # マウスポインタの絶対位置(ビューアの全幅に対する割合)を取得して、そこから現行フレーム範囲に沿って遠くに動かします。

        width, _ = self.scene_viewer.contentSize()
        pct = x / float(width)
        start_frame, end_frame = hou.playbar.frameRange()
        frame = int((end_frame - start_frame) * pct + start_frame)
        hou.setFrame(frame)

    def _scrub_rel(self, x):
        # マウスポインタの現行位置と以前の位置の差を使用して、前/後に動かすフレーム数を計算します。

        if self._base_x is not None:
            delta = int((x - self._base_x) / 10.0)
            frame = max(0, self._base_frame + delta)
            hou.setFrame(frame)
        else:
            self._base_x = x
            self._base_frame = hou.intFrame()

    def onMouseEvent(self, kwargs):
        device = kwargs["ui_event"].device()
        if device.isLeftButton():
            x = device.mouseX()
            if kwargs["mode"] == "abs":
                self._scrub_abs(x)
            elif kwargs["mode"] == "rel":
                self._scrub_rel(x)
        else:
            self._base_x = None


template = hou.ViewerStateTemplate("scrub", "Scrub", hou.objNodeTypeCategory())
template.bindFactory(ScrubState)

menu = hou.ViewerStateMenu("scrub", "Scrub")
menu.addRadioStrip("mode", "Mode", "rel")
menu.addRadioStripItem("mode", "rel", "Relative")
menu.addRadioStripItem("mode", "abs", "Absolute")
template.bindMenu(menu)

このツールを簡単に試すには、このツールのコードをHoudini Source Editorウィンドウに貼り付けてから、Pythonシェルで以下のコードを実行します:

>>> hou.ui.registerViewerState(hou.session.template)
>>> scene_viewer = hou.ui.paneTabOfType(hou.paneTabType.SceneViewer)
>>> scene_viewer.setCurrentState("scrub")

Pythonスクリプト

はじめよう

次のステップ

リファレンス

  • hou

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

導師レベル

Python Viewerステート

Pythonビューアハンドル

プラグインタイプ