Houdini 20.0 VEX

VEXユーザ向けのOpenCL

VEXの観点で説明したOpenCLの思想

On this page

なぜOpenCLなのか?

VEXは、ほとんどの計算で必要とされるものに最適です。 しかし一部の類のアルゴリズムでは、高速なGPUでの実行に適した構造になっているものがあります。 VEXはGPU上で実行できないため、別の言語でアルゴリズムを記述する必要があります。

OpenCLは、GPUとCPUの両方の実装をサポートしている標準のカーネル言語です。 GPUを搭載していないマシンでもアルゴリズムを実行でき、2つのバージョンを維持する必要はありません。

GPUの恩恵を受けるための主な要件は、データをGPUに保持することです。 OpenCLでないノードがジオメトリを処理する場合には、そのデータはCPUに戻され、それによってパフォーマンス上の利点が失われることがよくあります。 SOPでは、各SOPがクック完了後にジオメトリを戻してローカルキャッシュに保存しなければならないことに注意してください。 これは、OpenCLノードチェーンをコンパイルブロック内に入れることで回避することができます。

なぜOpenCLではだめなのか?

OpenCLは、VEXに比べるとかなり扱いにくい言語ですが、VEXの経験があれば、その多くは理解しやすいでしょう。 ポインタを使用するため、安全でないコードを記述してしまいやすく、それによってビデオカードドライバやHoudiniをクラッシュさせてしまう可能性があることに注意してください。 開発中、コンパイル時にすべてのカーネルでエラーが発生するなど、ひどい状態に陥る可能性もあります。 Houdiniを再起動して、ドライバを復元する必要が生じるかもしれません。 稀にマシンの再起動が必要になる場合もあります。

GPUは仮想メモリを持たないため、通常は割り当てるデータ量が多すぎるとスワップや速度低下が生じますが、OpenCLを使用した場合だと、割り当ての失敗やエラーが発生します。

構文と言語

OpenCLは、VEXと同様にC言語に似ています。どちらも見た目は同じで、各行はセミコロンで終了する必要があり、中括弧を使用してブロックを囲みます。

OpenCL自体はC99規格に準拠しているため、C99規格のオンラインリソースも参照することができます。

OpenCLにforeach()はありません。

関数のパラメータには、各パラメータの型が必要で、セミコロン(;)ではなくカンマ(,)で区切ります。

Vex:

int foo(float a; int b, c)
{
    return a + b + c;
}

OpenCL:

int foo(float a, int b, int c)
{
    return a + b + c;
}

OpenCLのパラメータは、常に“値渡し”です。 つまり、関数内でパラメータを変更しても、渡された値には影響しません。 しかし、OpenCLにはポインタがあるため、ポイントで指されているものを変更すると、元の値にも影響します。

VEXでは、関数内部で関数を宣言することができますが、OpenCLでは不可能です。

カーネル

VEXとOpenCLは、どちらもカーネル言語です。 多くのアルゴリズムでよく見受けられる外側ループを回避するというのが、カーネル言語の考え方です。 各ポイントに何か追加したい場合、従来の言語では以下のようになります:

for (int i = 0; i < number_of_points; i++)
{
    process_point(i);
}

しかし、明示的な外側ループによって、最適化が非常に困難になります。 というのも、process_pointが以前のコールに依存しているかもしれないからです。 代わりにprocess_pointのみを記述することで、よりシンプルながらも、簡単に並列で実行できるコードになります。 これを利用することで、VEXは数百万ものポイントを迅速に処理し、OpenCLはGPUが効率的にそのプログラムを実行できるようにします。

通常のVEX Wrangle SOPでは、process_point()関数は非表示になっています。 process_point()内にコードを記述するには、以下のようなスニペットを使用します:

@P += 1;

シーンの背後では、Wrangleノードは以下のようなカーネルのラッパー関数を構築します:

void process_point(vector _bound_P)
{
_bound_P += 1;
}

cvex dowrangle(export vector P)
{
    process_point(P);
}

このdowrangleカーネルは、VEXランタイムに渡されて、すべてのポイントで実行されます。

OpenCLノードには、それと同じ自動ラッパーはありません。 代わりに、dowrangleと同等のものをカーネル関数として記述する必要があります。

同等のOpenCLコードは以下のようになります:

kernel void dowrangle(
                 int P_length,
                 global float * restrict P
)
{
    int idx = get_global_id(0);
    if (idx >= P_length)
        return;

    float3 pos = vload3(idx, P);
    pos += 1;
    vstore3(pos, idx, P);
}

OpenCLノードでは、PPointアトリビュートを書き出せるようにするには、そのアトリビュートのバインドを明示的に設定する必要があります。

定型文を最小限にして、vloadvstoreを使用することなくアトリビュートへ直接アクセスできるようにするために、OpenCLノードには @-Binding モードも用意されています。 このモードが有効な時、 @KERNEL を使用してカーネルを指定することができ、それに適切な定型文が挿入されます。このコードは以下のようになります:

#bind point &P float3

