HoudiniのVEXにおけるaddprimとaddpointの挙動について


先日HoudiniのVEX内におけるaddprimaddpoitによって生成されるプリミティブやポイントの番号についての挙動に盛大に引っかかったので備忘録を兼ねた記事になります。
拙いVEXですがご容赦ください。

実際に作ったもの

普通のgridから45度傾いた斜めのグリッドを生成しようとしていました
一番の上流になるため、copy系のノードを使わず、VEXで早く処理できないかと思い、基本的にはVEXで実装しました

結果とノードは以下のような感じです

2つのAttribute Wrangleaddpointaddprimを使って、各プリミティブと外縁部ではないポイントそれぞれでプリミティブを生成してmergeしてfuseで繋げてる感じです

addprimとaddpointで引っかかった挙動

基本的に今まではadd系のVEXを使う際はRun overをDetail(once only)にしていたので問題にはならなかったのですが、Run overをpointやprimitiveにし、同一Wrangle内で、その生成されたpointやprimitiveに対して操作を行いたい場合、各番号はどうなるのか、というところが問題となりました。
(後に使うaddvertexではターゲットとなるprimitiveやpointを番号で指定する必要があるため)

結論から書くと、Run overがprimitiveやpointであった場合、addprimやaddpointで生成される各要素の番号は、現在の@ptnum@primnumのアトリビュートの数値の如何によらず、生成された順に、
@numprim + n あるいは@numpt + n となります。(n>=0)

実際のノードでの実装

from_prim

VEX(from_prim)
int maxiteration = primvertexcount(0,@primnum);

int ptoffset = @numpt;
int primoffset = @numprim;

vector posarray[];
int ptnumarray[];

for (int i=0; i<maxiteration; i++){
int linearvtx = vertexindex(0, @primnum, i);
int pt = vertexpoint(0, linearvtx);
ptnumarray[i]=pt;
vector pos = point(0,"P",pt);
posarray[i] = pos;
}

for (int j=0; j<maxiteration; j++){
int num = (j + 1)%maxiteration;
vector vtxpos1 = posarray[j];
vector vtxpos2 = posarray[num];
vector middlepos = (vtxpos1 + vtxpos2)/2;
addpoint(0,middlepos);
}

addprim(0,"poly");

for (int k=0; k<maxiteration; k++){
addvertex(0, primoffset ,ptoffset + k );
}

removeprim(0,@primnum,1);

プリミティブを構成する各ポイントの隣接する2頂点の中点にaddpointでポイントを生成し、addprimで生成したプリミティブにaddvertexで放り込む感じです
(汎用性を持たせるなら各エッジを起点に処理をしないといけないと思う)

最小で実行すると以下のような感じ

from_point

VEX(from_point)
int primoffset = @numprim;
int ptoffset = @numpt;

if (neighbourcount(0,@ptnum)==4) {

    int neighbourptnumarray[] = neighbours(0,@ptnum);
    int num2 = neighbourptnumarray[2];
    int num3 = neighbourptnumarray[3];

    neighbourptnumarray[2] = num3;
    neighbourptnumarray[3] = num2;

    neighbourptnumarray = reverse(neighbourptnumarray);

    addprim(0,"poly");

    int maxiteration = len(neighbourptnumarray);    

    for(int i=0;  i<maxiteration; i++){
        vector pos1 = point(0,"P",neighbourptnumarray[i]);
        vector pos = (@P + pos1)/2;
        addpoint(0,pos);
        addvertex(0,primoffset,ptoffset + i);
        }
}

removepoint(0,@ptnum,1);

4つのポイントと隣接しているポイントに対し、それらと自身との各中点にポイントを生成してプリミティブを作成するというものです。
(途中明らかに汎用性が欠落する部分があるので要修正かなと思っています。)

最小ではこう

各Wrangleでのaddvertexでは、ターゲットとするprim_numpoint_numがそれぞれ@numprim + n あるいは@numpt + n となっています
また、今回は自分自身の可読性を優先したため、primoffsetやらptoffsetと変数定義をしていますが、直接@numprim@numptを使っても問題ありませんでした。

余談

途中で作成し、実際にaddprimやaddpointの挙動の解決に至った際のものも置いておきます
各プリミティブの中心にポイントをインサートして、各エッジとつながる三角ポリゴンを生成するというものです

VEX(insert_point)
int maxiteration = primvertexcount(0,@primnum);

int ptoffset = @numpt;
int primoffset = @numprim;



vector posarray[];

int ptnumarray[];

for (int i=0; i<maxiteration; i++){

int linearvtx = vertexindex(0, @primnum, i);
int pt = vertexpoint(0, linearvtx);

ptnumarray[i]=pt;

vector pos = point(0,"P",pt);
posarray[i] = pos;
}

vector pointpos = avg(posarray);

addpoint(0,pointpos);



for (int j=0; j<maxiteration; j++){

int firstpt = ptoffset ;
int secondptindex = j;
int thirdptindex = (j+1)%4;

addprim(0,"poly");
addvertex(0, primoffset + j ,firstpt );
addvertex(0, primoffset + j , ptnumarray[secondptindex]);
addvertex(0, primoffset + j , ptnumarray[thirdptindex]);

}

removeprim(0,@primnum,0);

サンプルファイル

一応サンプルファイルを置いておきます
https://drive.google.com/file/d/1r-GZVoat2Aur3kKrHbPeySNYYuXc8jwV/view?usp=sharing

間違いや質問のほか、もっと簡単に書いてやったぞ!みたいなのでもお気軽に!

2021/10/24追記

intで変数宣言してからaddpointなりaddprimを行うことで、生成される要素の番号を戻り値として格納できるそうです。
というか公式のVEXドキュメントに普通に書いてありましたね、、、

int hoge = addpoint(0,pos);