Houdini VEXの構文について


前回の記事では、VEXにおける変数の紹介を行いました。この記事では、VEXの簡単な構文について紹介します。

算術演算

まずは算術演算です。

VEXでは演算には演算子というものを使って行います。
一般的な算数と同じように + や – を利用するものもあれば、そうでないものもあります。

以下が四則演算です。

//加算
int a = 1+2;
//   -> 3
//減算
int b = 1-2;
//   -> -1
//乗算
int c = 1*2;
//   -> 2
//除算
int d = 1/2;
//   -> 0

乗算では * 、除算では / を利用します。今回は整数型の変数を利用しているため、1/2の結果は0になります。

次に、こちらがVEXで利用可能な四則演算以外の基本的な算術演算です。

//余剰
int e = 1%2;
//   -> 1
//インクリメント
int f = e++;
//   -> 2
//デクリメント
int g = e--;
//   -> 0

インクリメントとは元の変数に1を加算する演算で、デクリメントは1を減算する演算です。
インクリメント/デクリメントは変数にしか利用ができないので、今回の例では余剰計算結果が代入された変数eに対して行っています。

また、括弧を使うことで演算順番の設定を行うことも可能です。

int h = 1+2-3*4;
//   -> -9
int i = ((1+2)-3)*4;
//   -> 0

上の行では、演算優先度の高い乗算が先に行われてから、加減算が行われているのに対し、
下の行では、括弧に従って、左から順に計算が行われていきます。

また、VEXにおけるC言語との算術演算の相違点は以下になります。

  1. vector型に対して*演算子を用いると、コンポーネントごとに乗算されます。内積、外積の算出には関数を利用する必要があります。
     
  2. ほとんどの演算子について、非スカラーデータ型で利用できるように定義されています。
    例えば、ベクトルにマトリックス(行列)を乗算すると、ベクトルが行列によって変換されます。
      
  3. ふたつの異なる型の変数を演算子で演算した際の計算結果の型は、2番目(右側)の値の型になります。
    例えば、整数とベクトルを、整数-> ベクトルの順番で加算すると、計算結果はベクトル型で返されます。

 

制御構文/比較演算/論理演算

制御構文と、これら2つの演算はVEXでは基本的に同時に使われることが多いので、ここで一緒に紹介します。
こちらは少し複雑なのでhipファイルをご用意させていただきました。

VEXにおける制御構文とは、簡単に説明すると、「分岐」「繰り返し」です。
HoudiniのSOPノードで言うと、SwitchノードとFor Eachノードが近い考え方を持っています。

分岐

まず分岐とは、条件に基づいて処理を切り替える構文です。

今回の例では、ポイント番号の値によってポイントに与える、Cdアトリビュートの値を切り返るような処理を考えます。

ポイント番号を調べて、50番以上ならCdをに設定、50番以上でないなら、に設定します。

例えば、これをVOPで記述すると、このようになります。

まず、入力ジオメトリからptnumを取り出して、Compareノードで50以上の数字かどうかを比較して調べます。
そしてその結果をIf Beginノードに入力し、結果が正しければ、(1, 0, 0) を、正しくなければ(0, 0, 0)Endブロックから出力されます。
最後にその結果を各ポイントのCdアトリビュートとして出力しています。

これをGridオブジェクトに適用したものがこちらになります。

ご覧の通り、0-49ポイントは、50-99ポイントはになっていること確認できます。

これを実際にVEXで記述してみると、このようになります。

if(@ptnum>=50)
    @Cd=set(1.0, 0.0, 0.0);
else
    @Cd=set(0.0, 0.0, 0.0);

VOPで作成した場合より、非常に簡素に構成されていることがわかります。
ifの右側にあるのが条件となり、その条件が満たされるときはifの下の行を、満たされないときはelseの下の行が実行されます。

 

繰り返し

次に繰り返しとは、特定の条件が満たされているかどうかで、処理を繰り返すかどうかを制御する構文です。

今回の例では、各ポイントのY座標の値の平均値をCdアトリビュートの緑成分に与えるような処理を考えます。

例えば、これをVOPで記述すると、このようになります。

