Houdini 21.0 Pythonスクリプト

Pythonで独自のビューアハンドルを記述する方法

ビューアハンドルは、インタラクティブにパラメータを変更することができる独自ハンドルです。

On this page

Pythonビューアハンドル

概要

Houdiniには、Pythonでカスタムビューアハンドルを実装するためのフレームワークが備わっており、Pythonステートのワークフローを自由にカスタマイズするための幅広い機能が揃っています。

  • DrawableガジェットまたはDrawable 2Dを使用して、ハンドルコンポーネントの描画、ピック、ハイライトを行なうことができます。

  • COP Pythonハンドル専用のhou.ViewerHandleDraggerまたはdrawable2d.Dragger2Dを使用して、マウス制御を拡張することができます。

  • Houdiniパラメータを使用してパラメータを定義し、特定のパラメータをPythonステートにエクスポートするように選択することができます。

  • hou.GeometryDrawableまたはhou.Drawable2Dを使用してガイドジオメトリを作成することができます。

  • ローレベルでマウス、キーボード、タブレットのイベントに応答することができます。

Viewer Handle Code Generatorを使用することで、様々なサンプルソースからソースコードを作成することができます。 Pythonハンドルソースコードを配置してHoudiniに登録すると、Pythonステートは、ハンドルのバインドを介して一般的な方法でそれらのコードを使用することができます。

Houdiniにビューアハンドルをインストールする方法

HoudiniのPythonハンドルは、Pythonファイルモジュール内で実装するか、HDA内に直接埋め込むか、いずれかの方法で実装することができます。 どちらの方法でも、Pythonステートの登録プロセスと同様に、HoudiniにPythonハンドルをインストールするための登録コールバックが必須となります。

createViewerHandleTemplateという名前の登録コールバックは、Pythonハンドルの構造と動作を定義します。 これには、ハンドルタイプ名、パラメータ、ガジェットなどが含まれます。 Houdiniはこの情報を使用して、Pythonステートで必要になるPythonハンドルオブジェクトをインスタンス化します。 Pythonハンドルの内容の定義に関する詳細は、hou.ViewerHandleTemplateを参照してください。

Pythonハンドルの作成を迅速に行なうには、Viewer Handle Code Generatorを利用すると良いでしょう。 このツールは、基本的なハンドルコードと必要な登録関数を生成します。 このコードジェネレータは、Viewer Handle Browserウィンドウ、または、HDAに埋め込まれたビューアハンドルのOperator Type PropertiesウィンドウのHandle Scriptタブからアクセスすることができます。

コードを手動で作成することも可能ですが、コードジェネレータを使用することで開発プロセスが短くなり、構文エラーのないPythonハンドルを迅速に動作させることができます。

Pythonハンドルの登録は、Houdiniの起動時またはhou.ui.registerViewerHandleやhou.ui.reloadViewerHandleなどの登録APIを介して行ないます。

典型的な登録コールバックは以下のようになります:

def createViewerHandleTemplate():
    """ このエントリポイントは、ビューアハンドルをHoudiniに登録するのに必須です。
    """
    handle_type = 'viewer_handle_intro1'
    handle_label = 'Viewer Handle Intro1'
    handle_cat = [hou.sopNodeTypeCategory()]

    template = hou.ViewerHandleTemplate(handle_type, handle_label, handle_cat)
    template.bindFactory(Handle)

    # 他のバインドをここで実装します。
    return template

Note

PythonハンドルとPythonステートは、Houdini起動時にほぼ同時にインストールされますが、これら2つにおける登録の順番は重要ではありません。 Houdiniでは、PythonステートがPythonハンドルをバインドできるようにそのPythonハンドルが先にインストールされている必要はありません。 この登録の過程では、PythonハンドルパラメータとPythonステートノードパラメータ間のバインド情報のみが収集されます。 これらのバインドは、後でPythonステートが実行された時にHoudiniによって使用され、この登録の過程では、適切な検証が行なわれ、問題があればバインドエラーが起きます。

アセット内にハンドルを埋め込む方法