@KERNEL
{
    float3 pos = @P;
    pos += 1;
    @P.set(pos);
}

Write-backカーネルが有効なSOPでは、@WRITEBACKを使用することで、Write-backカーネルを生成することができます。

Run Over

VEX Wrangleの重要なコンポーネントは、Run Overパラメータです。 これは、カーネルが実行されるエレメントを制御します。 例えば、Run Overをポイントに設定すると、カーネルはポイント毎に1回実行されます。 Volume Wrangleはその性質上、ボリュームとVDBでのRun Overに暗黙的に設定されているため、ボクセル毎にカーネルが実行されます。

OpenCLでは、カーネルのプライマリターゲットまでも指定する必要があります。 これは、書き込み先である必要はなくて、単にGPUに渡されるワークアイテムの数を定義するだけです。

最も単純な実行モードはFirst-Writableモードです。 これらは、最初の書き込み可能なアトリビュート、ボリューム、VDBを見つけ、それを実行のテンプレートとして使用します。

Run OverをDetailにして直列での実行を強制された場合でさえも何とか処理するVEXとは異なり、GPUは直列による実行をうまく処理できず、常に多くのエレメントをターゲットにします。

VEX WrangleのRun OverのNumberに相当するものが Detail Attribute of Worksets です。 ただし固定の数ではなく、入力ジオメトリ上のDetail配列アトリビュートのペアを受け取って、ワークフローアイテムを作成します。 これにより、複雑さはかなり増しますが、GPUの実行を非常に正確に制御することができます。

ドット演算子

VEXでは、ドット演算子(.)を使用してベクトルのコンポーネントにアクセスすることができます。 x、y、z、wや、r、g、b、a、さらにはu、vも使用することができます。 これらを組み合わせて、ベクトルをSwizzle(コンポーネントの並べ替え)することができ、例えばv.zyxは逆順の3次元ベクトルを作成します。

OpenCLには、それに似た表記方法があります。 また、ベクトル型の下位半分と上位半分を抽出する.lo.hiや、奇数番目と偶数番目を引き出す.odd.evenもあります。 ベクトル型は最大でfloat16(16個のfloat)まで対応し、.s表記もあります。 .s0.xと同じで、.s01.xyと同じです。 .s表記に9を超える数を使用する場合は、aからfまたはAからFを10から15に使用できます。

Note

OpenCLはVEXの.uまたは.vの亜種をサポートしていません。

組み込み関数

VEXと異なり、OpenCLの組み込み関数のセットは非常に少ないです。 VEXでは様々な演算が可能で、誤差関数の計算からジオメトリ上のポイントの照会まで、何でも行なうことができます。 OpenCLの内部関数は、大部分が純粋に数学的なものです。

残念なことに、組み込みマトリックスはほとんどサポートされていません。 matrix.hが用意され(およびデフォルトでスニペットに含まれ)、いくつかの方法でマトリックスの乗算を行なうことができます。

Note

mat3のサイズは、実際は12個のfloatです。

Note

selectはOpenCLとVEXの両方にありますが、残念なことに引数の順序が異なります。 VEXでは条件が最初、OpenCLでは条件が最後にきます。

matrix関数

注目すべきmatrix.h関数は以下の通りです:

関数

説明

mat2 transpose2(const mat2 a)

転置されたaを返します。

mat3 transpose3(const mat3 a)

転置されたaを返します。

mat2 mat2mul(const mat2 a, const mat2 b)

a * bを返します。

fpreal2 mat2vecmul(const mat2 a, const fpreal2 b)

b * Aを返します。

fpreal squaredNorm2(const mat2 a)

2×2マトリックスのL2ノルムの2乗を返します。

fpreal squaredNorm3(const mat3 a)

3×3マトリックスのL2ノルムの2乗を返します。

void mat3add(const mat3 a, const mat3 b, mat3 c)

c = a + b

void mat3sub(const mat3 a, const mat3 b, mat3 c)

c = a - b

mat3zero(mat3 a)

a = 0

mat3identity(mat3 a)

a = identity

mat3copy(const mat3 a, mat3 b)

b = a

mat3load(size_t idx, const global float *a, mat3 m)

a[idx*9]で始まる9個のfloatをmに読み込んで格納します。行優先(row-major)で読み込みます。

mat3store(mat3 in, size_t idx, const global float *data)

9個のfloatを行優先で、順にdata[idx*9]に格納します。

void mat3fromcols(const fpreal3 c0, const fpreal3 c1, const fpreal3 c2, mat3 m)

指定したベクトルの列で3×3マトリックスを作成します。

mat3 mat3mul(const mat3 a, const mat3 b)

a * bを返します。

fpreal3 mat3vecmul(const mat3 a, const fpreal3 b)

b * Aを返します。

fpreal3 mat3Tvecmul(const mat3 a, const fpreal3 b)

b * A^Tを返します。

fpreal2 mat3vecmul(const mat3 a, const fpreal3 b)

b * Aを返します。3番目のコンポーネントは破棄されます。

fpreal2 mat3Tvecmul(const mat3 a, const fpreal3 b)

