Using Python in Houdini

ここでは、実際に Python を Houdini で使う場合の初歩的な事柄について説明。

  1. なぜ Python を使うのか? いつ使うのか?
  2. Houdini の Python
  3. Python Shell
  4. オブジェクト名・パスの取得
  5. 子ノード情報の取得
  6. パラメータの取得・値の設定
  7. ヘルプ
  8. 関数の定義

1. なぜ Python を使うのか? いつ使うのか?

  1. 機能補完
    Houdini の機能が Python で書かれている。バージョンが上がるたびに増える傾向にある。
    • シェルフツール
    • HQueue
    • それ以外にも、モーションエフェクト, Houdini Help Server, Amazon クラウドレンダリング, カラーピッカ, Orbolt からのダウンロード機能など多数
  2. 機能を置き換えるためではない
    • VEX/VOP などでできることはそちらを使う(その方が速い)
  3. 機能拡張
    • Python ライブラリで提供される機能を使うため
    • 新しい SOP/COP/DOP/Object を C++ なしで (テスト) 実装するとき
  4. 自動化
    • アセットやシェルフにボタンを配置し、クリックしたときの自動化
    • 画像やジオメトリをスタンドアロンスクリプトから生成するとき

2. Houdini の Python

  1. Python 2.7 (と 2.6) が含まれている
    • インストール時に $HFS (Houdini インストール先) にインストールされる
      • Houdini 14.0.249/python27 (および python26)
      • 別途インストールは不要
  2. Python が使えるところ
    1. Python Shell
    2. Python Source Editor
    3. Python Panel Editor
    4. シェルフツール
    5. パラメータフィールド
    6. デジタルアセット
    7. Hython

3. Python Shell

Python コマンドを Houdini内でインタラクティブに実行するには、まず Python Shellを使う。このシェルは、次のいずれかの方法で起動可能。

  1. Desktop を Build (デフォルト)から Technical へ。メイン UI 下部に表示される。
  2. menu から実行 (Windows -> Python Shell またはAlt+Shift+P) 別ウィンドウで起動する。
  3. パネルの一つとして、パネル脇の "+" ボタンをクリック、New Pane Type->Python Shell とする。

4. オブジェクト名・パスの取得

以下 Build デスクトップを使用していると仮定。

  1. 例えば Node Editor で、Geometry ノードを作成 (TABキーを押して、'g', 'e', 'o' と入力 + Enter)。
  2. 出来たノード(geo1)を選択し、Python シェルにドラッグ&ドロップ。

    すると、
    >>> hou.node('/obj/box_object1') 
    と、このノードの定義同等のPython コマンドとして入力される。
  3. Enterを押して実行すれば、
    <hou.ObjNode of type geo at /obj/box_object1>
    と表示される。
  4. こうして出来るコマンドを変数に格納することも可能。
    >>> n = hou.node('/obj/box_object1') 
    とすると、変数 n に Python オブジェクトとして格納される。そうした上で、
    >>> n.name() 
    とすると、
    'geo1'
    とノード名を取得することが可能。コマンドを記述する際には、自動補間を使ってコマンドを入力可能。
  5. ノードまでのパスを取得するには、
    >>> n.path() 
    とすれば、
    '/obj/geo1'
    とノードまでの絶対パスが返る。

5. 子ノード情報の取得

  1. geo1 の中に入り、
    1. file1 ノードを削除
    2. Box, Sphere, Merge を作成
    3. box と sphere1 を merge1 に接続
    下記のような状態にする。

    変数 n は先ほどのままの hou.node('/obj/box_object1')
  2. 子ノード情報を取得するには、
    n.children()
    とすると
    (<hou.SopNode of type sphere at /obj/geo1/sphere1>, <hou.SopNode of type box at /obj/geo1/box1>, <hou.SopNode of type merge at /obj/geo1/merge1>)
    と3つの名前が tuple (タプル)として返り値になる。
  3. 上記の返り値を変数で受けることも可能。例えば変数 t で受けるには、
    >>> t = n.children() 
    このあと、配列として処理することが可能。
    >>> t[0]
    <hou.SopNode of type box at /obj/geo1/box1>
    >>> t[1]
    <hou.SopNode of type sphere at /obj/geo1/sphere1>
    >>> t[2]
    <hou.SopNode of type merge at /obj/geo1/merge1>
    
  4. ループに通すことも可能
    >>> for c in n.children():
    ...     print c.name()
    ... 
    box1
    sphere1
    merge1

6. パラメータの取得・値の設定