以下の手順は、Python ビューアハンドル を埋め込むためのSOPアセットの作成方法について説明しています。

  1. Objectレベルで、⇥ TabメニューからGeoオブジェクトを作成します。

  2. そのgeo1ノードをダブルクリックして、ジオメトリネットワークの中に入ります。

  3. ⇥ TabメニューからSubnetworkノードを作成します。

  4. そのsubnet1ノードを右クリックして、 Digital Asset → Create New を選択します。

  5. Type Name をhandle_demo、 Asset Label をHandle Demo、 Library Path をEmbedded in .hip Fileに設定します。

    ライブラリの保存先をEmbeddedに設定すると、そのアセットはアセットライブラリではなく現行シーンファイル内に保存されます。

  6. Author 、 Branch 、 Version のチェックボックスのチェックを外します。

  7. そのアセットのType Propertiesウィンドウが開きます(そのアセットタイプのインスタンスを右クリックして Type Properties を選択)。

  8. Interactive|Handle Script タブをクリックします。

  9. ハンドルコードを生成するために New… ボタンをクリックします。

  10. Samples 項目で Rotate を選択して、 Accept をクリックします。

  11. Apply ボタンをクリックして、その新しいハンドルを登録します。

このHandle Scriptエディターには、ジオメトリを軸回転させることができるPythonハンドルのコードが表示されているはずです。 この新しいハンドルは、Viewer Handle Browserペインのツリー内のHandle Demoノード下にリストされているはずです。

この新しいハンドルをテストするには、そのハンドルとバインドさせるビューアステートを作成する必要があります。

  1. Interactive|State Script タブをクリックします。

  2. ステートコードを生成するために New… ボタンをクリックします。

  3. Name フィールドには、 ステートの名前 としてstate_rotate_demoと入力します。

  4. Samples 項目で Static Handle を選択して、 Accept をクリックします。

  5. 以下の行を

    HANDLE_TYPENAME = "unknown"

    以下の内容に置換します。

    HANDLE_TYPENAME = "handle_demo"

  6. 以下の行を

    template.bindHandleStatic( HANDLE_TYPENAME, HANDLE_NAME, [] )

    以下の内容に置換します。

    template.bindHandleStatic( HANDLE_TYPENAME, HANDLE_NAME, [("ry","ry")] )

  7. アセット内にryという名前のfloatパラメータを追加します。

  8. Accept をクリックします。

この新しいstate_rotate_demoステートは、Viewer State Browserペインのツリー内にリストされているはずです。 このstate_rotate_demoノードを展開すると、その新しいhandle_demoエントリが見つかります。

それでは、geo1オブジェクト内にBox SOPを作成してディスプレイフラグを有効にし、そのBoxボックスのRotate Yフィールドにch("../subnet1/ry")を追加してください。

ネットワークエディタ内でHandle demoアセットノードを選択します。マウスをシーンビューア内に移動させてEnterを押します。すると、ハンドルが緑色のリングで表示され、そのリングをドラッグすると、ボックスが回転します。

Houdiniパスからハンドルを読み込む方法

以下の手順では、Houdini起動時に自動的に登録されるPythonハンドルモジュールの作成方法について説明しています。 このサンプルは、すべてのPythonハンドルコンテキストで有効ですが、 Viewer Handle Code Generator で用意されているサンプルの中には、以下に示すガジェットサンプルのように、COP Pythonハンドルコンテキストでは利用できないものもあります。

  1. New Pane Tab Type ▸ Inspectors ▸ Viewer Handle Browser メニューからViewer Handle Browserウィンドウを開きます。

  2. ブラウザのツールバーのリストメニューからSopカテゴリを選択します。

  3. File ▸ New Handle… メニューでViewer Handle Code Generatorを開きます。

  4. ハンドルの名前 として Name フィールドにhandle_demoと入力します。

  5. Samples オプションでGadgetを選択して、 Accept をクリックします。

サンプルコードを含んだ新しいPythonハンドルファイルが$HOUDINI_USER_PREF_DIR/viewer_handles/handle_demo.pyとして保存され、Viewer Handle BrowserツリーにHandle demoとしてリストされているはずです。

Gadgetサンプルが生成するコード:

import hou
import resourceutils as ru
import viewerhandle.utils as hu

