3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HDAのPython ModuleにEnumでパラメーターを作成して色々なところで使い回す

3
Last updated at Posted at 2025-12-07

251207.png

はじめに

HoudiniでHDAを作っていると、

・ノードにたくさんパラメータを追加したり

・学習中のViewer Stateでもパラメータを読んだり書き換えたり

といったことがよくあります。

こういうときに Python の Enum(列挙型) を使ってパラメータを管理しておくと、

  • パラメータ名のタイプミスを防げる
  • Viewer State 側と Python Module 側で、同じ名前を安全に共有できる
  • パラメータを自動生成したり、まとめて扱ったりしやすくなる

といったメリットがあります。

この記事では、次の流れで説明します。

  1. Python Enum の基本的な使い方
  2. Enum を使って HDA のパラメータを自動生成する方法
  3. Enum を Viewer State から参照して、SimpleDrawable の見た目を制御する方法

1. Enumの基本

Python には Enum(列挙型) という仕組みがあります。

「決まった選択肢に名前をつけて管理するためのクラス」と考えるれば分かりやすいです。

この Enum は、Houdini の HDA でもそのまま使えます。

from enum import Enum

class DisplayMode(Enum):
    CURRENT = ('current_viewport', 'Current Viewport Mode')
    WIREFRAME = ('wireframe', 'Wireframe Mode')

# 値の取り出し
print(DisplayMode.CURRENT.name)   # → 'CURRENT'
print(DisplayMode.CURRENT.value)  # → ('current_viewport', 'Current Viewport Mode')

このように定義しておくと、

  • DisplayMode.CURRENT.value[0]

    → Houdini の「パラメータ名(token)」として使える文字列

  • DisplayMode.CURRENT.value[1]

    → UI に表示する「ラベル文字列」として使える

という形で、1つの Enum から「内部用の名前」と「表示用の名前」をまとめて取り出すことができます。

Python Source Editor でこのコードを貼って試すと、動作を確認しやすいです。

スクリーンショット 2025-12-07 040042.png


2. Enumを使ってHDAのパラメータを自動生成する

まず、インプットが 2 つある簡単な HDA を Null から作ったとします

スクリーンショット 2025-12-07 045552.png

この HDA の Python Module に Enum を定義し、

create_parameters() という関数でパラメータを自動的に追加してみます。
(最後にget_enum_info(enum_class)としてVeiwer Stateへパラメータ名を渡す関数を追加しています。クラス名を取得する必要はなかったですがマジックメソッドにも慣れるために書いています。)

import hou
from enum import Enum

# ============================================================
# Enum定義
# ============================================================

class ToggleParms(Enum):
    """トグルパラメータの定義"""
    ENABLE_MATERIALS = ('enable_materials', 'Enable Materials')
    OUTLINE = ('outline', 'Outline')
    OUTLINE_ONLY = ('outline_only', 'Outline Only')

class Color(Enum):
    """カラー関連のパラメータ定義"""
    OUTLINE = ('outline_color', 'Outline Color')

# ============================================================
# パラメータ作成関数
# ============================================================
def create_parameters(node: hou.SopNode):
    """Enum定義に基づき、HDAノードにパラメータを自動生成"""
    ptg = hou.ParmTemplateGroup()

    # --- トグルパラメータ作成 ---
    for enum in ToggleParms:
        name, label = enum.value
        parm = hou.ToggleParmTemplate(name, label)
        ptg.addParmTemplate(parm)

    # --- カラーパラメータ作成 ---
    for enum in Color:
        name, label = enum.value
        color = hou.FloatParmTemplate(name, label, 3)
        color.setLook(hou.parmLook.ColorSquare)
        color.setNamingScheme(hou.parmNamingScheme.RGBA)
        color.setDefaultValue((0.5, 0.25, 0.25))
        ptg.addParmTemplate(color)

    # --- ノードに反映 ---
    node.setParmTemplateGroup(ptg)

# ============================================================
# Enum情報取得関数(ViewerStateで使用)
# ============================================================
def get_enum_info(enum_class):
    """Enumクラスからクラス名と値リストを辞書形式で返す"""
    return {
        "name": enum_class.__name__,
        "values": [v[0] for v in [member.value for member in enum_class]]
    }

スクリーンショット 2025-12-07 045929.png

これをHDAのPythonModuleに記述して、OnCreated

kwargs['node'].hdaModule().create_parameters(kwargs['node'])

と書いておくと、HDA ノードを作成したタイミングで、自動的にパラメータが生成されます。

スクリーンショット 2025-12-07 050127.png

ポイントは、

  • どのパラメータを作るかは Enum 側に集約されている
  • 実際にパラメータを作る処理は for 文で Enum をループするだけ