b * A^Tを返します。3番目のコンポーネントは破棄されます。

void outerprod3(const fpreal3 a, const fpreal3 b, mat3 c)

cをaとbの外積に設定します。

void mat3lcombine(const fpreal s, const mat3 a, const fpreal t, const mat3 b, mat3 c)

c = s * a + t * b

fpreal det3(const mat3 a)

aの行列式を返します。

fpreal3 diag3(const mat3 a)

aの対角ベクトルを返します。

fpreal2 mat4vec2mul(const mat4 a, const fpreal2 b)

b * Aを返します。

fpreal3 mat43vec3mul(const mat4 a, const fpreal3 b)

b * Aを返します(bの4番目のコンポーネントは0であると仮定)。

fpreal3 mat4vec3mul(const mat4 a, const fpreal3 b)

b * Aを返します(bの4番目のコンポーネントは1であると仮定)。

fpreal4 mat4vecmul(const mat4 a, const fpreal4 b)

b * Aを返します。

int mat4invert(fpreal16 *m)

mをその逆行列で更新します。成功した場合は0、特異行列なら1を返します。

fpreal mat2det(const mat2 m)

mの行列式。

fpreal mat2inv(const mat2 m, mat2 *minvvout)

minvoutをmの逆行列に設定します。行列式を返します。

fpreal mat3inv(const mat3 m, mat3 minvout)

minvoutをmの逆行列に設定します。行列式を返します。

void mat3scale(mat3 mout, const mat3 m, fpreal scale)

mout = m * scale

void mat3lincomb2(mat3 mout, const mat3 m1, fpreal scale1, const mat3 m2, fpreal scale2)

mout = m1 * scale1 + m2 * scale2

精度

VEXは、全体で単精度で実行されます。 floatは、32Bitモードでは32ビット、64 Bitモードでは64ビットです。したがって、doublefloatの区別はありません。

OpenCLの精度は固定されています。 しかし、32ビットの方が計算がかなり高速であり、一方で、何かしらの問題で64ビットが必要になることもあるので、必要に応じて精度を切り替えるコードを記述したい場合がよくあります。

組み込みのOpenCLの型には固有の精度があります。 fprealおよびexintという2つの新しい型が追加され、これらの精度はノードや入力ジオメトリに依存します。 そのため、コードを1回記述するだけで、複数の精度でそのコードを動作させることができます。

名前

精度

half

16

Float

float

32

Float

double

64

Float

fpreal

可変

Float

short

16

Integer

int

32

Integer

long

64

Integer

exint

可変

Integer

OpenCLとVEXは、基本の型は似ていますが、名前が異なります。 mat2/3/4型は、matrix.hで定義されています。 以下のfloatは、任意の浮動小数点精度(halffloatdoublefpreal)に置き換えることができます(intでも可能)。

VEX

OpenCL

int

int

Integer値

--

int2/3/4/8/16

指定された数のコンポーネントのIntegerベクトル

float

float

Float値

vector2

float2

2つのコンポーネントを持つベクトル

vector

float3

3つのコンポーネントを持つベクトル。OpenCLでは、これは4個のfloatによってメモリ内に配置されるため、構造t体で使用する場合は注意する必要があります。

vector4

float4

4つのコンポーネントを持つベクトル。

--

float8/16

OpenCLには、ネイティブの8および16のコンポーネントを持つベクトルもあります。

matrix2

float4, mat2

float4はmatrix2と同じサイズですが、より分かりやすくし、いくつかのユーティリティ関数を提供するために、mat2を定義しました。

matrix3

mat3

ネイティブの9個のエレメントを持つ型はありません。定義されているmat3は実際は12個のエレメントを持つ型なので、メモリに出し入れする際には注意する必要があります。

matrix

float16, mat4

float16はmatrixと同じサイズですが、より分かりやすくし、いくつかのユーティリティ関数を提供するために、mat4を定義しました。

string

--

OpenCLではprintf()などで文字列リテラルを定義できますが、GPUで実行され、特異な点が多くあるため、他のC言語で想定するようなconst char *と同じではありません。

dict

--

OpenCLでは、辞書はサポートされていません。

int[], float[]

int *, float *

VEXでは、動的に拡大および縮小することができ配列の型がサポートされています。 OpenCLでは、よく似た効果にポインタを使用することができますが、動的に変更することはできません。

バインドとプロトタイプ

VEX Wrangleおよびスニペットは、@構文を使用してアトリビュートを参照する時、アトリビュートを自動的にバインド(紐付け)します。 複雑なスニペットでは、使用する前にバインドを明示的に宣言することを必須にする Enforce Prototypes をオンにすると良いでしょう。

この自動バインドのために、VEXの@構文には、型が暗黙的に指定されない場合のその型を指定するための接頭辞があります。

OpenCLには、そのような自動バインドや型の接頭辞もありません。 代わりに、すべての@バインドは、ノードの Bindings タブのパラメータ、または、スニペット内の#bind命令のいずれかで明示的に指定する必要があります。