#使用方法: 何も処理をせずハンドルガジェットを描画するだけの単純なハンドル。

GADGET_PIVOT = "pivot"
SCALE = 250.0

class Handle(object):

    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

        # ハンドルのトランスフォーム操作をサポートするユーティリティクラス。
        self.xform_aid = hu.TransformAid(self,kwargs)

        # ここでは、ガジェットをクラスアトリビュートとして保存します。
        # ガジェットはself.handle_gadgets attributeを介していつでも利用可能なので、これは任意です。
        color_options = ru.ColorOptions(self.scene_viewer)
        self.pivot = self.handle_gadgets[GADGET_PIVOT]
        self.pivot.setParams({"draw_color":color_options.colorFromName("HandlePivotColor")})

        # ピボットガジェットにBoxジオメトリを割り当てます。
        sops = hou.sopNodeTypeCategory()
        verb = sops.nodeVerb("box")
        verb.setParms({"type":1, "scale":0.1, "divrate":(2,2,2)})
        pivot = hou.Geometry()
        verb.execute(pivot, [])
        self.pivot.setGeometry(pivot)
        self.pivot.show(True)

    def onDraw( self, kwargs ):
        draw_handle = kwargs["draw_handle"]

        # ピボットガジェットを描画します。
        self.pivot.draw(draw_handle)

    def onDrawSetup(self, kwargs):
        """ 描画、ピック、ロケート(マウス下の検索)の操作をする前にコールされます。"""

        # カメラ位置に関係なくスケール係数でピボットガジェットをスケールします。
        origin = hou.Vector3()
        scale = self.handle_context.scaleFactor(origin)*SCALE
        scales = [scale]*3

        xform = self.xform_aid.updateTransform(s=scales)
        self.pivot.setTransform(xform)

def createViewerHandleTemplate():
    """ 登録するビューアハンドルテンプレートを作成して返すための必須エントリポイント。"""

    handle_type = "handle_demo"
    handle_label = "Handle demo"
    handle_cat = [hou.sopNodeTypeCategory()]

    template = hou.ViewerHandleTemplate(handle_type, handle_label, handle_cat)
    template.bindFactory(Handle)
    template.bindIcon("MISC_python")

    # Drawable Gadgetをハンドルにバインドします。
    # このガジェットは、基本的にはビューポート内でインタラクティブに操作可能なハンドルコンポーネントを定義する際に使用されるGeometry Drawablesです。
    #
    # このガジェットは、マウス下の位置の特定やピックといった一般的なハンドル操作を実行する際にHoudiniで使用されます。
    #
    # ガジェットインスタンスは、Houdiniで生成され、このデータメンバーを介してHandleオブジェクトで利用可能にします:
    # self.handle_gadgets: 名前でキーを設定可能なガジェットの辞書。
    template.bindGadget( hou.drawableGeometryType.Face, GADGET_PIVOT )

    return template

このハンドルをテストするために、以下の手順に従います:

  1. Objectレベルで⇥ Tabメニューを使用してGeoオブジェクトを作成します。

  2. そのgeo1ノードをダブルクリックしてGeometryネットワークの中に入ります。

  3. ⇥ Tabメニューを使用してSubnetworkノードを作成します。

  4. そのsubnet1ノードを右クリックして Digital Asset → Create New を選択します。

  5. Type Name をstate_handle_demo、 Asset Label をState Handle Demo、 Library Path をEmbedded in .hip Fileに設定します。

    このライブラリの保存場所をEmbeddedに設定することで、アセットライブラリではなく現行シーンファイルにアセットが保存されます。

  6. Author 、 Branch 、 Version のチェックボックスのチェックを外します。

  7. このアセットのType Propertiesウィンドウが開きます(アセットタイプのインスタンスを右クリックして Type Properties を選択)。

  8. Interactive|State Script タブをクリックします。

  9. New… ボタンをクリックすると、Viewer State Code Generatorダイアログが開きます。

  10. Samples オプションで Static Handle を選択して Accept をクリックします。

  11. その新しいステートソースコードの中の HANDLE_TYPENAME に“handle_demo”に設定して Accept をクリックします。

  12. state handle demoノードを選択して、ビューア内でEnterキーを押します。

