怖くないVEX


この記事は Houdini Advent Calendar 2018 の14日目の記事です。
Houdiniの中で特に初見殺しのVEXについてまとめた導入記事をあまり見かけないので、
知識を増やして触る人を増やすために本記事をかきました。スマブラが楽しくて少し内容が薄いです。

はじめに

ここに集う「Houdiniチョットデキる」方々は、VEXをさも当然の如く使っていますが、ノードを組むぐらいで精一杯な我々にとってよくわからない言語を使うのは敷居が高いです。
Houdini がCG初心者におすすめできない理由は、CG特有の専門用語の多さと出来れば触りたくない苦手意識のある数学に加え、VEXに代表される暗黙知のプレフィクスが多すぎて挫折するからです。私もそうでした。

本記事はVEXに対する偏見をなくし、周辺知識を少しずつ埋めていくことで抵抗心を和らげるため書きます。チョットデキる方々には退屈かもしれませんが、公式ドキュメントを調べて実践した内容で書かれているので、新しい発見があるかもしれません。

VEXの組み込み関数は膨大なため、リファレンスに理論と実践で学ぶHoudini を一冊おいておくと安心です。
(電子書籍が無いのが難点です...)

シェーダ言語として見る VEX

公式ドキュメントの中を見る限り、VEXがシェーダ言語である旨は特に明記されていません。しかし、RSLをベースに実装されていることやその文法、共通する標準ライブラリを含め、モダンなシェーダ言語の特徴を全て備えたDSLです。

  1. include 含むプリプロセッサ
  2. オフラインコンパイル
  3. 構造体 + 関数 ベースのデータ設計

モダンなシェーダ言語は LLVM 基盤で実装・最適化するのが一般的で、OSL や HLSL のバックエンド、SPILVもLLVM ベースです(最新のSPILV-Rは独自実装)。中間言語を含む最適化で高速化を実現しています。よくよく調べてみると、Houdini のライセンスに LLVM が見つかります。かつての FabricEngine にも VEX に似た KL 言語が実装されていました。これは LLVM によるjit最適化を実現していたことから、予測ではありますが VEX も LLVM によるフロントエンドコンパイラを使うシェーダ言語として扱った上で本稿の中身を書きます。

シェーダ言語との差異

モダンなレンダラーに広く搭載されているOSLとの違いはSIMD+マルチプロセスに対応していること、コンテキストのレベルの深さです。(Mantraは別) 組み込みの関数の多さが比較にならないので、VEX はシェーダ言語の領分を超えていますが、コンテキストで区分されていてその敷居をまたぐことは基本的にできません。
VEXは他のエコシステム系から完全に独立していて Houdini の中でしか使えませんが、その知識はレンダラー付属のシェーダ言語、リアルタイムのシェーダ言語に応用することが出来ます。逆に言えばシェーダプログラマーやデータプロットをルーツに持つ方々は、習得しやすいと言えます。

VOP と結局何が違うのか

お世辞にも親切なエディターとは言えなかった Unity が ShaderGraph をあとから実装したように、アーティストがコーディングしないといけない状況は必ずしも好ましいものではありません。

VOPはプログラミングに抵抗のあるアーティストに勧められていますが、ノードベースのアプリケーションは人を選びます。Substance や ICE 使っていた層はそもそもテクニカルの素養があった人が多く、オペレータや三角関数をつないでいく感覚にも慣れています。

テクニカル脳から見た時に四則演算のオペレータもノードで繋がなければいけないのは煩わしく思います。逆にコーディングをどうしても毛嫌いするアーティストもいるので、到達する手段が異なるだけで好みの違いでしか無い、と考えるのをおすすめします。

VEX: 使い方

SOP であれば Wrangle, Attribute VOP が VEX のインターフェースです。

hou.node.saveCookCodeToFile にノードのパスを引数で渡すと、VEX or RSL で保存できます。実際のパイプラインにおいては、HDAやHoudiniEngineを通して使う機会がほとんどなはずなので、vflファイルを使う場面はあまり想像できません。デバッグやコンパウンド的用途には使う場面があるかもしれません。

VEX: 言語

OOPを無くした C++ にコンテクストとVEX特有のディレクティブを足した構文になっています。Pythonに慣れすぎた体に、型の明示や文末にセミコロンを要求する言語仕様は少々きついですが、GUI側にタブとインデントが混ざってエラーになるMayaに比べれば楽かもしれません。

実際のデバッグには printfassert (厳密にはマクロ)を使うことが出来ます。

実際の公式ドキュメントから抜き出したcvexで文法を少し覗いてみます。

vex
import callee;

cvex caller()
{
    int mval = 1;
    int rval = 2;
    int wval = 1;
    callee("mval", mval, "rval", rval, "wval", wval, "castval",
            1);
    printf("%d %d %d\n", mval, rval, wval);
}

include / import ディレクティブに対応しているので、オーバーヘッドがなくなり最適化が期待できます。
最適化のため特別なディレクティブを宣言する必要はありません。

VEX: コンパイラ

Houdini を使う際に意識することはないですが、モダンなシェーダ言語はオフラインコンパイルが基本です。vcc/vexexec というコマンドラインアプリケーションがインストールされます(Maya は cgc が付属しています)。

vcc
# コンパイル
vcc -o [--vex-output] [file|-]

# cvexコンテクストに限定した関数の取得
vcc -X cvex

普段の制作ではあまり縁の無い Hscript にも VEX をサポートする便利な関数があります。

Hscript
vopwritevfl # hou.node.saveCookCodeToFile の代替
      > vopwritevfl /vex/surface1 $HIH/vex/Surface/surface1.vfl
        Write the surface1 VFL code to the proper VEX subdirectory for
        VEX Surface shaders.

      > vopwritevfl /shop/vopmaterial1 -s -c displacement $HOME/disp.vfl

        Write the displacement shader vfl code provided by the vop
        material, and skip the file header comment.

vexprofile # プロファイラー
      > vexprofile -n -a start opcook /obj/geo1/mountain1 vexprofile > /tmp/mountain.stats

vexinfo # hou.VexContext の代替
      > vexinfo -a
          Show all loaded functions.
      > vexinfo -x
          Show CVEX functions.

Hscript のエディタで呼び出すことが可能ですが mel.eval のように、Python のhou.hscript で呼び出すことが出来ます。HoudiniのPythonは非常にパワフルなので、積極的に使うことをおすすめします。
去年の記事にPythonについてまとめているので、ご興味のある方はそちらを参照して下さい。

まとめ

DCCツールは根幹部分を隠してエンドユーザが簡単には使えなくなる事が多いですが、Houdini は VEX を通してプリミティブな部分にまで触れることが出来ます。得られる自由の代償に全て理解するのは大変です。

最近のHoudiniに関してはVEX/VOPが必須項目になっているだけに、アーティストに優しいチュートリアルの登場が待たれます(日本語で)。学習曲線がなかなか上がってこない時の知識の足しになれば幸いです。