まず、入力ジオメトリからptnumを取り出し、For Beginノードのlength_inに接続して反復数を指定します。
Forブロック内で、Get Attributeノードでジオメトリの座標Pを取得し、Vector to FloatノードでY成分を抜き出し、足し合わせます。
index_outGet Attributeノードのi1に接続することで、Forブロックによるループにより、全てのポイント数のY座標を加算します。
最後に、 numptで除算することで平均値を算出し、Float to Vectorノードでベクトルに変換してからCdに出力しています。
ptnumが現在処理しているポイント番号を指すのに対し、numptとはジオメトリに存在する全てのポイントの総数を指します。

これをMountainノードが接続されたGridオブジェクトに適用したものがこちらになります。

ご覧の通り、全てのポイントの色が濃い緑になったかと思います。この数値が全てのポイントのY座標の平均値となります。
実際にGeometry Spreadsheetでアトリビュートを確認してみると、
以下のように全てのポイントのCd.gの値に、0.300353という数値が入っているのがわかります。

これを実際にVEXで記述してみると、このようになります。

float y_sum=0.0;
for(int i=0; i<@numpt; i++){
 vector pos=point(0,"P",i);
 y_sum+=pos.y;
}
@Cd=set(0, y_sum/@numpt, 0);

こちらも、VOPで作成した場合より、非常に簡素に構成されていることがわかります。
forの右側にあるのが条件となり、その条件が満たされるときは {} の中の行を繰り返し、満たされないときは の下の行が実行されます。

for文はifと違い括弧の中が条件だけではありません。形式は for(初期値; 条件; 変化) となります。
初期値というのはループに入る前の処理で、ここではint型の変数x初期値0で作成しています。
条件はif文と同じです。ここではi@numpt未満であることを条件にしています。
最後の変化というのは、{}内の処理が一回終わるごとに実行される部分です。ここではiの値がインクリメントされます。

つまりこのfor文では、最初にint i を定義し、一周するごとにiを足していき、最終的にiが@numptと同じ数になればループ終了です。
iの値がpoint関数の引数になることで、Point Attribute P を「i番目のポイント」という形で取得することができるようになっています。

 

比較演算

次に比較演算についてですが、こちらは既にこの記事内で登場しております。

これは簡単に説明をするならば、VOPでいうところの、Compareノードになります。
式の右辺と左辺を比較する演算で、比較演算子というものが用いられます。

比較演算子は数が少なく、一般的にHoudiniで用いられるのは、この6種です。

演算子 意味
== 右辺と左辺が等しい
等号
> 左辺が右辺より大きい
超過
< 左辺が右辺より小さい
未満
>= 左辺が右辺より大きいか等しい
以上
<= 左辺が右辺より小さいか等しい
以下
!= 右辺と左辺が等しくない
不等号

使い方は、既に分岐や繰り返しの箇所で登場しているように、制御構文中で「条件」として使うことが一般的です。
例えば、先ほどの分岐の部分では、このような行がありました。

if(@ptnum>=50)

これは、「以上」の比較演算になります。@ptnumの値が50以上かどうかを調べる比較演算です。
この比較の結果を利用して制御構文ifが動作しております。

 

論理演算

最後に論理演算です。論理演算とはANDやORのことです。これは主にビット演算と論理和論理積の2種類があるのですが、
ビット演算は初歩の内容では必要ないので、ここでは論理和 / 論理積について紹介します。

簡単に紹介してしまうと、これが論理和です。

if(@ptnum>=50 || @ptnum<25)

これはORになります。先ほどが@ptnumの値が50以上、だけが条件でしたが、
今度は@ptnumの値が50以上または、@ptnumの値が25未満かどうかを調べています。
先ほどの分岐のif文と入れ替えてみると、0-24と50-99のポイントが赤くなります。

次に、こちらが論理積です。

if(@ptnum>=50 && @ptnum<75)

これはANDになります。
今度は@ptnumの値が50以上かつ、@ptnumの値が75未満かどうかを調べています。
先ほどの分岐のif文と入れ替えてみると、50-74のポイントが赤くなります。

以上がHoudini VEXの基本的な構文となります。

次の記事では、実際にWrangleというノードを用いて、複数行のスニペッドを用いて、
実際にジオメトリを制御しながらVEXコードの簡単な書き方を紹介します。