Posted at

拡散していくボックス


はじめに

フジヤマタカシです。まだまだ空きがあるようなので更に投稿させていただきます。

今回はSolverを使ってボックスが広がって何かの形を作るをやってみたいと思います。

1作目のトランスフォーマーに出てきたオールスパークの逆みたいな感じです。

*オールスパークはサイバトロンがメガネに示された地図から必死に探そうとしていたのにセクター7によってとっくに発見されていた例の立方体です。

ak2c3-ybyu1.gif

こういう感じのです。


拡散

先ずはじめにシンプルにボックスが隣のひとつをボックにしての拡散行く設定です。最初は分かりやすく平面でやってみましょう。ポイント間の間隔は1ユニットです。

Screenshot from 2018-12-16 13-47-37.png

最初にアトリビュート@boxedを準備します。ボックス化しているものは1。そうでなければ0です。1ポイントのみ予め1にしておきます。

if(@ptnum == 0)i@boxed = 1;

次はSolver内の設定です。

手法としては完成形のポイントを予め用意しておいてSolver内でアトリビュートを書き換えていきます。

このような広がる系の手法だとポイントクラウドで隣接ポイントを判定して自身のアトリビュートを書き換えるのが一般的だと思います。その中でランダムに書き換えたり書き換えなかったり。

今回はボックス化しているポイントがボックス化されてない隣接ポイントの中から1つをボックス化するようにします。この方が拡散の連続性が見れて気持ちの良い展開のようになるからです。

自身のアトリビュートを書き換えるなら、普通に@Cd = set(1,0,0);ですが、各ポイントが自身のパラメータを使い別のポイントのアトリビュートを更新するにはsetattrib(0,”Cd”, nextpt, set(1,0,0))を使います。

Untitled-1.png

この手法はEntagmaさんのSpace Colonizationのチュートリアルをヒントにしています。やってることは全然違うんですがsetattrib使用のコンセプトはこれを参考にしています。

内部ネットワークは今の所PointWrangleひとつで大丈夫です。

int closept[] = pcfind(0, "\@boxed==0", "P", @P, 1, 4);

int selNex = floor( rand(@ptnum * 20 + @Frame) * len(closept) );
int nextP = closept[selNex];

setpointattrib(0, "boxed", nextP, 1);

int closept[] = pcfind(1,"P",@P, 1, 4);は平面なので周囲最大4つのボックス化されてないポイントを取得しcloseptに配列格納します。

int selNex = floor( rand(@ptnum * 20 + @Frame) * len(closept) );は配列の中からひとつを選択するために、ランダムに配列内のインデックスを選びます。

int nextP = closept[selNex];でランダムに選んだポイントのナンバーを取得します。

そしてsetpointattrib(0, "boxed", nextP, 1);で選んだポイントのナンバーをboxedアトリビュートを1にします。

Solver後はポイントにboxをコピーしますがその前に@boxed==0のポイントを削除しておきましょう。

色は適当に

if(i@boxed==0)removepoint(0,@ptnum);

@Cd = set(rand(@ptnum),0,0);

y6uwv-iob2x.gif


拡散制限

広がり方が均一すぎて微妙ですね。現在@boxedが1であれば毎フレーム周囲のポイントに影響させようとしますがこれに制限をかけます。一度他のポイントをボックス化させると以降のフレームではその操作をしない事にします。その為に@topというアトリビュートを用意しておきます。

そしてこのようにi@top == 1のポイントだけ処理させるようにします。

ボックス化させた隣接ポイントのtopは1になり自身のtopは0になります。

int closept[] = pcfind(0,"\@boxed==0","P",@P, 1, 4);

///possibility
int active = 0;
if(len(closept)!=0){
if(i@top == 1){
active = 1;
}
}

i@top = 0;

if (active){
///select Next
int selNex = floor( rand(@ptnum * 20 + @Frame) * len(closept) );
int nextP = closept[selNex];

setpointattrib(0, "top", nextP, 1);
setpointattrib(0, "boxed", nextP, 1);
}

ldp7d-e01z9.gif

袋小路に迷い込み処理が止まってしまいました。。。その為にtopが0の場合でも一定確立で隣をbox化させるに変更します。

int closept[] = pcfind(0,"\@boxed==0","P",@P, 1, 4);

///possibility
int active = 0;
if(len(closept)!=0){
if(i@top == 1){
active = 1;
}else{
if(rand(@ptnum+999 + @Frame) < 0.02 )active = 1;
}
}

i@top = 0;

if (active){
///select Next
int selNex = floor( rand(@ptnum * 11 + @Frame) * len(closept) );
int nextP = closept[selNex];

setpointattrib(0, "top", nextP, 1);
setpointattrib(0, "boxed", nextP, 1);
}

q5ruy-84oep.gif

とりあえずこれで良しとします。


拡散時に移動。

次にボックスが隣に移るときに数フレーム移動させたいと思います。その為に3つアトリビュートを追加します。

i@moving ボックスが移動してる間のアトリビュート

f@moveVal ボックスがどのくらい移動してるかのアトリビュート。0スタートでこれが1になるとboxedが1になりmovingは0になる。

v@moveFrom movingの値を1にしてくれた隣のポイントの位置。

更新用Wrangleのコードはほぼ同じですが、その際にアップデートboxedの代りにmovingを1にします。それと同時にsetpointattrib(0, "moveFrom", nextP, @P);で位置情報をv@moveFromに渡します。

int closept[] = pcfind(0,"\@boxed==0","P",@P, 1, 4);

///possibility
int active = 0;

if(len(closept)!=0){
if(i@top == 1){
active = 1;
}else{
if(rand(@ptnum+999 + @Frame) < 0.02 )active = 1;
}
}

i@top = 0;

if (active){
///select Next
int selNex = floor( rand(@ptnum * 11 + @Frame) * len(closept) );
int nextP = closept[selNex];

setpointattrib(0, "top", nextP, 1);
setpointattrib(0, "moving", nextP, 1);
setpointattrib(0, "moveFrom", nextP, @P);
}

次にもうひとつWrangleを足します。動いてるものに対しての処理なので

Groupは@moving==1です。

@Cd = set(0,1,0);

float moveStep = 5;

@moveVal += 1.0/moveStep;
if(@moveVal >= 1){
i@boxed = 1;
@Cd = set(1,0,0);
i@moving=0;
}

@moveVal += 1.0/moveStep;はmoveStepの値の数値分のステップで移動が完了しbox = 1になります。

Solverの外での設定は@moveValの値でv@moveFrom と@Pをlerpさせて移動させます。

if(i@boxed==0 && i@moving == 0)removepoint(0,@ptnum);

@P = lerp(v@moveFrom ,@P ,f@moveVal);
@scale = lerp(set(0.75,0.75,0.75),1,f@moveVal);

@Cd = set(rand(@ptnum),0,0);

if(@top==1)@Cd = 1;

4sdtk-juwxp.gif


立体への適用

立体へのそのまま適用可能です。pcfindのサーチ数を6に変えるだけです。

int closept[] = pcfind(0,"\@boxed==0","P",@P, ch("distance"), 6);

これを作るときのサーチDistanceとポイント間の間隔およびボックスのサイズは揃えておきましょう。

w35mg-xxiky.gif

作成したファイルはこちらになります。

https://drive.google.com/file/d/1H-UoAgYvWIdAS30UvMWSY4zGUuQTIxZh/view?usp=sharing

では今回は以上になります。ここまで読んでいただきありがとうございます!