これでPythonハンドルデモがアクティブになり、原点にピボットガジェットが表示されているはずです。

ハンドルを実装する方法

このセクションでは、Pythonハンドルの実装について詳しく説明します。 ゼロから作成するのは難しく、エラーが発生しやすいです。 このプロセスを効率化するには、Viewer Handle Code Generatorの使用を検討してください。 このツールには、Pythonハンドルの基本構造を生成するのに活用できる様々なコードサンプルが用意されています。

Pythonハンドルを実装するには、Pythonクラスを作成する必要があります。 以下のセクションでは、サポートされているクラスメソッドの概要を説明します。

Note

Houdiniには、viewerhandle.utilsというPythonモジュールが用意されています。 このモジュールには、ビューアハンドルのインストールをサポートしたり、独自のハンドルの実装に役立つドキュメント化された様々なユーティリティ関数/クラスが含まれています。 このモジュールは、$HHP/viewerhandleフォルダに配置されています。

Tip

$HHP環境変数は、Houdiniのインストールディレクトリ内のPythonライブラリを含んだサブディレクトリ($HFS/houdini/pythonX.Ylibs/)を指しています。

特定の機能の実装に関する詳細は、以下のページを参照してください:

3D Pythonハンドル

3D Pythonハンドルには、3D操作機能が備わっており、シーンビューア内で動作します。 3D Pythonハンドルは、SOP、LOP、OBJノードなどのコンテキストで定義することができます。

イニシャライザ

def __init__(self, **kwargs)

__init__メソッドは、Pythonハンドルクラスを初期化するのに必須です。 Houdiniは、事前定義されたキーエントリを含んだkwargs辞書を引き数として、このメソッドをコールします。

Note

kwargs辞書の内容をクラスのアトリビュートとして__init__に格納することができます。 これによって、コード内で辞書を繰り返し照会することなく、これらのエントリに直接アクセスできるようになります。

def __init__(self, **kwargs)
    self.__dict__.update(kwargs)
    ...

def onActivate(self, kwargs):
    self.log("Handle parameters", self.handle_parms)

handle_name

登録時に設定されるビューアハンドルのタイプ名。

handle_label

登録時に設定されるPythonハンドルのラベル。

handle_instance_name

Pythonハンドルをhou.ViewerStateTemplate.bindHandleまたはhou.ViewerStateTemplate.bindHandleStaticにバインドする時にPythonステートで指定するハンドルインスタンス名。

scene_viewer

Pythonハンドルが実行されているシーンビューアを表現したhou.SceneViewerのインスタンス。

handle_context

アクティブハンドルに関する様々なコンテキスト情報にアクセス可能なコンテキストオブジェクト。

handle_gadgets

hou.ViewerHandleTemplate.bindGadgetで定義されているgadgetオブジェクトの辞書。 ガジェットの名前を辞書キーとして使用することで、そのガジェットオブジェクトを照会することができます。

handle_parms

Pythonハンドルのパタメータ値と設定値を含んだ辞書。 この辞書には、hou.ViewerHandleTemplate.bindParametersとhou.ViewerHandleTemplate.bindSettingsで与えられた情報から収集されます。 パラメータ名または設定名を使用することで、その辞書の値を照会することができます。

2D Pythonハンドル

2D Pythonハンドルは、 Compositing Viewer および Scene Viewer 内で動作するように設計されています。

イニシャライザ

def __init__(self, **kwargs)

2D Pythonハンドルの場合、__init__メソッドは、ハンドルクラスを初期化するのに必須です。 Houdiniは、事前定義されたキーエントリを含んだkwargs辞書を引き数として、このメソッドをコールします。

Note

kwargs辞書エントリをハンドルクラスのアトリビュートとして格納しておくと便利な場合が多いです。 これによって、辞書を繰り返し参照しなくても、それらをself.attribute_nameとして直接アクセスできるようになります。

例:

def __init__(self, **kwargs):
    self.__dict__.update(kwargs)

def onActivate(self, kwargs):
    self.log("Handle parameters", self.handle_parms)

handle_name