#bind命令では、簡潔な行で、Bindingsパラメータと同じ情報を指定することができます。 同じ@バインドが#bindおよびBindingsパラメータの両方で制御されている場合、Bindingsパラメータが使用されます。

#bind命令の基本的な形式は以下の通りです。

//    タイプ 名前   フラグ...
#bind parm foobar read write

このタイプは、バインド先です。 この名前は、このバインドを参照する@ステートメントで使用されるトークンです。 デフォルトではアトリビュート名とマッチしますが、フラグを使用して異なるアトリビュートを選択することもできます(これは、同じ名前の2つのアトリビュートをバインドする場合に必要で、@を明確にするために異なる名前が必要になります)。

フラグは、スペースで区切ったフラグのリストです。

バインド名のデコレーション

名前はデコレーションすることができます。 デコレーションは、名前の前または後に追加することができます。

デコレーション

暗黙的に設定されるフラグ

&

write

?

opt

!

noread

バインドタイプ

以下は、有効なバインドワードのリストです。マルチパラメータ内の対応するバインドで、これらの仕組みについての詳細を確認できます。

バインド

タイプ

parm

整数、浮動小数点、浮動小数点ベクトルスタイルのバインドとマッチします。 floatfloat3intなどのフラグで型を指定します。 スニペットを制御するために使用され、すべてのワークアイテムで一定のパラメータを使用します。

point/prim/primitive/global/detail/vertex

このクラスのジオメトリアトリビュートをバインドします。

ramp

ランプをバインドします。スカラーランプまたはベクトルランプの場合、floatまたはfloat3のフラグで制御します。

volume

ジオメトリ内のボリュームプリミティブをバインドします。

vdb

ジオメトリ内のVDBプリミティブをバインドします。

option

DOP内のDOP Optionをバインドします。

sfield/vfield/mfield/scalarfield/vectorfield/matrixfield

指定されたタイプのDOPフィールドにバインドします。

型フラグ

フラグで指定する1個の型は、floatfloat2といったOpenCLの型をフラグとして使用することができます。 ここには、バインドのベクトルのサイズや精度などを指定します。 float[]は、配列アトリビュートへのバインドを指定するのに使用することができます。 また、float?int?を使用すると、任意のサイズのアトリビュートにバインドすることができます。 tuplesizeメソッドを使用すると、実際のバインドサイズを確認することができます。

アクセスフラグ

アクセスフラグは、ソースアトリビュートがカーネルにバインドされる方法を制御します。

フラグ

意味

read / noread

デフォルトはreadです。

バインドが読み込み可能な場合、そのOpenCLバッファは元の値から初期化されます。 バインドを読み込み可能としてマークしなかった場合には、値を上書きすることが重要になります。 上書きしなかった場合、任意のデータが存在することになります。

write / nowrite

デフォルトはnowriteです。

書き込み可能としてマークされていないバインドは、変更なしとみなされるため、CPUには書き出されません。 無理に行おうとすれば、書き出すことも可能ですが、未定義の挙動が発生します。

opt / noopt

デフォルトはnooptです。

オプションのバインドは、元のジオメトリに存在する必要はありません。 バインドが存在する場合はマクロdefine HAS_nameが定義され、異なるコードパスを持つことができます。 または、defフラグが存在する場合、欠けているバインドが単一のデフォルト値に置き換えられます。

def / nodef

デフォルトはdefです。

オプションのバインドが存在しない場合、代わりに同じ場所でパラメータがバインドされます。 例えば、オプションでPointアトリビュートmassをバインドする場合にmassがなければ、floatパラメータmassがその場でバインドされます。 これにより、コードを変更したり、HAS_mass #ifdefsを使用することなく、コードで@massを使用して値を参照したり、デフォルト値とジオメトリ値を切り替えることができます。

ターゲットフラグ

ターゲットフラグをバインドすることで、バインドのソースに何を使用するのか厳密に制御することができます。 @に使用する名前は常にバインド名であり、バインドされるもののデフォルトになることが多いですが、これによってより詳細な制御が可能になります。

フラグ

意味

val=#

デフォルトは0です。

パラメータ、ボリューム、VDBにデフォルト値を設定します。 ベクトルバインドで単一スカラーが指定されている場合、それが繰り返されるため、ベクトル上val=1はデフォルト値の(1, 1, 1)を使用します。 ベクトル値は中括弧を使用して指定できるため、val={1, 2, 3}は対応するデフォルト値を使用します。

name=SSS

デフォルトはバインド名です。

バインド先のアトリビュート、ボリューム、VDBの名前。

input=#

デフォルトは0です。

SOPでは、バインド先の入力です。1番目の入力のみ書き出すことができます。

geo=SSS

デフォルトはジオメトリです。

DOPでは、現在のシミュレーションオブジェクトのルートを基準とした、バインド先のシミュレーションジオメトリです。

機能フラグ

さらに一般的な機能フラグもあり、それらはほとんどの場合、特定のバインドタイプに固有です。 これらは、バインドで特定のメソッドを有効にするために必要となることもあります。 これらは、OpenCL SOPまたはDOPのいずれかのBindingsマルチパラメータのトグルに相当するため、詳細についてはそちらも参照してください。

