Houdiniプラグイン開発備忘録4 ~ カスタムSOPにカスタムパラメータを追加する編

今回は、カスタムノードにカスタムパラメータを追加してみます


VerbとProtoヘッダファイル

 最近のHDKでは、SOPノード作成にVerbという仕組みを使うことが多いようです。
 Verbというのは、かなりざっくりいうと、SOPの振る舞いを定義する際、ジオメトリへの処理と、それ以外のパラメータ操作などの処理を分離する仕組みです。

[参考]プログラム的にVerb(動詞)を使ったジオメトリ

 Verbを利用してSOPを作成する際、これまで何度か言及していた、「Protoヘッダファイル」をビルド手順の中で生成し利用することになります。


Protoヘッダファイルの主な役割

 Protoヘッダファイルには、ジオメトリ処理以外の実装が自動的に記述されます。

※これは現時点での理解なので間違っているかもしれませんが、この仕組みにより、開発者は面倒なパラメータとジオメトリ処理をつなぐ実装を省略し、主にジオメトリ操作に関する処理に注力すれば良くなります。

 主なProtoヘッダファイルの役割は以下のようなものになります。

  1. PRM_Templateを生成する
  2. パラメータの操作を簡単化する関数群を自動生成する

Protoヘッダファイルの作り方

 Protoヘッダファイルは何もしなくても勝手に作成されるわけではなく、ソースコードの中にそのノードがどのようなパラメータを持っているかを示す「Dialog Script」を記述、または「*.ds形式のファイル」として用意して、PRM_TemplateBuilderに与える必要があります。

 このDialog Scriptは、ソースコード中で *theDsFile に記述します。

static const char *theDsFile = R"THEDSFILE(
・・・
)THEDSFILE";
//SOP_Starの例

static const char *theDsFile = R"THEDSFILE(
{
    name        parameters
    parm {
        name    "divs"      // Internal parameter name
        label   "Divisions" // Descriptive parameter name for user interface
        type    integer
        default { "5" }     // Default for this parameter on new nodes
        range   { 2! 50 }   // The value is prevented from going below 2 at all.
                            // The UI slider goes up to 50, but the value can go higher.
        export  all         // This makes the parameter show up in the toolbox
                            // above the viewport when it's in the node's state.
    }
    parm {
        name    "rad"
        label   "Radius"
        type    vector2
        size    2           // 2 components in a vector2
        default { "1" "0.3" } // Outside and inside radius defaults
    }
    parm {
        name    "nradius"
        label   "Allow Negative Radius"
        type    toggle
        default { "0" }
    }
    parm {
        name    "t"
        label   "Center"
        type    vector
        size    3           // 3 components in a vector
        default { "0" "0" "0" }
    }
    parm {
        name    "orient"
        label   "Orientation"
        type    ordinal
        default { "0" }     // Default to first entry in menu, "xy"
        menu    {
            "xy"    "XY Plane"
            "yz"    "YZ Plane"
            "zx"    "ZX Plane"
        }
    }
}
)THEDSFILE";

Dialog Scriptを生成する

 頑張って調べてみましたが、この記事を執筆している時点では、Dialog Scriptに関するリファレンスマニュアルのようなものを見つけることは出来ませんでした。
 そのかわり、リファレンスに頼ってフルスクラッチで書かなくとも、簡単にDialog Scriptを生成する方法があったので紹介します。

 やり方は、概ね以下の手順になります。

  1. パラメータ定義を抽出するためHDAを作成
  2. HDAに、カスタムノードに持たせたいパラメータを作成
  3. HDAのhou.ParmTemplateGroup.asDialogScript()でDialog Scriptのコードを取得
# Dialog Scriptを出力するサンプル
hda_node = hou.node("/to/hda/node/path")
hda_type = hda_node.type()
hda_definition = hda_type.definition()
hda_parm_template_group = hda_definition.parmTemplateGroup()
hda_dialog_script = hda_parm_template_group.asDialogScript()
print(hda_dialog_script)

 これにより、そのHDAに定義されたパラメータ定義が、Dialog Scriptの形式で取得できます。

 その後、ソースコードの*theDsFileに、取得したコードをそのままコピペするなどして与えた後、いつも通りの手順でビルドするだけです。


テスト

 以下は、HDAとして標準で用意されているColor SOPからDialog Scriptを頂いて、カスタムSOPにそのまま持たせてみたものです。


以上、カスタムSOPにカスタムパラメータを追加する方法でした。
なにか間違いや、不明な点などあれば、コメントいただけると嬉しいです。

AppleデバイスのLiDARスキャナとHoudini

 最近のiPad ProやiPhone 12 Pro / Maxに搭載されているLiDARスキャナで取得した点群をHoudiniに取り込んでみるテストをしたのでメモ。

使用機材

iPad Pro 2020
Houdini 18.5.351
pronoPointsScan

PCにファイルを転送する

  • pronoPointsScanで点群をスキャンし、ファイルとして保存します
  • iOSのファイルアプリで、「このiPad内 → pronoPointScan」を開きます
  • 先程保存した目的のファイルを「コピー」
  • PCから参照しやすい場所に「ペースト」
    • 今回は、OneDrive経由でPCにファイルを転送しました

Houdiniでファイルを開く

Table Import SOPを作り、先程PCに転送したtxtファイルを開きます。

pronoPointsScanから出力されるデータは非常にシンプルで、以下のようなフォーマットになっています。

各行が一つ一つのポイント情報に相当し、各行にはそれぞれ以下のように数字が羅列されています。

@P.x,@P.y,@P.z,@Cd.r,@Cd.g,@Cd.b


@Cdを修正

pronoPointsScanで生成した点群データのカラー値は0-255なので、Wrangleを書いて0-1に修正します。

v@Cd = fit(v@Cd, {0,0,0}, {255,255,255}, {0,0,0}, {1,1,1});

方向を修正

Bound SOPで点群のOBBと、OBBをまっすぐに戻すためのxformアトリビュートを作成


点群ジオメトリにxformアトリビュートをコピー

Attribute Copy SOPで、点群ジオメトリにOBBのxformアトリビュートをコピーする


点群の軸を修正する

Match Size SOPで、Bound SOPで生成されたxformアトリビュートを使い、点群の軸を修正する

今回は点群の撮影場所が室内だったこともあり、たまたまいい方向に向いてくれましたが、点群の形状によっては全く見当違いな方向に向く可能性があるので、その場合は適宜、いい感じに工夫する必要があります。


問題点

  • Table Import SOPが非常に遅い
    • Pythonでやるなら先にtxtを解釈し、行数分のポイントを作成した後、アトリビュート配列を組み立ててから、hou.Geometry.setPointFloatAttribValues(name, values)を使って、一括でセットするなどしてタイムロスを最小限に抑える必要がありそう。
  • ポイントにはそもそも法線情報がないので、Poinit Cloud Iso SOPなどで面を貼るためには下準備が必要

以上、手軽にLiDARスキャナで遊べる小ネタでした。