登録時に設定されるビューアハンドルのタイプ名。

handle_label

登録時に設定されるPythonハンドルのラベル。

handle_instance_name

このハンドルインスタンスの固有な名前。 これは、Pythonステートでhou.ViewerStateTemplate.bindHandleまたはhou.ViewerStateTemplate.bindHandleStaticを使用してハンドルをバインドする時に指定します。 これは、このPythonハンドル実装を参照したhou.Handleインスタンスを初期化するのによく使用します。

scene_viewer

ハンドルが実行されているCompositing Viewerを表現したhou.CompositorViewerのインスタンス。

handle_context

アクティブなハンドルに関する様々なコンテキスト情報にアクセスできるhou.ViewerHandleContextオブジェクト。 これを使用することで、Drawableの描画順を定義したり、ハンドルパラメータを照会したり、ガジェットにアクセスすることができます。

handle_contextは、onDrawやonMouseEventなどのPythonハンドルコールバック内で利用可能であり、これによって、ハンドル実装はDrawableをレンダリングし、ユーザの操作に対して一貫した応答を行なうことができます。

handle_parms

Pythonハンドルのパラメータや設定の値を含んだ辞書。 これは、hou.ViewerHandleTemplate.bindParametersおよびhou.ViewerHandleTemplate.bindSettingsから設定します。 パラメータ名または設定名をキーとして使用して、その値にアクセスします。

イベントハンドラー

Pythonハンドルイベントに反応できるようにいくつかのハンドルがサポートされています。 これらのイベントハンドラーのほとんどは、そのイベント関連の特定の値を含んだ単一辞書引数(kwargs)を使ってコールされます。

すべてのハンドラーに共通するkwargsエントリを以下に載せています:

handle_context

アクティブハンドルに関する様々な情報にアクセス可能なコンテキストオブジェクト。 このキャッシュは、クラスアトリビュートとしても利用可能です。

handle_parms

Pythonハンドルにバインドされたパラメータと設定を表現した名前を含んだ書き込み可能な辞書。

ui_event

イベントに関する情報(例えばマウスイベントの場合、現行マウス座標やボタンがクリックされたかどうか)を持ったhou.ViewerEventインスタンスを含んでいます。 イベントがコンポジタービューで発生した場合、これは代わりにhou.CompositorViewerEventインスタンスとなります。

このテーブルには、すべてのイベントハンドラーと、該当する場合の特定のkwargsエントリを載せています。

メソッド名

説明

onMouseEvent

このコールバックは、3D Pythonハンドルのhou.GadgetDrawableまたは2D Pythonハンドルのhou.Drawable2Dがロケート(マウス下の検索)、ピック、ドラッグされた時にコールされます。詳細は、マウスのハンドリングを参照してください。

onMouseIndirectEvent

ビューポート内の任意の場所からでマウスがドラッグされた時にコールされます。 間接的なマウスの制御を参照してください。

indirectMouseIsSupported

ハンドルが間接的なマウス操作をサポートしているかどうかを示します。 サポートを有効にするにはTrueを、無効にするにはFalseを返さなければなりません。 このハンドラーが実装されていない場合、Houdiniは間接操作がサポートされていないものとみなします。

indirectMouseComputeDistance(x, y)

ハンドルとマウス位置との距離を計算します。 マウス位置を入力として受け取り、スクリーン空間での距離を浮動小数点数で返します。 Houdiniは、この値を使用して、ビューポート内のアクティブなハンドルのうち、どのハンドルが間接操作イベントを受け取るかを決定します。 最も近いハンドルが優先されます。 実装されていない場合、Houdiniはそのハンドルがマウスによる間接操作がサポートされていないものとみなします。

Note

HUDハンドルに関しては、このハンドラーを実装する必要はなくて、Houdiniが自動で距離を計算します。

onMouseWheelEvent

マウススクロールが発生した時にコールされます。 hou.UIEventDevice.mouseWheelは、スクロール方向に応じて-1または1を返します。 マウスホイールのハンドリングを参照してください。

onKeyEvent

キーが押された時にコールされます。 詳細は、キーボードデバイスの読み込みを参照してください。

onKeyTransitEvent

