MatrixのアレをHoudiniで作ってみた

##完成すると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/a259fad9-3ad3-a7b9-6302-a3a838510c37.png)


新作の映画と、UEのゲームとか最近色々と話題のマトリックスですが今回は、、、
こんなもの作りたいと思います。
この記事は、Houdini始めた人でもわかるように頑張って書いたつもりです…。
VEXを使用しておりますが、そこまで難しいことはしていないので大丈夫だと思います。

↓↓↓↓↓プロジェクトファイルはこちらから↓↓↓↓↓
https://drive.google.com/drive/folders/1c0X_H09WiVre0WYHrq3AqURnfvMX-GW8?usp=sharing

##作り方

簡単にイメージすると。。。
色んな種類の文字を各ポイントへバラバラに貼り付け、アルファを使って表現する感じです。

今回のポイントは以下の通りです

- コード元となる文字のセットアップ
- グラデみたいなバラバラに流れるコード（アルファ）
- 時々コードの内容が変化するアニメーション（ランダム）

大まかにこんな感じでしょうか

##コード元のセットアップ編
###エクセルからHoudiniへ
文字がないと始まらないのでHoudini内に持ってきましょう。
今回はエクセルを使って、インポートする方法でやろうと思います。

マトリックスのコード文字の内容ですが。。。調べてみると”お寿司のレシピ”を元に作られているみたいですね
ではお寿司のネタ一覧をエクセルに書き込んでHoudini内へ持ってきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/ea76bbf4-e041-7611-4b1e-e6446df785e7.png)
こんな感じですかね？ グーグルさんから"寿司ネタ一覧"を調べてそのまま貼り付けた感じです。
必ず保存方法は"CSV"で書き出しましょう

CSVのインポートは "Table Import"ノードで行うことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/ac71ba65-7dcc-6e5c-193b-2dc4ea26e3cb.png)
それぞれCSVの内容をインポートするための設定を１列目、２列目、、、と決めていきます。
必ず Attribute Typeを" String "文字として読み込みましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/c03125b0-1f77-a807-def3-39b984d62d7d.png)
こんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/ef016e51-2630-e803-cbe1-53c8c74ea252.png)
###文字毎に"variant"を割り当てる
ここからVEXで一文字づつ切り分けて"variant"を割り当てていきます。
文字の切り分けからです、人によってやり方はそれぞれですが。

VEXの大まかな処理の流れ

- sushi_array 配列に全て格納
- sushi_word  "Join"関数ですべての配列を一文字にする
- sushi_array_word 一文字づつ"push"関数で配列に割り当てる
- word フレーム毎にsushi_array_wordの[X（フレーム）]番目の配列から取り出す

補足
今回の文字は2byteの文字を使用しているのでpushの関数を使うときは2づつで行うと正しい結果が得られます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/f5189f16-d057-d7d9-bd14-7771e03b9338.png)

```
////////まず一つの配列に全部格納する//////////////////////////
string sushi_array[];

for(int i = 0;i<npoints(0);i++){
string sushi_1 = point(0,"sushi_1",i);
string sushi_2 = point(0,"sushi_2",i);
string sushi_3 = point(0,"sushi_3",i);
push(sushi_array,sushi_1);
push(sushi_array,sushi_2);
push(sushi_array,sushi_3);
}
s[]@sushi_array =sushi_array;

////////join関数で一文字にする//////////////////////////
string sushi_word = join(sushi_array,"");
s@sushi_word = sushi_word;

////////一文字づつ配列で割り当てる//////////////////////////
int count = len(sushi_word);
i@count = count;

string sushi_array_word[];

for(int z = 0;z<count;z++){
push(sushi_array_word,sushi_word[z]);
z +=2;
}
s[]@sushi_array_word = sushi_array_word;

////////配列から[X]目の文字をピックアップする//////////////////////////
s@word = sushi_array_word[@Frame];
i@array_count = len(sushi_array_word);
```