という形になっていて、後からパラメータを追加するときも Enum に 1 行足すだけで済む点です。


3. EnumをViewerStateで活用する

次に、Viewer State 側から Enum を使う例です。

このViewer Stateの処理は、Houdiniに内蔵されているDemo Stateの Simple drawable を
ベースに、学習のためにHDA moduleのEnumから値を取得する形に改変したものです。
Viewer Stateに興味を持つ方がいれば比較してみてください。
image.png

ここでは、SimpleDrawable を使って、ノードのパラメータ状態をビューポートに反映します。

ViewerStateModule 側で Enum を使う

import hou
import logging

# ------------------------------------------------------------
# ロガー設定
# ------------------------------------------------------------
logger = logging.getLogger("CurrentViewportState")
logger.setLevel(logging.INFO)

class State(object):
    def __init__(self, state_name, scene_viewer):
        """ViewerState初期化"""
        self.state_name = state_name
        self.scene_viewer = scene_viewer
        self.drawable = None

    def onEnter(self, kwargs):
        """ViewerState起動時:Drawable初期化とパラメータ反映"""
        self.node = kwargs["node"]

        # 入力ジオメトリ (input[1]) を取得
        geo = self.node.inputGeometry(1)
        if geo is None:
            logger.warning("Input[1] にジオメトリが接続されていません。")
            return

        # SimpleDrawable を作成
        self.drawable = hou.SimpleDrawable(self.scene_viewer, geo, "simple_drawable")
        self.updateDrawableFromParms()

    def updateDrawableFromParms(self):
        """ノードパラメータ値を読み取り、Drawableへ反映"""
        if self.drawable is None:
            return

        mod = self.node.hdaModule()

        # --- Toggle設定を反映 ---
        for token in mod.get_enum_info(mod.ToggleParms)["values"]:
            val = self.node.evalParm(token)
            if token == "enable_materials":
                self.drawable.setShowMaterials(val)
            elif token == "outline":
                self.drawable.setDrawOutline(val)
            elif token == "outline_only":
                self.drawable.setOutlineOnly(val)

        # --- Outline Color設定を反映 ---
        for token in mod.get_enum_info(mod.Color)["values"]:
            rgb = self.node.parmTuple(token).evalAsFloats()
            color = hou.Color(rgb)
            if token == "outline_color":
                self.drawable.setOutlineColor(color)

        # --- 表示モード ---
        # 今回は「Current Viewport Mode」をベースとして表示
        self.drawable.setDisplayMode(hou.drawableDisplayMode.CurrentViewportMode)
        self.drawable.enable(True)
        self.drawable.show(True)

    def onNodeChangeEvent(self, kwargs):
        """ノードのパラメータ変更時に再描画"""
        if kwargs["parm_tuple"] is None:
            return
        self.updateDrawableFromParms()

def createViewerStateTemplate():
    """
    ViewerState登録関数。
    Houdiniがこの関数を呼び出してViewerStateを登録する。
    """
    state_typename = kwargs["type"].definition().sections()["DefaultState"].contents()
    state_label = "Current Viewport State"
    state_cat = hou.sopNodeTypeCategory()

    template = hou.ViewerStateTemplate(state_typename, state_label, state_cat)
    template.bindFactory(State)
    template.bindIcon(kwargs["type"].icon())

    # ノードのパラメータ変更イベントを監視
    template.bindNodeChangeEvent([hou.nodeEventType.ParmTupleChanged])

    return template

ここでのポイントは、

  • mod = self.node.hdaModule() で Python Module にアクセス
  • mod.get_enum_info(mod.ToggleParms)["values"]
    Enum に定義した パラメータ名(token)のリストを取得
  • Viewer State 側では、生の文字列を書くのではなく Enum 情報を読むだけ

という形になっている点です。

これにより、

  • HDA の Python Module 側でパラメータ名を定義
  • Viewer State 側は「Enum 情報を読むだけ」で常に最新の状態に追従

という構造になります。
パラメータ名を文字列でコピペする必要がないので、名前ズレによるバグを減らせます。

3つのトグルパラメータにチェックを入れ、input[1] にジオメトリをつなぐと、
SimpleDrawable がアウトライン付きで表示されるはずです。

スクリーンショット 2025-12-07 050323.png


4. まとめ

項目 従来 Enum利用後
パラメータ名の管理 文字列ハードコード Enum定義に集約
パラメータ生成 手動追加 Enumループで自動生成
ViewerStateとの整合性 名前ズレでバグが出やすい Enumで常に同期可能
拡張性 新規追加時に複数修正が必要 Enumに1行追加するだけ

この方法を使うと、HDA・ViewerState・PythonModuleの管理が一貫します。

開発チームでも安全かつ再利用性の高いHDA構築が可能になります。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?