フラグ

意味

fieldoffsets / nofieldoffsets

デフォルトはfieldoffsetsです。

DOPのField Bindingsで、このフィールドのオフセットパラメータを有効にします。

forcealign / noforcealign

デフォルトはforcealignです。

すべてのフィールドまたはボリュームが同じ解像度である必要があります。 これにより、コードがシンプルになるうえ、サンプルが揃っていると想定することが可能になります。

最初の書き込み可能なフィールドまたはボリューム(イテレートが行なわれるもの)はforcealignedであるべきではないので、デフォルトはnoforcealignです。

resolution / noresolution

デフォルトはnoresolutionです。

フィールドまたはボリュームの解像度を含めます。 これは境界チェックに必要ですが、その他が揃っている場合は、通常最初のボリュームのみに必要です。

最初の書き込み可能なボリュームでは、デフォルトはresolutionです。

voxelsize / novoxelsize

デフォルトはnovoxelsizeです。

ボリュームのボクセルのサイズを含めます。

xformtoworld / noxformtoworld

デフォルトはnoxformtoworldです。

インデックス空間からジオメトリ(SOP)空間へのトランスフォームを含めます。

xformtovoxel / noxformtovoxel

デフォルトはnoxformtovoxelです。

ジオメトリ(SOP)空間からインデックス空間へのトランスフォームを含めます。

Spareパラメータの作成

VEXでは、コード内に直接ch("myparm")を含めることで、関数をインストルメント化(Spareパラメータから関数の値を編集できるように)することができます。 その後、パラメータ生成ボタンを押すと、VEXコードが実行時に読み込むmyparmSpareパラメータが作成されます。

GPU上で実行されるOpenCLでは、すべてを明示的にバインドする必要があるため、ch("myparm")と同等の機能を持つことができません。 そのため、似たことをする場合には、#bind parm myparm floatなどの#bind命令を追加することになります。

バインドされた値を実際に制御するには、Bindingsタブでバインドとしてmyparmを手動で追加します。 それをFloatタイプに設定することで、Float値をそこでアニメーションさせて、OpenCLに渡される値を制御することができます。

作業を楽にするために、OpenCLノードのパラメータ生成ボタンがすべての#bind命令を解析して、Bindingsページでそれらに呼応したエントリを作成しますが、マルチパラメータ値を駆動するコードの隣にSpareパラメータも作成します。 結果のSpareパラメータはOpenCLコードによって直接読み込まれないことに注意してください。 マルチパラメータの値を駆動し、その後そのマルチパラメータは実行前にカーネルにバインドされます。

トポロジーとグループバインド名

VEXにはバインド処理に影響を与えるいくつかのマジック名(便利機能を備えた予約済みの名前)があります。 例えば、@group_foofooグループにバインドし、@opinput1_Pは2番目の入力のPにバインドします。

OpenCLにもよく似たオプションがあります。 group:fooアトリビュートへのバインドでは、fooグループにバインドします。 バインドはInteger型である必要があります。

topo:接頭辞を使用して、いくつかのトポロジーアトリビュートもサポートされています。 これらは、適切なクラスおよび型にバインドする必要があります。これらはすべて読み込み専用です。可能な限り、これらは呼応するVEX関数にほぼ一致します。

トポロジー名

クラス

意味

topo:primpoints

prim

int[]

プリミティブ番号によってインデックス化され、そのプリミティブに属するすべてのポイントインデックスを格納します。

topo:primvertices

prim

int[]

プリミティブ番号によってインデックス化され、そのプリミティブに属するすべての頂点インデックスを格納します。

topo:primvertexcount

prim

int

プリミティブ番号によってインデックス化され、そのプリミティブ上の頂点の数を格納します。

topo:pointprims

point

int[]

ポイント番号によってインデックス化され、そのポイントを参照するプリミティブインデックスを格納します。

topo:pointvertices

point

int[]

ポイント番号によってインデックス化され、そのポイントを参照する頂点インデックスを格納します。

topo:pointneighbours

point

int[]

ポイント番号によってインデックス化され、neighbours VEX関数のように、周囲の隣接ポイントのポイントインデックスを格納します。

topo:vertexpoint

vertex

int

頂点番号によってインデックス化され、頂点の参照先のポイントインデックスを格納します。

topo:vertexprim

vertex

int

頂点番号によってインデックス化され、頂点を所有しているプリミティブインデックスを格納します。

topo:vertexprimindex

vertex

int

頂点番号によってインデックス化され、この頂点が属するプリミティブ内の場所を格納します。

グローバルバインド

VEXには、様々なデフォルトのバインドがあり、多くのWrangleに用意されています。 同様にOpenCLにもいくつかありますが、VEXはコード内にこれらが出現するとJust-In-Timeでバインドすることが多いのに対し、OpenCLではほとんどの場合、バインドを有効にするためには、ノード上で明示的に機能フラグを設定する必要があります。

バインド