キートランジションイベントが発生した時にコールされます。 詳細は、キーボードデバイスの読み込みを参照してください。

onMenuAction

ユーザがコンテキストメニュー項目を選択した時にコールされます。 コンテキストメニューのハンドリングに関しては、Pythonステートのコンテキストメニューを参照してください。

menu_item: 選択されたメニュー項目名を含んでいます。

Note

このハンドラーは、kwargs内のui_eventエントリを取得しません。

onMenuPreOpen

コンテキストメニューが開かれる前にコールされます。 コンテキストメニューの更新を参照してください。

menu_states: ルートメニューまたはサブメニューの状態値。

menu_item_states: 開こうとするメニューのすべてのメニュー項目の状態値。

onParmChangeEvent

ハンドルのパラメータまたは設定が変更された時にコールされます。 ハンドルパラメータのハンドリングを参照してください。

parm_name: 変更されたパラメータ名または設定名。

parm_value: 新しいパラメータ値または設定値。複数コンポーネントのパラメータに関しては、parm_valueにはリストを設定します。

onDraw

HoudiniがPythonハンドルの再描画を必要とした時にコールされます。 詳細は、ハンドルの描画を参照してください。 このメソッドは以下の時にコールされます:

  • ユーザがマウス移動やマウスクリックなどのインタラクティブなイベントを引き起こした時。

  • Houdiniが現行ビューポートの再描画を強制された時。

onDrawSetup

onDrawの前にコールされます。 このメソッドは、典型的にはハンドルのガジェットを描画する前にそれをスケールするのに使用します。

Note

onDrawSetupは、3D Pythonハンドルでのみサポートされています。 2D Pythonハンドルの場合、Houdiniがハンドルのガジェットを自動で計算してスケールします。

onActivate

ハンドルがアクティブに設定された時にコールされます。これは以下の時に起こります:

  • ハンドルが作成された時。

  • ビューポートにフォーカスされた時。

  • カメラツールを使用した後。

onDeactivate

ハンドルが非アクティブに設定された時にコールされます。これは以下の時に起こります:

  • 異なるステートが選択された時、または、ユーザがHoudiniを終了した時。

  • ユーザがカメラツールまたはVolatileセレクターの使用を開始した時。

  • ビューポートからフォーカスが外れた時。

onLoadSettings

ハンドル設定がHoudiniに読み込まれて処理される準備が整った時にコールされます。 一つの設定が変更される度にコールされるonParmChangeEventとは対照的で、このメソッドは通常では、すべての設定を一括で処理するのに使用されます。 onLoadSettingsはOnActivateの後にコールされます。

Undo対応

Houdiniは、ハンドルやノードパラメータが変更された時に自動的にUndoスタック上にアイテムを生成します。 とはいえ、独自にUndo対応が必要な場合、hou.undosモジュールとhou.SceneViewerのUndoメソッドを使用することで、 Undo可能なオペレーションをUndoスタック上に1個のエントリにまとめることができます。 詳細は、ステートのUndo対応を参照してください。

Note

一部のhou.SceneViewerUndoメソッドは、hou.CompositorViewerでサポートされていません。

ユーティリティ

