Edited at

【Houdini】vexのinclude文の挙動

Houdini の Wrangle ノードに記述する vex コードには include 文で外部ファイルに記述してあるコードを読み込ませることができます。あまりサンプルを見ませんし、自分個人としては include を多用する事にはやや否定的なのですが、実際便利なこともありますし、そもそもまとまっている情報を見かけないので、ざっと挙動を調べてみました。環境は、Windows10 PRO + Houdini7.5 Indieです。


書式

とりあえず、my_snippet.vfl という外部ファイルを用意します。配置場所は後述します。内容は適当に文字列をprintする関数のコードとしました。

void test(string s)

{
printf("Hello %s!\n", s);
}

このファイルを wrangle SOP で読み込むには、(ノード内のコードとして)下記のような記述をします。

#include "my_snippet.vfl"

外部ファイル名の拡張子としては .vfl もしくは .h がよく使われるようです。が、.txt としても動作したのでなんでも良いようです。この投稿では、ファイル各位調子を .vfl で統一します。(.hのほうが意味的に適切かもしれませんが、VSCodeなどへの紐づけが楽なのでそうしています。)

#include <my_snippet.vfl>

このような書き方でも動作します。この投稿では前者の書き方で統一します。


外部ファイルの保存場所

$HOUDINI_VEX_PATH$HOME/vex/include におくと良いという情報があったのですが、それっぽい場所にファイルを置いてみたり、Houdini.env やマシンの環境変数にフォルダパスを設定してみてもうまく include できませんでした。(パスの解決順序などをきちんと理解しなければいけなそうです。。)

現在 include 動作が確認できているのは、


  • includeを絶対パスで書く

  • hipファイルの横に 'vex/include' フォルダを作りそこに外部ファイルを置く

の2パターンです。

絶対パスでは

#include "C:\MyHoudini\vex\my_snippet_abs.vfl"

または

#include "C:/MyHoudini/vex/my_snippet_abs.vfl"

のように書きます。Mac上での動作などまだ確認していませんが、後者のようにスラッシュをパスの区切り文字に使った方が汎用性が高そうです。とはいえ、実際には絶対パスを使うことは少ないかと思います。

hipファイル横に vex/include フォルダを掘った場合は

#include "my_snippet.vfl"

のように簡潔に書けます。これがよさそうです。

#include "hoge/my_snippet.vfl"

のように、さらにサブフォルダを掘って外部ファイルを保存することもできました。


有効スコープと複雑な include


  • あるノードで読み込んだ外部ファイル定義は後続の別ノードでは無効でした。まあ当然な感じです。必要であれば別ノードで再度 include します。

  • 外部ファイルから別外部ファイルを読み込むことが可能です。vfl ファイル内に include文を記述します。

  • 別外部ファイルのパス解決は、ファイルの真横もしくは元々の基準パス(今回の例では $HIP/vex/include)を基準として解決されるようです。

  • この時、両者で同じ関数を設定していると多重定義エラーになります。

  • 複雑なファイルの依存関係をつくると1つのファイルを何度も読み込んでしまい、多重定義を作ってしまいえます。これをさけるには、C言語でおなじみの ifdef 命令を使います。以下は先ほどの関数に対応を入れた例です。

#ifndef __test_func__

#define __test_func__

void test(string s)
{
printf("Hello %s!\n", s);
}

#endif


外部ファイルに記述できる内容


  • 関数定義

  • マクロ定義

  • 構造体定義

などです。マクロ定義は下記のように設定でき

#define HOGE "HOGE"

#define MOGE 1
#define println(message) printf("%s\n", message)

読み込んだ wrangle側で利用できます。

#include "my_snippet.vfl"

setprimgroup(0, HOGE, @primnum, 1);
i@hoge = MOGE;
println("hogehoge");

この辺りは、C言語での記述をそのまま参考とすればよいようです。アトリビュートを変更するスニペットのようなコードをいきなり書くとエラーになります。関数もしくはマクロで処理させます。


外部ファイル更新時の注意点

外部ファイルを更新しても、それを察知してHoudini側で変更が走ったりはしません。空白や改行を加えるなど、wrangle のvexコードになにか変更を加えて保存してやると外部ファイルも読み込みなおされます。(pythonなどで機能拡張してやるとこの辺りのわずらわしさが解決できるかもしれません。なにやら高機能なwrangleノードを自作してらっしゃる方を海外のどこかのサイトで見かけましたが、URLを失念しました。)


参考

Houdini のインストールフォルダの中にたくさんの include用 .hファイルが存在します。自分の環境では C:\Program Files\Side Effects Software\Houdini 17.5.293\houdini\vex\include にありました。あとは公式のヘルプではこのページが参考になります。 http://www.sidefx.com/ja/docs/houdini/vex/lang.html

日本語情報はあまりみませんが、海外のフォーラムを覗いているといろいろ書いてあります。


考察

自分が明るくない方面なのでまとめましたが、特に後半はC系の言語やシェーダーに詳しい方から見るとあたりまえの内容かとは思います。(ちなみに vexは実際にシェーダー言語だという事です。)そういう事で自分メモ用ではありますが、この記事が誰かの役に立てば幸いです。