| On this page |
コンテキスト
VEXプログラムは特定の コンテキスト 用に記述します。例えば、オブジェクトのサーフェスカラーを制御するシェーダはsurfaceコンテキスト用に記述します。ライトからの輝度を決めるシェーダはlightコンテキスト用に記述します。チャンネルデータを作成またはフィルタリングするVEXプログラムは、chopコンテキスト用に記述します。
コンテキストが変われば、利用可能な関数、ステートメント、グローバル変数も変わります。
VEXを使用できるコンテキストの概要は、VEXコンテキストを参照してください。
シェーディングコンテキスト(surface、displacement、lightなど)用に記述する場合、シェーディングコンテキスト固有の情報も読んでください。
ステートメント
VEXはC言語と同様の通常のステートメントをサポートしています。また、特定のコンテキスト内でのみ利用可能なilluminanceとgatherのループなどのシェーディング固有のステートメントもサポートしています。
組み込み関数
ユーザ定義関数
関数はC言語と同様に定義します: 戻りのタイプ、関数名、括弧で括った引数のリスト、その後にコードブロックを指定します。
同じタイプの引数は、タイプを再度宣言することなくカンマ(,)区切りのリスト内に宣言することができます。他のタイプの引数はセミコロン(;)で区切らなければなりません。
int test(int a, b; string c) { if (a > b) { printf(c); } }
同じ名前で引数の数やタイプが異なる、または戻りのタイプが異なる関数を オーバーロード することができます。
オプションのfunctionキーワードを使って関数定義を導入することで、タイプの曖昧さを回避することができます。
function int test(int a, b; string c) { if (a > b) { printf(c); } }
void print(basis b) { printf("basis: { i: %s, j: %s, k: %s }\n", b.i, b.j, b.k); } void print(matrix m) { printf("matrix: %s\n", m); } void print(bases b) { printf("bases <%s> {\n", b.description); printf(" "); print(b.m); printf(" "); print(b.n); printf(" "); print(b.o); printf("}\n"); } basis rotate(basis b; vector axis; float amount) { matrix m = 1; rotate(m, amount, axis); basis result = b; result.i *= m; result.j *= m; result.k *= m; return result; } void rotate(basis b; vector axis; float amount) { b = rotate(b, axis, amount); }
メモ
-
ユーザ関数は、参照される前に宣言しなければなりません。
-
関数は、コンパイラで自動的にインラインされます。そのため、 再帰関数は動作しません 。再帰アルゴリズムを書くには、代わりにシェーダコールを使います。
-
RenderManシェーディング言語と同様に、ユーザ関数に渡すパラメータは常に 参照 です。つまり、ユーザ関数内の修正は、それをコールした関数の変数に影響があります。
-
ユーザ関数の数に制限はありません。
-
関数内に2つ以上のreturnステートメントを記述することができます。
-
直接グローバル変数にアクセスすることができます(RenderManシェーディング言語と違い、
externでグローバル変数を宣言する必要はありません)。 しかし、グローバル変数にアクセスしないことを推奨します。なぜなら、これは、あなたが作成した関数が1つのコンテキスト(そのグローバル変数が存在するコンテキスト)内でのみしか動作しなくなるからです。 代わりに、グローバル変数をパラメータとして関数に渡してください。
メイン(コンテキスト)関数
VEXプログラムには、戻りのタイプがコンテキストの名前である関数を1つ含めなければなりません。その関数が、Mantraでコールされるプログラムのメイン関数となります。コンパイラはファイル毎に1つのコンテキスト関数を必要とします。
この関数には、必要な情報の計算とグローバル変数の修正の作業(組み込み関数またはユーザ定義関数をコールする)をさせるべきです。コンテキスト関数から値を返すreturnステートメントは使わないでください。各コンテキストで利用可能なグローバル変数用に関しては、特定のコンテキストのページを参照してください。
コンテキスト関数への引数は、もしあれば、プログラム用のユーザインターフェースになります。例えば、VEXプログラムを参照するシェーディングノードのパラメータがそれです。
コンテキスト関数のパラメータと同じ名前のジオメトリアトリビュートが存在すれば、そのアトリビュートは、パラメータの値を上書きします。これによって、ジオメトリ上のアトリビュートをペイントすることでVEXコードを制御することができます。
surface noise_surf(vector clr = {1,1,1}; float frequency = 1; export vector nml = {0,0,0}) { Cf = clr * (float(noise(frequency * P)) + 0.5) * diffuse(normalize(N)); nml = normalize(N)*0.5 + 0.5; }
Note
コンテキスト関数へのパラメータは、VEXで特別な方法によって扱われます。 パラメータと同じ名前のジオメトリアトリビュートを使ってパラメータの値を上書きすることができます。 この特別な場合を除いては、パラメータはシェーダのスコープ内では、“const”とみなされるはずです。 つまり、パラメータの値を修正することは不当です。 コンパイラは、これが起きるとエラーを発生します。
exportキーワードを使えば、元のジオメトリに対して修正したいパラメータのフラグを立てることができます。
ユーザインターフェースのプラグマ
Houdiniでこのプラグマから生成したユーザインターフェースは最小限(基本的には変数名とデータタイプに基づいた汎用テキストフィールド)のインターフェースです。例えば、frequencyパラメータなら、ある範囲内のスライダのUIに、clrはカラーピッカーUIとして指定したい場合があります。これらのことがユーザインターフェースコンパイラのプラグマを使うことで可能です。
#pragma opname noise_surf #pragma oplabel "Noisy Surface" #pragma label clr "Color" #pragma label frequency "Frequency" #pragma hint clr color #pragma range frequency 0.1 10 surface noise_surf(vector clr = {1,1,1}; float frequency = 1; export vector nml = {0,0,0}) { Cf = clr * (float(noise(frequency * P)) + 0.5) * diffuse(normalize(N)); nml = normalize(N)*0.5 + 0.5; }
演算子
VEXには標準のC言語の演算子をC言語と同じ優先順位で持っています。以下にC言語と違う箇所を説明します。
乗算は、2つのベクトルまたはポイント間で定義されます。乗算は、エレメント対エレメントで計算を実行します(内積や外積とは違います。crossとdotを参照してください)。
ほとんどの演算子が非スカラーデータタイプ用に定義されています(つまり、ベクトルにマトリックスを乗算すると、ベクトルがマトリックスでトランスフォームします)。
2つの異なるタイプを演算子で組み合わせた時の曖昧な状況では、結果は、2番目(右側)の値のタイプになります。例えば、整数とベクトルを以下の順番で加算すると、結果はベクトルになります。
int + vector = vector
ドット演算子
ドット演算子(.)を使えば、vector、matrix、structの個々のコンポーネントを参照することができます。
ベクトルでは、コンポーネントの名前が固定されています。
-
.xまたは.uはvector2の1番目のエレメントを参照します。 -
.xまたは.rはvectorやvector4の1番目のエレメントを参照します。 -
.yまたは.vはvector2の2番目のエレメントを参照します。 -
.yまたは.gはvectorやvector4の2番目のエレメントを参照します。 -
.zまたは.bはvectorやvector4の3番目のエレメントを参照します。 -
.wまたは.aはvector4の4番目のエレメントを参照します。
u,v/x,y,z/r,g,bの文字の選択は任意です。 ベクトルはポイントやカラーのどちらかを保持するわけではないので、どちらの文字でも構いません。
マトリックスに関しては、1組の文字を使用することができます。
-
.xxは、[0][0]エレメントを参照します。 -
.zzは、[2][2]エレメントを参照します。 -
.axは、[3][0]エレメントを参照します。
さらに、ドット演算子を使用することで、ベクトルのコンポーネントを“Swizzle(かき混ぜる)”させることができます。例えば、
-
v.zyxは、set(v.z, v.y, v.x)と等価です。 -
v4.bgabは、set(v4.b, v4.g, v4.a, v4.b)と等価です。
Note
Swizzle(かき混ぜる)させたベクトルに値を割り当てることはできません。
あくまで読み込み専用です。
そのため、v.zyx = bはできず、反対にv = b.zyxはできます。
比較
比較演算子(==, !=, <, <=, >, >=)は、その演算子の左側と右側を比較します。この演算子は、string、float、intのタイプだけに対応します。
演算結果は、intタイプです。
文字列マッチング演算子(~=)は、演算子の両側に文字列がある場合にのみ定義することができ、両側の2つの値を使ってmatch関数をコールすることと等価です。
論理演算子(&&, ||, !)とビット演算子(& |, ^, ~)はintのタイプのみに対応します。
優先順位テーブル
テーブルで上にある演算子ほど優先度が高いです。
優先度 |
演算子 |
関連性 |
説明 |
|---|---|---|---|
15 |
|
LtR |
関数コール、エクスプレッションのグループ化、構造体メンバー |
13 |
|
LtR |
論理否 |
13 |
|
LtR |
1の補数 |
13 |
|
LtR |
単項のプラス(例えば、 |
13 |
|
LtR |
単項のマイナス(例えば、 |
13 |
|
LtR |
インクリメント(例えば、 |
13 |
|
LtR |
デクリメント(例えば、 |
13 |
|
LtR |
型変換(例えば、 |
12 |
|
LtR |
乗算 |
12 |
|
LtR |
割算 |
12 |
|
LtR |
剰余 |
11 |
|
LtR |
加算 |
11 |
|
LtR |
減算 |
10 |
|
LtR |
未満 |
10 |
|
LtR |
より大きい |
10 |
|
LtR |
以下 |
10 |
|
LtR |
以上 |
9 |
|
LtR |
等号 |
9 |
|
LtR |
不等号 |
9 |
|
LtR |
文字列マッチ |
8 |
|
LtR |
ビット演算のAND |
7 |
|
LtR |
ビット演算のXOR |
6 |
|
LtR |
ビット演算のOR |
5 |
|
LtR |
論理積 |
4 |
|
LtR |
論理和 |
3 |
|
LtR |
条件演算子(例えば、 |
2 |
|
RtL |
変数割当て |
1 |
|
LtR |
引数の区切り文字 |
オペレータタイプの相互作用
-
floatとintを演算した場合、その結果のタイプは、その演算子の左側のタイプになります。つまり、float * int = float、int * float = intです。 -
ベクトルをスカラー値(
intまたはfloat)で加算、乗算、割算、減算した場合、VEXは、コンポーネント毎に演算が適用された同じサイズのベクトルを返します。例:{1.0, 2.0, 3.0} * 2.0 == {2.0, 4.0, 6.0} -
異なるサイズのベクトルを加算、乗算、割算、減算した場合、VEXは、大きいサイズのベクトルを返します。この演算はコンポーネント毎に適用されます。
重要: 小さい方のベクトルの“足りない”コンポーネントは、
{0.0, 0.0, 0.0, 1.0}のように充たされます。{1.0, 2.0, 3.0} * {2.0, 3.0, 4.0, 5.0} == {2.0, 6.0, 12.0, 5.0}これは、想定外の結果を招くことがあります。例:
// vector2の3番目の要素は0として処理されますが、 // 4番目の要素は1.0として処理されています。 {1.0, 2.0} + {1.0, 2.0, 3.0, 4.0} == {2.0, 4.0, 3.0, 5.0}
異なるサイズのベクトルを組み合わせる場合、それらのコンポーネントを抜き出して、それぞれのコンポーネントを“手動”で演算させることで、想定内の結果を得ることができます。
データタイプ
Warning
デフォルトでは、VEXは32ビットの整数を使用します。もしAttribCast SOPを使ってジオメトリアトリビュートを64ビットに変換した場合、VEXコード内のアトリビュートを操作する時にはVEXは静かに余分なビットを破棄してしまいます。
VEXエンジンは32ビットモードまたは64ビットモードのどちらかで走ります。
32ビットモードでは、すべての浮動小数点、ベクトル、整数が32ビットです。
64ビットモードでは、それらが64ビットになります。
数学で精度を混在させることができるようにdoubleタイプもlongタイプもありません。
アンダースコアを使用すれば、長い番号を区切ることができます。
タイプ |
定義 |
サンプル |
|---|---|---|
|
整数値 |
|
|
浮動小数点のスカラー値 |
|
|
2つの浮動小数点値。これらの値を使えば、テクスチャ座標(しかし、通常ではHoudiniはベクトルを使用します!)や複素数を表現することができます。 |
|
|
3つの浮動小数点値。これらの値は、位置、方向、法線、カラー(RGB または HSV)を表現するために使用することができます。 |
|
|
4つの浮動小数点値。これらの値は、同次座標の位置、アルファ付きのカラー(RGBA)を表現するために使用することができます。これはクォータニオンの表現でよく使用されます。VEXでのクォータニオンは |
|
|
値のリスト。詳細は、配列を参照してください。 |
|
|
名前を付けた値の固定セット。詳細は、構造体を参照してください。 |
|
|
4個の浮動小数点値。これらの値は2D回転マトリックスを表現します。 |
|
|
9個の浮動小数点値。これらの値は3D回転マトリックスまたは2Dトランスフォーメーションマトリックスを表現します。 |
|
|
16個の浮動小数点値。これらの値は3Dトランスフォーメーションマトリックスを表現します。 |
|
|
文字列。詳細は、文字列を参照してください。 |
|
|
|
|
|
Bidirectional Scattering Distribution Function (双方向散乱分布関数)。BSDFの情報は、PBRシェーダの記述を参照してください。 |
構造体
Houdini12では、struct(構造体)キーワードを使って新しく構造化されたタイプを定義することができます。
C+11のメンバー初期化と同様に、構造体定義内でメンバーデータにデフォルト値を割り当てることができます。
2つの暗黙コンストラクタ関数が構造体毎に作成されます。 1つ目の関数は、構造体内に宣言された初期化引数の順番で、それらの引数を受け取ります。2番目の関数は、引数を受け取りませんが、すべてのメンバーをデフォルト値に設定します。
#include <math.h> struct basis { vector i, j, k; } struct bases { basis m, n, o; string description; } struct values { int uninitialized; // メンバーデータが初期化されていません int ival = 3; float fval = 3.14; float aval[] = { 1, 2, 3, 4.5 }; } basis rotate(basis b; vector axis; float amount) { matrix m = 1; rotate(m, amount, axis); basis result = b; result.i *= m; result.j *= m; result.k *= m; return result; } // 構造体変数を宣言します basis b0; // デフォルト値(この場合では0)を使って初期化します basis b1 = basis({1,0,0}, {0,1,0}, {0,0,1}); // コンストラクタを使って初期化します basis b2 = { {1,0,0}, {0,1,0}, {0,0,1} }; // 明示的な構造体として初期化します b1 = rotate(b1, {0,0,1}, M_PI/6);
Note
構造体はソースファイルで使用する前に定義しなければなりません。
構造体関数
構造体内部で関数を定義することで、コードを整理し、オブジェクト指向プログラミングの制限された形式を可能にすることができます。
-
構造体関数内では、
thisを使って構造体インスタンスを参照することができます。 -
構造体関数内では、構造体フィールドを変数であるかのように名前で参照することができます(例えば、
basisはthis.basisのショートカットです)。 -
->矢印オペレータを使って構造体インスタンスの構造体関数をコールすることができます(例えば、sampler->sample())。this->method()を使って構造体の他のメソッドをコールすることができるように構造体関数内部に記述します。
struct randsampler { // フィールド int seed; // メソッド float sample() { // 構造体関数は名前でフィールドを参照することができます。 return random(seed++); } } cvex shader() { randsampler sampler = randsampler(11); for (int i = 0; i < 10; i++) { // ->を使って構造体インスタンスのメソッドをコールします。 printf("%f\n", sampler->sample()); } }
Mantra固有のタイプ
Mantraには、事前定義された構造体タイプがいくつかあり、シェーディング特有の関数で使用します。
|
Mantraシェーディングコンテキストのみで定義されています。これは、光源のハンドルを表現した構造体です。 この構造体には、メソッドがあります:
IFDで、 これらのステートメントは、ライトオブジェクトに対して |
|
Mantraシェーディングコンテキストのみで定義されています。これは、オブジェクトに割り当てられたマテリアルを表現した不透明度の構造体です。 |
|
Mantraシェーディングコンテキストのみで定義されています。これは、Light Path Expressionsのアキュムレータ(累算器)を表現した構造体です。 この構造体にはメソッドがあります:
|
キャスト(型変換)
変数の型変換
これは、C++やJavaの型変換と同様です。あるタイプの値を他のタイプの値に変換します(例えば、intからfloat)。
これは以下のような場合に必要になる時があります:
int a, b; float c; c = a / b;
このサンプルでは、コンパイラは整数の割算をします(タイプの計算を参照してください)。そうではなくて、浮動小数点の割算をしたかったので
あれば、明示的にaとbをfloatに変換します:
int a, b; float c; c = (float)a / (float)b;
これで型変換が行なわれます。これにより、コードのパフォーマンス性能が問題になる場合があります。
関数のキャスト(型変換)
VEXは、引数のタイプだけでなく戻り値のタイプに基づいて関数を割り当てます(C++やJavaのように)。 同じ引数のタイプでも戻り値のタイプが異なる関数を明確にコールするためには、 関数をキャスト(型変換) します。
例えば、noise関数は異なるパラメータタイプを受け取り、異なるタイプを返すことができます。つまり、noiseはfloatまたはvectorのどちらかを返すことができます。
コード:
float n; n = noise(noise(P));
VEXはfloat noise(vector)またはvector noise(vector)のどちらかに割り当てることができます。
関数コールをキャスト(型変換)するには、以下のようにtypename( ... )で関数を囲みます:
n = noise( vector( noise(P) ) );
これは関数コールのように見えますが、内部で関数コールを明示しているだけで、パフォーマンスのオーバーヘッドがありません。
関数のキャスト(型変換)は、関数コールを直接的に指定したタイプの変数に割り当てた時に暗黙的に行なわれます。 以下のエクスプレッションは、どちらも同じで、関数のキャスト(型変換)はコードをより簡潔にするために省略することがあります:
vector n = vector( noise(P) ); // 不要な関数キャスト(型変換) vector n = noise(P);
Note
VEXが、あなたがコールしようとしている関数の引数やタイプを決めることができない時、曖昧なエラーとして候補となる関数を出力します。 適切な戻り値を選択して、それが選択されるように関数キャスト(型変換)を追加してください。
関数のキャスト(型変換)が任意のタイプの変換を生成しない(単にコールする関数を選択するだけ)ので、それを使ったパフォーマンス低下はありません。 パフォーマンスの低下を避けるためにできるだけ変数のキャスト(型変換)よりも関数のキャスト(型変換)を使う方が良いです。
コメント
VEXはC++スタイルのコメントを使用します:
-
1行コメントは頭に
//を付けます。 -
自由形式のコメントは、
/*で始めて、*/で終えます。
予約語
break, bsdf, char, color, const, continue, do, dict, else,
export, false, float, for, forpoints, foreach, gather,
hpoint, if, illuminance, import, int, integer, matrix,
matrix2, matrix3, normal, point, return, string, struct, true,
typedef, union, vector, vector2, vector4, void, while