有効性

意味

@ix, @iy, @iz

int

ボリューム、VDB、フィールドのいずれかに対して実行します。

現行の処理済みのボクセルの整数インデックス。

@elemnum

int

ボリューム、アトリビュート、VDBいずれかに対して実行します。フィールドが整列している場合、フィールドに対して実行します。

現行の処理済みのエレメントを表す整数インデックス。 VDBの場合、これはトポロジーによって異なることに注意してください。

@P

float3

フィールドに対して実行します。

処理済みのボクセルの現行のDOP/モデル空間。

@Time

float

ノードで指定されたTimeを含めます。

現行時間(秒)。ノードが時間依存になります。

@TimeInc

float

ノードで指定されたTimestepを含みます。

現行のタイムステップ(通常はSOPで1/$FPS)ですが、DOPの場合は、現行のシミュレーションステップサイズです。

@SimFrame

int

ノードで指定されたSimulation Frameを含めます。

現行のシミュレーションフレーム、$SF

@-Bindingメソッド

VEXでは、@バインドは実際の値です。 @Pは現行位置のベクトルであり、型はベクトルです。現行位置への書き出しは、単に@Pに割り当てるだけです。 現行ポイント以外のポイントの位置を使用する場合は、pointおよびsetpointattrib関数を使用します。

VEXでは、@バインドは実質的にローカル変数です。その変数への書き出しまたは読み込みは他の変数と同じです。 OpenCLでは、@バインドは計算量の増加につながるため、広範囲で使用する場合、通常はそれをローカル変数にコピーすると役立つことが多いです。

OpenCLでは、すべてのデータが明示的にバインドされている必要があるため、pointsetpointattrib関数で行なわれるような任意のアトリビュートへの書き出しや読み込みは不可能です。 しかしこれは、ポジションアトリビュートが@Pにバインドされている場合、すべての位置データが読み込み可能であることも意味します。 全データへのアクセスは、様々なメソッドを@バインドに追加することで実現します。 例えば、@P.getAt(53)はインデックス53のポイントを読み込みます。これらのメソッドには範囲外アクセスチェックが含まれ、pointおよびsetpointattribと同様に、プログラミングエラーによってカーネルが破滅的に失敗しないようになっています。

VEXのsetpointattrib関数は、スレッドセーフになるように設計され、常に同じように作用します。それに呼応するOpenCLのsetAtにはそのような保証はありません。2つのワークアイテムを同じポイントに書き出さないよう注意することが重要です。

利用可能なメソッドは、バインドのタイプ、バインド先のデータの型、データが読み込み可能なのか書き込み可能なのか、データが現行ワークアイテムに揃っているかどうかによって異なります。 特に、最後に加えておきたいのは、ポジションアトリビュートまたはマッチするアトリビュートに対して実行される場合のみ、@PをRaw値とみなせることです。 そうでない場合、どのポイントにするのか指定する必要があります。

パラメータバインドメソッド

parmバインドは、それ自体が単なる値です。したがって、@nameは実際の値を参照するため、メソッドはありません。

ランプバインドメソッド

OpenCLのランプは、常にfloatの1D配列で、ランプ値を取得するために補間されます。 ランプのサイズはバインド内で指定します。 ただし、用意されているメソッドのおかげで、データレイアウトの微妙な差異を気にする必要はありません。

メソッド

意味

@name.data

実際のランプデータのfloat配列。

@name.len

ランプのサイズ。

@name(float), @name.getAt(float)

要求した0..1の位置でランプの値を調べ、サンプル間を補間します。

フィールドバインドメソッド

ベクトルおよびマトリックスフィールドには、様々なコンポーネントを参照するための_xおよび_xx接尾辞があります。 そのため、バインド名がnameの場合、ベクトルフィールドには、ベクトルフィールドのxフィールドのyストライド向けに@name.stride_x_yがあります。

実行されるフィールドと解像度およびトランスフォームが一致する場合、フィールドが揃えられます。

メソッド

意味

@name.data

フィールドのそのままのfloatデータ。

@name.stride_x/y/z/offset

データのX、Y、Z軸のステップのストライド。オフセットは、データから0,0,0ボクセルへのオフセットです。

@name.x/y/zres

フィールドのX、Y、Zの解像度。

@name, @name.get

現行の処理済みの値。揃っている場合、有効です。

@name.getAt(x,y,z)

インデックス位置X、Y、Zにおけるボクセル。

@name.set(val)

現行の処理済みのボクセルをvalに設定します。揃っている場合、有効です。

@name.setAt(x, y, z, val)

(x, y, z)におけるボクセルをvalに設定します。

@name.sample(xyz)

float3 xyzでのインデックス空間のフィールドを評価します。

アトリビュートバインドメソッド

アトリビュートがジオメトリアトリビュート(ポイント、プリミティブ、頂点、ディテールなど)にバインドされます。 これらにはgroup:接頭辞を持つグループと、topo:接頭辞を持つトポロジーが含まれます。

