この記事はHoudini Advent Calendar 2016の21日目の記事です。
#ポイントの隣を求めるには?
真っ先に考えられるのは、neigbourを利用する手法です。
もしくは、接続されているかを考えなければnearpointを利用してもいいかもしれません。
http://majou.jp/archives/623/
http://nomoreretake.net/2015/12/17/houdinin_pointcloud_n/
#プリミティブの隣を求めるには?
隣のプリミティブが存在するかどうかを確認するにはどうすればいいでしょうか?
ポイントの場合はエッジで接続されたポイントの先を見るだけでよかったのですが、プリミティブの場合は隣り合うプリミティブを求めてくれる関数がありません。(もしかしたら存在するかもしれませんが)
今回は、groupSOP、ハーフエッジ、バーテックスの3つの方法で隣のプリミティブの状態を求めていきましょう。
##プリミティブの隣が存在しない(UnsharedEdges)を見つける
###groupSOPを利用
一番簡単な方法はgroupSOPを利用してEdgeグループからポイントやプリミティブに振り分ける方法です。この機能が慣れていない頃に気づきにくい理由は、Numberタブのチェックを外し忘れて全体の選択となってしまい、edgeのグループに気が回らないからではないかと思います。
▼チェックを外し
###ハーフエッジを利用する
さっきgroupSOPで出来たんだから、それでいいでしょ。と思うかもしれません。しかしgroupSOPでは、どのエッジがUnsharedEdgeだったのか?まではわかりません。例えば上下左右にプリミティブが結合された状態で、1番目のエッジがどのような状態なのか?は、wrangleを利用してhedge系の関数を利用し始めなければなりません。
int isBorderEdge(int pt0, pt1)
{
int hedge = pointhedge(0, pt0, pt1);
if (hedge == -1 )
{
hedge = pointhedge(0, pt1, pt0);
if (hedge == -1 ) return -1;
}
return hedge_equivcount(0, hedge) == 1;
}
int vtx[]=primvertices(0,i@primnum);
int ptv[];
int gridtype=0;
for(int j=0;j<primvertexcount(0, @primnum);j++){
ptv[j]=vertexpoint(0,vtx[j]);
}
for(int j=0;j<len(ptv);j++){
int pt0 = ptv[j];
int pt1 = ptv[(j+1)%len(ptv)];
int isborder = isBorderEdge(pt0, pt1);
if(isborder){
i@gridtype = isborder;
}
}
何をやっているかというと、プリミティブ毎に全バーテックスを取得し、バーテックスに含まれるポイントを取得した後、isBorderEdgeの関数に2点のポイントpt0, pt1を投げます。
注目すべきは”面が隣接しているときハーフエッジは必ず等価である”という点です。
図で説明すると、隣接していないときハーフエッジは0→1の方向性しか持ちませんが、隣接している場合0→1の方向性と1→0の方向性を持つという事です。
つまり、0→1、1→0のハーフエッジの有無を見て、返り値がどちらも-1でなければ
この2点間は隣接しているという事です。
*hedge_equivcountは、ハーフエッジhedgeが無効な場合は-1を返し、有効な場合は、同じ両端点を持つハーフエッジの数を返します。
#バーテックスでプリミティブの隣に応じた種類分け
この方法は、もともと1年前に書いた
http://majou.jp/archives/701/
で[後編]として紹介する用だったのですが、この際なので紹介します。
ポイントとバーテックスの関係は、先ほどもチラッとハーフエッジで触れました、
さらに詳しくは、こまつさんのブログにもあります。(houdini-mayaユーザのためのsop入門前夜)
http://blog.taikomatsu.com/2011/09/23/houdini-maya%E3%83%A6%E3%83%BC%E3%82%B6%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AEsop%E5%85%A5%E9%96%80%E5%89%8D%E5%A4%9C/
つまり何が言いたいかというと、ポイントが共有しているバーテックスの数を数えたら、隣り合うプリミティブの位置と存在がわかる。ということです。
ただ、四角形ポリゴンしかこのプログラムは対応していませんのであしからず。
if(primvertexcount(0, @primnum)==4){
int vtx[]=primvertices(0,@primnum);
int ptv[];
int ptvc[];
for(int j=0;j<4;j++){
ptv[j]=vertexpoint(0,vtx[j]);
int piv[]=pointvertices(0,ptv[j]);
ptvc[j]=len(piv);
}
if((ptvc[0]==1)&&(ptvc[1]!=1)&&(ptvc[2]!=1)&&(ptvc[3]!=1)){
i@my_type=0;//corner0
}else if((ptvc[0]!=1)&&(ptvc[1]==1)&&(ptvc[2]!=1)&&(ptvc[3]!=1)){
i@my_type=1;//corner1
}else if((ptvc[0]!=1)&&(ptvc[1]!=1)&&(ptvc[2]==1)&&(ptvc[3]!=1)){
i@my_type=2;//corner2
}else if((ptvc[0]!=1)&&(ptvc[1]!=1)&&(ptvc[2]!=1)&&(ptvc[3]==1)){
i@my_type=3;//corner3
}else if((ptvc[2]==3)&&(ptvc[1]!=2)&&(ptvc[3]!=2)){
i@my_type=4;//corner4
}else if((ptvc[3]==3)&&(ptvc[2]!=2)&&(ptvc[0]!=2)){
i@my_type=5;//corner5
}else if((ptvc[0]==3)&&(ptvc[3]!=2)&&(ptvc[1]!=2)){
i@my_type=6;//corner6
}else if((ptvc[1]==3)&&(ptvc[0]!=2)&&(ptvc[2]!=2)){
i@my_type=7;//corner7
}else if((ptvc[0]==4)&&(ptvc[1]==4)&&(ptvc[2]==4)&&(ptvc[3]==4)){
i@my_type=8;//inside
}else if(((ptvc[0]==2)&&(ptvc[1]==2))||((ptvc[0]==2)&&(ptvc[1]==3))||((ptvc[0]==3)&&(ptvc[1]==2))){
i@my_type=9;//outside0
}else if(((ptvc[1]==2)&&(ptvc[2]==2))||((ptvc[1]==2)&&(ptvc[2]==3))||((ptvc[1]==3)&&(ptvc[2]==2))){
i@my_type=10;//outside1
}else if(((ptvc[2]==2)&&(ptvc[3]==2))||((ptvc[2]==2)&&(ptvc[3]==3))||((ptvc[2]==3)&&(ptvc[3]==2))){
i@my_type=11;//outside2
}else if(((ptvc[3]==2)&&(ptvc[0]==2))||((ptvc[3]==2)&&(ptvc[0]==3))||((ptvc[3]==3)&&(ptvc[0]==2))){
i@my_type=12;//outside3
}
}else{
i@my_type=13;//other
}
これは…背景作成に役に立ちそうな匂いがプンプンしていますね。
今回のhipファイルはこちら。
https://drive.google.com/open?id=0B8-SILG4S2_feWtYUWxwajVLTU0
以上!