Houdiniには、Pythonハンドルの実装に役立つ様々なユーティリティクラスが用意されています。 例えば、ColorOptionsやhou.SceneViewer.hudInfoといったユーティリティは、Houdiniの標準と整合性が合うように設計されており、 これらのユーティリティティを使用することを強く推奨します。 これらのユーティリティの使い方のサンプルは、Pythonハンドルのデモを参照してください。

  • viewerhandle.utils.TransformAid:

    TransformAidは、Pythonハンドルのトランスフォーム操作を制御します。 updateTransformやtoScreenといったメソッドは、ビューポートがワールド空間に設定された時にハンドルのオブジェクトトランスフォームを補完します。

    Note

    TransformAidは主に3D Pythonハンドル向けに設計されており、そのメソッドの一部は2Dハンドルにも適用可能に見えるかもしれませんが、 2D Pythonハンドル内で2D固有の操作を扱うには、代わりにdrawable2d.Dragger2Dを使用することを推奨します。

  • viewerhandle.utils.DebugAid:

    Pythonハンドルのデバッグに役立つユーティリティクラス。

  • resourceutils.ColorOptions:

    Houdiniカラーオプションにアクセスできるユーティリティクラス。 詳細は、Gadget Drawablesを参照してください。

  • resourceutils.DisplayGroup:

    このクラスは、Drawablesをビューポート内にグループとして表示することができます。 例えば、HoudiniトランスフォームモードキーのYと同様に循環形式でハンドルガジェットのグループの表示を切り替えたい場合にこれが役立ちます。

  • drawable2d.Dragger2D:

    2D画像空間におけるhou.Drawable2Dオブジェクトのマウスによるインタラクティブな操作のためのユーティリティクラス。 これは、主にCOP PythonハンドルやCOP Pythonステートで使用され、[-1, -1]から[1, 1]の範囲の正規化されたモデル空間内でユーザ操作が行なわれます。

  • drawable2d.Drawable2DGroup:

    このクラスは、hou.Drawable2DオブジェクトのDrawableグループ化機能を扱います。

  • resourceutils.CursorLabel:

    このクラスを使用すると、カーソルの動きに追従するテキストラベルを表示することができます。 これは、2D Pythonハンドルと3D Pythonハンドルの両方でコンテキスト情報を用意するのに役立ちます。 詳細な使用方法は、move_tool_demoおよびcop_state_drawable_demoのハンドルサンプルを参照してください。

  • resourceutils.DebugMenu:

    Pythonハンドルコンテキストメニューにデバッグメニューエントリを作成する際にHoudiniで使用されます。 実際にViewer Handle Code Generatorは、これを使用してハンドルのコンテキストメニューを作成しています。

サンプル

Viewer Handle Code Generatorのサンプルだけでなく、サンプルシーンを使用してPythonハンドルを実験することができます。 以下のシーンは、viewer_handle_demoパッケージと一緒に$HFS/package/viewer_handle_demo/scenes下に配布されています。 以下のシーンを使用する前に、Viewer Handle Browserの File|Load Examples メニューをクリックしてそのパッケージをHoudiniに読み込んでください。

Demo Viewer Handle シェルフツールまたはメインメニューバー内の File|Open… メニューからサンプルシーンを読み込むことができます。

3D Pythonハンドル

viewer_handle_intro.hipシーンでは、Pythonハンドルの実装について紹介されており、そのシーンからPythonハンドルの基本機能を学ぶことができます。

move_tool_demo.hipシーンでは、ジオメトリを移動/回転/スケールさせるPythonハンドルのもっと完璧で複雑な実装のサンプルが用意されています。

2D Pythonハンドル

cop_viewer_handle_demo.hipシーンでは、COP専用のPythonハンドルの作成方法について説明しています。 このサンプルを詳しく見ていくことで、COP用Pythonハンドルの基本的な機能や実装手法を学ぶことができます。

Pythonハンドルの使い方

Pythonハンドルとビルトインハンドルの制御で使用するワークフローの違いはほとんどありません。 例えば、ビルトインハンドルだろうとPythonハンドルだろうとどちらを使用しても以下のUI機能をユーザは使用できるはずです:

  • Pythonハンドルを表示するボタン。

  • パラメータと設定にアクセスすることができるHandle Parameterダイアログ。

  • Pythonハンドルを持続型として有効化することができるPersistent Handle Editor(COP Pythonハンドルとは互換性がありません)。

  • Draggersのスナップオプションを設定するダイアログ(COP Pythonハンドルとは互換性がありません)。。

  • Pythonハンドルのスケールを調整するカメラズーム。

  • キーフレームによるPythonハンドルパラメータのアニメーション。

Note

ただし、Handle Preferenceダイアログは、Houdiniビルトインハンドルの設定を制御するように設計されているので、Pythonハンドル向けに意図されていません。 これらの設定の一部は、良いタイミングで将来Pythonハンドル向けに露出される予定です。

ビューアハンドルを検査する方法