アトリビュートのインデックスがマッチするのは、カーネルがアトリビュートに対して実行され、そのアトリビュートが実行を適用されているアトリビュートと同じクラスおよびサイズである場合です。

メソッド

意味

@name.data

そのままのアトリビュートデータ。すべてのエレメントデータが、穴やページのない単一の配列に平坦化されます。配列アトリビュートでは、配列データは連続的に格納されます。

通常、これに直接アクセスすることはなく、境界チェックメソッドを提供する他のメソッドが使用されます。

@name.len

アトリビュートの長さ。これは、アトリビュートが持つポイント、プリミティブ、頂点の数です。

@name, @name.get

現行インデックスのアトリビュート値。

読み込み可能な場合、有効です。配列でない場合、有効です。マッチするインデックスの場合、有効です。

@name(idx), @name.getAt(idx)

特定のインデックスでアトリビュートを取得します。

読み込み可能な場合、有効です。配列でない場合、有効です。

@name.set(val)

現行インデックスでアトリビュート値を設定します。

書き込み可能な場合、有効です。配列でない場合、有効です。マッチするインデックスの場合、有効です。

@name.setAt(idx, val)

指定したインデックスにおけるアトリビュートを値に設定します。

書き込み可能な場合、有効です。配列でない場合、有効です。

@name.tuplesize

アトリビュートの各エレメントのサイズ。float型のアトリビュートのサイズは1、vector型のアトリビュートのサイズは3です。

@name.tuple

現行の処理済みのアイテムの配列へのポインタ。OpenCLのネイティブの型にマッピングしないアトリビュートサイズを使用する場合、これが便利ですエレメントにアクセスするには、[]を使用(@name.tuple[2]のように)して現行アトリビュートの3番目の部分を取得します。この場合、アトリビュートのタプルサイズを超えて読み取らないように、境界チェックを行なう必要があります。

マッチするインデックスの場合、有効です。

@name.tupleAt(idx)

インデックスidxにおける特定のアイテムの配列へのポインタ。tupleと同様、これを使用する際には注意が必要です。

@name.bound

アトリビュートがバインドされるかどうか。オプションのアトリビュートでは、バインドされる場合は1、されない場合は0にします。オプションでないアトリビュートは常にバインドされます。存在しない場合はカーネルが実行されないためです。

@name.comp(compidx)

配列アトリビュートでは、現行インデックスのデータの特定のコンポーネントを抽出します。

配列の場合、有効です。マッチするインデックスの場合、有効です。

@name.entries

現行インデックスの配列の長さ。

配列の場合、有効です。マッチするインデックスの場合、有効です。

@name.compAt(idx, compidx)

配列アトリビュートでは、特定のインデックスのデータの特定のコンポーネントを抽出します。idxは、アトリビュートのエレメント番号です(ポイント番号やプリミティブ番号など)。compidxは、そのエレメントの配列内のアクセスする場所です。

配列の場合、有効です。

@name.entriesAt(idx)

インデックスidxの配列の長さ。

配列の場合、有効です。

ボリュームバインドメソッド

ジオメトリ上のボリュームをバインドすることができます。

カーネルがボリュームに対して実行され、バインドされたボリュームがその解像度およびトランスフォームとマッチする場合、ボリュームのインデックスがマッチします。

ボリュームには、メソッドによって読み込み可能なバインド追加データを追加するためのフラグが多数あります。 特にボリュームが実行を適用されるボリュームと揃っていない場合、一部のメソッドでは追加のフラグが必要になることがあります。

メソッド

意味

@name.data

ボリュームのそのままのデータ。stride_値を使用してインデックス化されたボリュームの値の平坦な配列です。境界チェックがあるため、直接dataを使用するのではなく、getAtまたは類似のメソッドを使用することをお勧めします。

@name.stride_x/y/z/offset

X、Y、Z軸のステップサイズと、data配列の開始から0,0,0ボクセルのオフセット。

@name.x/y/zres

ボリュームの解像度。パディングされることが多いため、インデックスにストライドを使用する必要があることに注意してください。

@name.voxelsize_x/y/z

各軸に沿った0,0,0ボクセルのサイズ。

voxelsizeフラグが必要です。

@name.xformtoworld

ボクセルインデックスをモデル/SOP空間にマッピングするfpreal16

xformtoworldフラグが必要です。

@name.xformtovoxel

モデル/SOP空間をインデックス空間にマッピングするfpreal16

xformtovoxelフラグが必要です。

@name, @name.get

現行ボクセルインデックスにおけるボリュームの値。

読み込み可能な場合、有効です。マッチするインデックスの場合、有効です。

@name.valid(x,y,z)

ボクセルのx、y、zがボリュームの境界内にある場合はTrueです。

@name.getAt(x,y,z)

ボクセル(x, y, z)での値を返します。ボリュームの範囲外の場合、インデックスはボリュームの範囲にクランプされます。

読み込み可能な場合、有効です。

@name.set(val)

現行の処理済みのボクセルをvalに設定します。

書き込み可能な場合、有効です。マッチするインデックスの場合、有効です。

@name.setAt(x, y, z, val)