fontノードを使いフレーム毎に読み込まれる文字を表示します。
`details("../font_out","word")`　でビュワー上に表示されます
「../font_out」ノード選択　「word」detailのattribute名
ここで表示されない場合、2byteの文字が表示できないフォントが選ばれている場合があるので注意です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/886af7ac-297a-58fe-f4ab-3bd50d49cf75.png)
各フレームで文字が読み込まれるので、"variant"を各フレームに割り当てます。

```
i@variant = @Frame-1;
```

これで文字の出力とvarinat出力が各フレームで出力することが出来ました。
この二つを補間する為に、Trail SOPを使います。
どこのフレームまで補間するのかは、先ほどのVEXで調べておきます
配列の数＝フレーム数なので "i@array_count = len(sushi_array_word);" で計算しておきます。
この値をTrailLengthへリンクさせcsvの内容が変わっても自動で反映してくれます detail("../font_out","array_count",0)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/04015b3b-8eb5-c714-f01e-662c724e8589.png)
timeshiftノードを使い 末端フレーム"1044"で固定しておきます。

これで文字とvariantの設定は終わりました。


##グラデみたいなバラバラに流れるコード編
完成形です
これに先ほどの文字を割り当てる感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/a9fd4f45-c7dd-6432-7f3a-8e8762b72b22.png)

元がないのでまず面から
グリッドを作成して　→　addsopで [Delete Geometry But Keep the Points]にチェックを入れポイントのみにします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/0e187623-52e9-1bc5-4ed6-3ad491f313aa.png)
手法は色々ありますが、縦に一本のラインを繋げるためにバウンディングボックスカラーを使い一本の線を作ります。
@Cd.x部分だけの数値を使って明るさが同じ数値を"id"化させることでaddで一本のラインを作ることが出来ます。
@Cd.xだけにしたもので同じ明るさ同士が線になっているのがわかります
![goke2aaa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/ea9e29b3-86a8-ed75-5bc6-fa2e31168f7b.gif)
idを@Cd.xで割り当てます

```
string x = itoa(@Cd.x*10000);

s@id = x;
```

add sop で同じidを一本の線でつなぎます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/c6b2be0a-cf2b-fcec-fe85-7e9a776898af.png)

これでグラデーションを作る準備が整いました。
大まかな処理の流れです

- 各線がいろんな場所にあって作業がやりづらいので、原点へ持っていきます
- 線のポイント数と現在のフレームで割った余りの数字を使ってグラデ部分のアルファを計算します
- 各ライン"id"それぞれ固有なので、idを使ってアニメーションの時間をズラします


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/77395c94-37ac-2e9d-55a2-dbe66081254b.png)
###原点移動
原点へ持っていくので移動する前に今の位置情報を"rest"として保存しておきます。

```
v@rest = @P;

```
便利なこのノードで原点へ移動してくれます、VEXでgettbox関数を使った処理しなくても、簡単なのでおすすめです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/0883ef0c-b7e8-c53a-6785-6120b9147f5a.png)
色々ポチポチ調整して原点へ持っていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/0a2b31d2-a635-87bc-1c0c-5cd0fb380fb0.png)
###アニメーション
完成形


waveの数値を調整すると波長の調整が出来ます。
![goke2aaaa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/7717c82c-9b9d-f229-1c11-344f7b2abbb3.gif)
scaleの数値を調整すると、尾っぽの引く余韻の調整が出来ます。
![goke2aaaaa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/6e77dada-8ffa-5c03-bd24-98869466ac5b.gif)

Wrangleの内容です。

```
float num = npoints(0);
float pt = @ptnum;

float alpha = pow( ((float(num-pt)-@Frame))/chi("wave")%0.99999999 , chf("scale"));


if(alpha<0.01){
f@Alpha =0;
}else{
f@Alpha = alpha;
}
```

VEXの内容ですが、アルファ部分の処理の内容をバラシて解説します。

