はじめに
追記:{
Attribute Promote SOPから配列を作る
}
🔰 Houdini初心者向けに、VEXの基礎を解説する記事を書いていきます。
本記事では、VEXを学ぶうえで最初に理解しておきたい 配列(Array) と Run Over の基本について解説します。
配列はプログラミング全般で頻繁に使われる重要な概念であり、Run OverはHoudiniならではの実行方式です。この2つを理解することで、VEXのコードが格段に読みやすくなり、実践的な処理も書けるようになります。
初心者の方でも理解しやすいように、できるだけシンプルなサンプルコードを交えながら説明していきます。
配列とは?
配列(Array)とは、同じ種類のデータをまとめて管理するためのデータ型です。
例えば、果物の名前を複数扱いたい場合、次のように1つずつ変数を作ることもできます。
string fruit1 = "apple";
string fruit2 = "banana";
string fruit3 = "orange";
string fruit4 = "grape";
しかし、データが増えるたびに変数を増やす必要があり、管理が大変になります。
そこで配列を使うと、複数のデータを1つの変数にまとめることができます。
string fruits[] = {"apple", "banana", "orange", "grape"};
または、array() を使って書くこともできます。
string fruits[] = array("apple", "banana", "orange", "grape");
どちらも同じ意味なので、好きな書き方を使って構いません。
配列の中身を確認する
配列全体を表示してみます。
string fruits[] = {"apple", "banana", "orange", "grape"};
printf("%s\n", fruits);
出力
{"apple", "banana", "orange", "grape"}
要素を追加する
append() を使うと、配列の末尾に新しい要素を追加できます。
string fruits[] = {"apple", "banana", "orange", "grape"};
append(fruits, "strawberry");
printf("%s\n", fruits);
出力
{"apple", "banana", "orange", "grape", "strawberry"}
配列の要素を取り出す
配列の要素には、インデックスと呼ばれる番号でアクセスします。
配列の番号は 0から始まる ことに注意してください。
インデックス
0 1 2 3
┌───────┬────────┬────────┬───────┐
│ apple │ banana │ orange │ grape │
└───────┴────────┴────────┴───────┘
例えば、最初の要素を取得するには次のように書きます。
string fruits[] = {"apple", "banana", "orange", "grape"};
printf("%s\n", fruits[0]);
出力
apple
同様に、
printf("%s\n", fruits[1]);
なら
banana
が表示されます。
配列は 「同じ種類のデータを1つにまとめて管理するための箱」 と考えると理解しやすいでしょう。
この配列を for 文と組み合わせることで、データ数が増えても同じコードで効率よく処理できるようになります。
vector と vector4 の違い
VEXには、複数の数値を1つの変数として扱うための型が他にもあります。
vector
vector は 3つの float を持つデータ型です。
vector pos = set(1, 2, 3);
各要素には x、y、z でアクセスできます。
printf("%g\n", pos.x); // 1
printf("%g\n", pos.y); // 2
printf("%g\n", pos.z); // 3
vector4
vector4 は 4つの float を持つデータ型です。
vector4 value = set(0, 1, 2, 3);
4つ目の要素は w と呼ばれます。
printf("%g\n", value.x); // 0
printf("%g\n", value.y); // 1
printf("%g\n", value.z); // 2
printf("%g\n", value.w); // 3
また、配列のようにインデックスでもアクセスできます。
printf("%g\n", value[0]); // 0
printf("%g\n", value[1]); // 1
printf("%g\n", value[2]); // 2
printf("%g\n", value[3]); // 3
配列との違い
一見するとvectorやvector4 は配列のように見えますが、別のデータ型です。
配列
float values[] = {0, 1, 2, 3};
- 要素数を増減できる
-
append()が使える - 同じ型なら何個でも格納できる
vector4
vector4 value = set(0, 1, 2, 3);
- 要素数は常に4つ
-
append()は使えない - 数学的な4次元ベクトルとして扱われる
つまり、
- 配列は「データをたくさん保存するための入れ物」
- vector / vector4は「座標や方向などを表すための固定長データ」
という役割の違いがあります。
配列とRun Over
複数のTestGeometryのノード名のtestgeometry_以下の文字列
をDetailクラスに配列として格納してみます