(x, y, z)におけるボクセルをvalに設定します。これは境界チェックされ、範囲外の場合はそのままです。

書き込み可能な場合、有効です。

@name.sample(xyz)

インデックス空間fpreal3の位置xyzにおいて、ボリュームにトリリニア補間を行ないます。有効な範囲内にクランプします。

読み込み可能な場合、有効です。

@name.sample2d(xy)

インデックス空間fpreal2の位置xyzにおいて、ボリューム対してバイリニア補間を行ないます。有効な範囲内にクランプします。

読み込み可能な場合、有効です。

VDBバインドメソッド

ジオメトリ上のVDBをバインドすることができます。 OpenCLの世界のVDBは、NanoVDBレイアウトにトランスフォームされています。 CNanoVDBおよび類似のヘッダを使用してそれらに直接アクセスできますが、用意されているメソッドはアクセスパターンを簡略化するため、こちらの方が望ましいです。

VDBに対して実行され、VDBにマッチするトランスフォームがある場合、VDBのインデックスはマッチします。

VDBへの書き込みは可能ですが、書き込みを行なってもトポロジーは変更できません。 OpenCLの外部で既にアクティブ化されているボクセルにのみ書き込むことができます。

Note

VDBの定数領域は定数タイルに圧縮される場合が多いので、書き込むことができません。 これらの領域は明示的に密度を決める必要があります。 これは、ボクセル毎に乱数を追加するVolume Wrangleで行ないます。

VDBには、メソッドによって読み込み可能なバインド追加データを追加するためのフラグが多数あります。 特にVDBが実行を適用されるVDBと揃っていない場合、一部のメソッドでは追加のフラグが必要になることがあります。

VDBは通常、floatまたはfloat3タグを使用して、タイプに明示的にバインドされます。タグが指定されていない場合、anyとしてバインドされ、利用可能なメソッドが少なくなります。

メソッド

意味

@name.data

そのままのNanoVDBデータ。CNanoVDBヘッダを使用してこれを直接検査できますが、CNanoVDBは非常に詳細なため、メソッドを使用する方法が望ましいです。

@name.voxelsize_x/y/z

X、Y、Z軸でのVDB(0,0,0)ボクセルのサイズ。

voxelsizeフラグが必要です。

@name.xformtoworld

インデックス空間からモデル/SOP空間へのfpreal16トランスフォーム。

xformtoworldフラグが必要です。

@name.xformtovoxel

モデル/SOP空間からインデックス空間へのfpreal16トランスフォーム。

xformtovoxelフラグが必要です。

@name, @name.get

現行の処理済みのインデックスでの値を返します。

読み込み可能な場合、有効です。マッチするインデックスの場合、有効です。

@name.pos

現行の処理済みインデックスのモデル/SOP位置を返します。

マッチするインデックスの場合、有効です。

@name.active

現行の処理済みVDBインデックスがこのVDB上でアクティブかどうか。

vectorまたはfloatバインドが必要です。マッチするインデックスが必要です。

@name.activeAt(x, y, z)

指定されたX、Y、Zインデックス座標がアクティブかどうか。

vectorまたはfloatバインドの場合、有効です。

@name.valid(x, y, z)

指定されたX、Y、Zインデックス座標がアクティブかどうか。

vectorまたはfloatバインドの場合、有効です。マッチするインデックスの場合、有効です。

@name.getAt(x, y, z)

インデックス(x, y, z)での値を返します。VDBは、非アクティブな領域に背景値を所有しているため、任意のインデックス上で実行することができます。

vectorまたはfloatバインドの場合、有効です。読み込み可能な場合、有効です。

@name.set(val)

現行の処理済みのボクセルを値valに設定します。

vectorまたはfloatバインドの場合、有効です。書き込み可能な場合、有効です。マッチするインデックスの場合、有効です。

@name.setAt(x, y, z, val)

インデックス(x, y, z)におけるボクセルを値valに設定します。インデックスがVDBトポロジーにない場合、書き込みは何もしません。

vectorまたはfloatバインドの場合、有効です。書き込み可能な場合、有効です。

@name.sample(xyz)

指定されたインデックス空間の位置において、VDBにトリリニア補間を行ないます。

vectorまたはfloatバインドの場合、有効です。読み込み可能な場合、有効です。

@name.worldSample(xyz)

指定されたモデル/SOP空間の位置において、VDBにトリリニア補間を行ないます。

vectorまたはfloatバインドの場合、有効です。読み込み可能な場合、有効です。

@name.worldGradient(xyz)

指定されたモデル/SOP空間におけるVDBの勾配を計算し、モデル/SOP空間で勾配を返します。

floatバインドの場合、有効です。読み込み可能な場合、有効です。

オプションバインドメソッド

シミュレーションデータのオプションは、DOP OpenCLノードによってバインドすることができます。

バインド先のデータは、geoフラグによって制御します。どのオプションかは、nameフラグによって制御します。

メソッド

意味

@name, @name.get

指定したデータのオプションの値。

VEX

言語

次のステップ

リファレンス