```
f@a = (float(num-pt)-@Frame);
f@aa = (float(num-pt)-@Frame)/chi("wave");
f@aaa = (float(num-pt)-@Frame)/chi("wave")%0.99999999;
```

- a は総ポイント数と現在のポイントを引いた数を更に、フレームで引いたもの（こいつが動かす元）。
- aa chi("wave")で代入される数が大きくなるほど、"a"の数が小さくなり数字が全体的に平坦になる。（波長の仕組み）
- aaa 剰余算(%0.99)を行う事で、1（0.99）の余りを算出する。
- 最後にpow(乗算)を全体にかけることで数字に緩急をつけることが出来ます（尾の長さ調整）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/fe0842d8-164d-2f41-c2b4-fe37b259675b.png)
aaaの補足
- 1で割り切れない数字[例:-0.85]としたの数字の余りなので1(割る数字)-0.85=0.15として結果が返ってきます

###原点から元の位置へ戻す

wrangleで"rest"として保存した数値を@Pへ反映させ元の位置へ戻す

```
@P = v@rest;

```

###アニメーションの時間をズラす

Timeshiftで時間をズラす為に、pointにある固有のidをDetailへ移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/ec6caed2-c62e-4b3d-1e47-6710f7662403.png)
このまま数字をTimeshiftへリンクさせたいところですが、数字が文字として認識され呼び出すことが出来ません。
なので文字数字を数字として変換させています。

```
i@timeshift = atoi(s@id);
```

これでTimeshiftノードへ値を送る準備が出来ました。
解説するとそのままのずれたフレームを入れても数値の誤差が少なく全体的にランダムな感じにならないので数字を大きくしてバラバラにしている感じです。
timeshift sop のFrameへこんな感じにエクスプレッションを入力します。

```
rand(detail("../timeshift_num","timeshift",0))*10000+$F
```

あとはForloopノードで全ての線に繰り返し計算させる感じになります。


##時々コードの内容が変化するアニメーション編
完成形です
![goke2aaaaaaa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/a57f7981-9382-7bff-0288-9671a9b08a0c.gif)

これも簡単にランダム要素を加えれれるノードがあり、Adjust Integerノードというものを使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/105cc439-2648-125a-08af-5303a8c0ee24.png)
作りたいアトリビュート名をAttribute Nameで"variant"と記入し
ランダムの生成方法と、ランダムの使用する数字の範囲を指定することでお手軽に作ってくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/d47268b7-7dec-d495-b6e3-265fdf14af84.png)
これですべてのポイントにVariant0～1044のランダムな数値が入力されました。
次に一部のポイント番号だけ変化させる方法ですが、グループの機能を使って行っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/6ae5358c-ba40-6a0d-fdbd-e8a70574c330.png)
wrangleでグループを作ります。
簡単に説明するとrand関数ランダム数値で各ポイントで割り当てた物をifを使いグループを生成しています。
scaleの値を0.5にすると総ポイントの半分が該当し、グループに割り当てる割合を簡単に調整できます。

```
float ran = rand(@ptnum+@Frame);

if(ran<chf("scale")){

i@group_pt1 = 1;

}
```
作ったグループ情報をGroupへ入力しグループ"1"に該当する物だけVariantのランダム数字を再度かけることが出来ます。
オペレーション方法を加算にしたりすると、ランダム数字から更に加算され1044以上の数字になるので注意。
ランダムの数字を上書き方式にしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/054e8756-69a2-1f02-14af-2ac315f39700.png)

文字反転方法も同じようなやり方なので割愛します。

##最後の工程編（グラデへ文字をコピー）
wrangleでupとNのアトリビュートを作成し、upの軸とN方向を数値で設定して。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/4047e857-eb69-074b-2657-9e7bc70733dd.png)
copy to points で各ポイントへ文字をコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/e3036d3e-27c7-3653-8887-7168566c00f7.png)

これで完成です、お疲れさまでした！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2389986/56cebe1e-6697-c91e-ed37-baaf9d41c3dd.png)