packしてMerge
ここでは分かりやすいように、Test GeometryをPackして一つのコンポーネントに
まとめてからMergeします。
その際Tranfer Attributesにshop_materialpathと入れてください
このpathからノード名を取り出します。
Mergeすると3つのprimだけになります。
分かりやすいようにNullをおいてOUT_Packsとしておきます。
豆知識
ノードを選択した状態で
ctrlキーを押しながらクリックで形や色を変更すると、
同じタイプのノードが一括で変更されます。
また、新規で同じタイプのノードを作った時にも、
その変更を受けた状態で作ることができます。

配列と Run Over

VEXで配列を扱うときは、Run Overの設定がとても重要です。
特に、複数のPrimitiveから値を集めて、1つの配列にまとめたい場合は、Run Over: Detail を使うのが基本です。
一番良い例:Run Over Detailで1回だけ実行する
// Run Over: Detail
string name_array[];
for (int i = 0; i < nprimitives(0); i++)
{
string path = prim(0, "shop_materialpath", i);
string slash[] = split(path, "/");
string under[] = split(slash[2], "_");
append(name_array, under[1]);
}
// detail配列アトリビュートとして保存
setdetailattrib(0, "name_array", name_array, "set");
foreach (string name; name_array)
{
printf("%s\n", name);
}
Run Over: Detail は、Wrangleを1回だけ実行します。
そのため、全Primitiveを for 文で回して、取得した名前を1つの配列にまとめる処理に向いています。
配列にはなるが効率が悪い例:Primitiveで全Primitiveを回す
// Run Over: Primitives
string name_array[];
for (int i = 0; i < nprimitives(0); i++)
{
string path = prim(0, "shop_materialpath", i);
string slash[] = split(path, "/");
string under[] = split(slash[2], "_");
append(name_array, under[1]);
}
setdetailattrib(0, "name_array", name_array, "set");
これは一見動きますが、効率が悪いです。
Run Over: Primitives は、Primitiveの数だけWrangleを実行します。
例えばPrimitiveが100個ある場合、
Primitive Wrangleで100回実行
その中で for 文が100回実行
となるため、合計で
100 × 100 = 10,000回
処理されます。
つまり、同じ配列を何度も作って、detail属性に何度も上書きしている状態です。
意図通りの配列にならない例:Primitiveごとに配列が作られる
// Run Over: Primitives
string material_path = prim(0, "shop_materialpath", @primnum);
string slash[] = split(material_path, "/");
string underscore[] = split(slash[2], "_");
string name_array[];
append(name_array, underscore[1]);
printf("%s\n", name_array[0]);
setdetailattrib(0, "name_array", name_array, "set");
このコードでは、各Primitiveごとに name_array が作られます。
つまり、Primitiveが3つある場合は、内部的には次のようなイメージになります。
Primitive 0 → name_array = {"Body"}
Primitive 1 → name_array = {"Head"}
Primitive 2 → name_array = {"Arm"}
1つの配列に
{"Body", "Head", "Arm"}
と入るわけではありません。
Run Over: Primitives では、各Primitiveが個別に処理されるため、ローカル変数として作った配列はPrimitiveごとに別物になります。
まとめ
複数のPrimitiveから値を集めて、1つの配列にしたい場合は、
Run Over: Detail
を使うのが基本です。
一方で、Primitiveごとに個別の処理をしたい場合は、
Run Over: Primitives
を使います。
つまり、
全体で1つの配列を作る → Detail
各Primitiveごとに処理する → Primitives
と考えると分かりやすいです。
追記
Attribute Promote SOPから配列を作る
Array of Allのオプションを使うと配列が作れるのを教えて頂きました。
知らんかったー

shop_materialpathの配列が作られるので
ノード名だけを取り出してアトリビュートを上書きすると以下のようになります。
//run over detail
string name_array_renamed[];
string name_array[] = detail(0, "name_array");
foreach (string name; name_array){
string slash[] = split(name, "/");
string underscore[] = split(slash[2], "_");
append(name_array_renamed, underscore[1]);
}
setdetailattrib(0, "name_array", name_array_renamed);