ジオメトリレベルからオブジェクトレベルに上がる。

  1. geo1のtxの値を取得する場合、
    >>> n.parm("tx")
    <hou.Parm tx in /obj/geo1>
    で、パラメータの存在を確認可能。
    >>> n.parm("tx").eval()
    とすれば、
    0.0
    と返ってくる。
  2. 先ほど同様、変数に取ることも可能。
    >>> p = n.parm("tx")
    としたあと、
    >>> p.eval()
    とすれば、同じように
    0.0
    となる。
  3. 値を設定するには、
    >>> n.parm("tx").set(1.0)
    とすれば、tx の値は 1.0 となる。また、
    >>> p.set(0.0)
    とすれば原点に戻る。
このようにHoudini内のオブジェクトは、Pythonオブジェクトとして非常にダイレクトに扱うことが可能。また、殆どの場合において、Auto Completionが使える (Ctrl+tab)。

7. ヘルプ

dir

    dir(引数) とすれば対応するメソッドが表示される。例えば、
    >>> dir(hou.Geometry)
    >>> dir(hou.node('/obj/geo1'))
    >>> dir(n)
    >>> dir(p)

    など。
help
    また、
    >>> dir(hou.Geometry)
    >>> help(n.parm)

    とすれば、下記の様にヘルプが表示される。
    Help on method parm in module hou:
    
    parm(*args) method of hou.ObjNode instance
        parm(self, parm_path) -> hou.Parm or None
        
        Return the parameter at the given path, or None if the parameter 
    doesn't exist. REPLACES chexist function
ドキュメント
    Help->Houdini Helpからヘルプを参照することも可能。"Python Scripting with the Houdini Object Model"に行き、Reference 以下のhouに行くと、ノードのメソッドを知ることが可能。

8. 関数の定義

>>> def childrenOfNode(node):
...     result = []
...     for c in node.children():
...         result.append(c)
...         result += childrenOfNode(c)
...     return result
... 
これを実行すれば以下のようになる。
>>> childrenOfNode(n)
[<hou.SopNode of type box at /obj/geo1/box1>, <hou.SopNode of type sphere at /obj/geo1/sphere1>, <hou.SopNode of type merge at /obj/geo1/merge1>]

8.1 関数の格納場所

  1. Python Source Editor
    Windows->Python Source Editor で起動。ここに
    def childrenOfNode(node):
        result = []
        for c in node.children():
            result.append(c)
            result += childrenOfNode(c)
        return result
    と記述し、Accept を押せば、この関数はシーンファイル (.hip) に保存される。
    この関数を呼ぶには以下のように行う。
    >>> hou.session.childrenOfNode(n)
    [<hou.SopNode of type box at /obj/geo1/box1>, <hou.SopNode of type sphere at /obj/geo1/sphere1>, <hou.SopNode of type merge at /obj/geo1/merge1>]
  2. シェルフへの登録
    • シェルフの空いたスペースで、RMB(右マウスボタン)->New Tool...を実行。
    • 名前とラベルを変更。例えばhello, Helloなど。
    • Scriptタブに行き、フィールドにスクリプトを入力。
      print "hello"
      など。Accept としたあと、シェルフに出来た Hello ボタンを押せば、Python Shellに hello が表示される。
  3. .py ファイル

8.2 Python によるエクスプレッション

    例えば、Translate Xに $F/10 (フレーム番号/10)というエクスプレッションをPythonで定義する場合、
    hou.frame()/10
    とし、RMB->Expression->Change to Python Expressionとする。 もしくは、Parameterウィンドウの"H" (HScript)というアイコンをPythonに変更する。 "hou."は無くとも良い。

    同様にRotate Xに
    frame()*5
    とすることも可能。

    HとPythonアイコンの部分が、ノードのデフォルトエクスプレッション言語を決定している。 デフォルト言語でエクスプレッションを書いた場合には、緑で表示され、デフォルトで無い言語で書いた場合には赤く表示される。

    その他、$PTなど、ローカル変数を使う場合には、
    lvar("PT")
    lvar("TX")
    などと定義可能。
    lvar("TX")
    は、
    pwd().curPoint().position
    と定義可能。

    複数行のExpressionを書く場合は、Alt+Eでエディタを表示可能。
    この場合、次のようなエクスプレッションを複数行で書くことも可能。
    point = pwd().curPoint()
    if point.number() == 0:
        return 2.0
    return point.position()


    各パラメータのエクスプレッション全部選択し、をPython Shellにドラッグ&ドロップすれば、そのパラメータまでのPythonによるパスが表示される。同様にパラメータのラベルをドラッグ&ドロップすることも可能。 前者の場合、
    >>> hou.parm('/obj/geo1/point1/tx')
    <hou.Parm tx in /obj/geo1/point1>
    となり、後者の場合、
    >>> hou.parmTuple('/obj/geo1/point1/t')
    <hou.ParmTuple t in /obj/geo1/point1>
    となる。
    今までのノードを削除し、Fontノードを作成。Text Fieldに一度キーフレームを設定(ラベルをAlt+LMBクリック)してから、Expression TypeをPythonにして、
    "Frame: %s" % int(frame())
    と入力。

0 件のコメント:

コメントを投稿