Houdiniは、登録済みのすべてのPythonハンドルをViewer Handle Browserウィンドウで表示することができます。 このブラウザはViewer State Browserと同様で、ほぼ同じ機能が用意されています:

  • 登録済みのハンドルをブラウズするツリー。

  • メッセージをログに出すコンソール。

  • アクティブハンドルのクラスアトリビュートをダンプする様々なオペレーション。

  • Viewer Handle Code Generator。

  • Pythonハンドルの編集と読み込みに対応。

デバッグに関するTips

Pythonハンドルで利用可能なデバッグ機能は、Pythonステートのデバッグ機能とほぼ同じです。 これらの機能について学習したいのであれば、Pythonステートのデバッグに関するTipsの章を参照してください。

DebugAid

ユーティリティクラスのviewerhandle.utils.DebugAidには、Pythonハンドルのデバッグサポートが用意されています。 このユーティリティは、Pythonハンドルブラウザでメッセージをログに出すのに便利ですが、さらにPythonハンドルブラウザで現在利用可能なすべてのログ機能をメソッドとして用意しています:

  • アクティブなPythonハンドルを検査します。

  • コンソールにマーカーを追加します。

  • デバッグトレースを有効化します。

  • ロギングコンソールを有効化します。

  • 実行中のPythonハンドルをリロードします。

import traceback
from viewerhandle.utils import DebugAid

class Handle(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)
        self.dbg = DebugAid(self)

    def onEnter(self, kwargs):
        # ハンドルを検査します。
        self.dbg.marker()
        self.dbg.inspect()

        # トレースを開始します。
        self.dbg.trace()

    def onMouseEvent(self, kwargs):
        # マウス位置をログに出します。
        ui_event = kwargs["ui_event"]
        device = ui_event.device()

        self.dbg.marker()
        self.dbg.log("Mouse position x=", device.mouseX(), "y=", device.mouseY())

        # 現在のPythonコールスタックをログに出します。
        self.dbg.log(''.join(traceback.format_stack()))

ハンドルをリロードする方法

HoudiniからPythonハンドルモジュールをリロードできれば、Pythonハンドルの開発サイクルが向上します。 Pythonハンドルをリロードする方法がいくつか用意されています:

  • ソースコードがHoudiniのViewer Handle Editorで開かれていれば、Acceptボタンをクリックします。

  • Viewer Handle BrowserペインのFileメニューまたはブラウザツリー内からReloadコンテキストメニューを選択します。

  • hou.ui.reloadViewerHandle

  • viewerhandle.utils.DebugAid.reload

  • ハンドルがHDAに埋め込まれている場合は、Python Handleエディタからリロードします。

Note

Pythonハンドルをリロードすると、そのハンドルのインスタンスが使用中であれば、実行中のPythonステートが自動的に抜けます。

デバッグコンテキストメニュー

Pythonハンドルにデバッグ機能を追加する別の方法は、デバッグコンテキストメニューを使用することです。 Viewer Handle Code Generatorには、以下のViewer Handle Browserデバッグ機能にアクセス可能なデバッグメニューを生成するオプションが備わっています:

  • Logging

    コンソールのロギングを有効または無効にします。 有効にすると、self.logまたはDebugAidユーティリティによってログに出されたメッセージがコンソールに送信されます。

  • Clear

    ロギングコンソールをクリアします。

  • Inspect

    大元のPythonハンドルの内容をコンソールにダンプします。

  • Trace

    デバッグトレースを有効または無効にします。有効にすると、アクティブなPythonハンドルのトレースのログがコンソールに出されます。

  • Marker

    メッセージを区別できるようにマーカーをコンソールに追加します。

生成されるコードには、サブメニューとしてデバッグメニューが追加されます。 このデバッグメニューを平坦なメニューとして追加したいのであれば、以下のようにcreateViewerHandleTemplate内のコードを修正します:

menu = hou.ViewerStateMenu(handle_type + "_menu", handle_label)
...

# これを ...
menu.addMenu(hu.createDebugMenu(handle_type))

# ... このコードに置換します。
hu.addDebugEntriesToMenu(handle_type, menu)

...

HOM API

Pythonビューアハンドル

Pythonスクリプト

はじめよう

次のステップ

リファレンス

  • hou

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

導師レベル

Python Viewerステート

Pythonビューアハンドル

プラグインタイプ