Wire SolverでなくFor-Eachを利用したワイヤー表現

この記事はHoudini Advent Calendar 2016の四日目の記事です。

この記事では
・Stroke SOP
・Ray SOP
・For-Each SOP
・PolyFrame SOP
について記述しています。

＊バグが含まれていたので追記しました。新しいhipファイルを一番下に置いています。
![forwire2.PNG](https://qiita-image-store.s3.amazonaws.com/0/151589/52a8f493-470f-e3e2-10c0-f6b82bc9ed30.png)

#DOPで作成する場合
DOPでワイヤーを表現する場合、WireSolverを利用すれば紐の動作を行うことができます。

WireSolverの話は…と書こうと思ったらすでに書かれていますね。
外部リンク：http://nomoreretake.net/2016/09/17/houdinicapture-deform/

確かにDOPを利用すれば正しい動作は期待できます。しかし、solverの欠点は1フレーム目から計算を行わなければ結果が見れないというところにあります。
個人的には何か動作したら、すぐに結果が見たいというもの。じゃあSOPで完結すればいいじゃないか！

#SOPでどうすべきか
strokeとrayを利用します！
結果はこんな感じになります。
![tube1.png](https://qiita-image-store.s3.amazonaws.com/0/151589/d1839719-c49a-55a8-a439-711831a8c338.png)

まずは、ワイヤーの元となるpolylineを作りましょう。

#Stroke SOPでワイヤー形状を
strokeでは筆圧など様々な情報が格納されており、いろんな用途に使えそうです。
(ただ今回は筆圧でワイヤーの太さを変える動作はさせないので、いらないattributeは削除しておきます。)
事前にstrokeでpolylineを作成します。traceSOPでもlineを取得できるのですが、strokeで嬉しいのは、１ストローク1primitiveであるということです。つまりforeachで1ストロークごとに処理を行うことができます！
![stroke1.png](https://qiita-image-store.s3.amazonaws.com/0/151589/eda1c258-19ff-d686-c9ed-58d07f6eb981.png)

#Ray SOP
rayはpointの法線方向にある物体に向かって瞬時に張り付きます。(ProjectRayがデフォルトで@Nのため)
この機能を利用して疑似的にワイヤーがからまるような表現を行います。

▼raySOP
![ray.png](https://qiita-image-store.s3.amazonaws.com/0/151589/c1e4a89a-daf1-1602-97d6-74bc24cb94d7.png)

法線方向についてはProjectRayで相手のオブジェクトに対して法線を方向手動で入れてもいいですし、Minimum Distanceを利用して最短距離を求めるのもいいと思います。
sphereなどについては、下のWrangle(Run Over:Points)のように書いて重心をターゲットにするのもいいかもしれません。

```
vector min, max;
getbbox(1,min, max);
vector target = (min+max)/2; 
@N=normalize(target-@P);
```
・getbbox(min, max);でなくgetbbox(1,min, max);と書くことで2番目のinputのバウンディングボックスを取得することができます。


ひとまず法線の方向に何らかのオブジェクトを配置します。(でなければpointは微動だにしません)


#ForEachでループ処理
forの話は…と書こうと思ったらすでに書かれていますね。
外部リンク：http://nomoreretake.net/2016/01/08/houdini_for-loopsop/
##ForEachの全体
Houdini15からforノードができてbegin-endのblock内で処理ができるようになりました。
これで毎回subnet内に入る必要がなくなります。(ただネットワークがでかくなる…)
![target.png](https://qiita-image-store.s3.amazonaws.com/0/151589/78e4ca5b-181e-1491-dc4c-bcbca1a4cce1.png)

##ダブルBlock-begin
今回工夫している点はpieceとfeedbackを複合させ、次のループの下準備を前のループで行っている点です。
２つのeachはそれぞれの役割を持ちます。左側のpieceは名前の通りワイヤーを一本ずつ運んできます。右のfeedbackにはrayに衝突させるためのオブジェクトが入ります。途中PolyWireを入れています。これは次のループの衝突用オブジェクトです。このループで出力されるのは、変形したpolywireだけでなく衝突用オブジェクトも含まれます。衝突用オブジェクトは、ガイド用のため最終的に出力したいワイヤーの太さの2倍にしておきます。そうすることで干渉が起きにくくなります。
![guide.png](https://qiita-image-store.s3.amazonaws.com/0/151589/2d3e5730-e37e-fd60-88b0-0eaa926f68f6.png)


###なぜこんな工夫が必要なのか？
通常のfeedback処理は、処理を行うオブジェクトのみループします。しかし今回のように衝突用オブジェクト(sphere)をfeedback前にmergeしたら、foreachの結果にも残ってしまうので、最終的に衝突用オブジェクトが11回重複してしまいます。しかし、rayを当てるオブジェクトの更新は行いたい。ということで、一時的に衝突用のオブジェクトは消さずfor脱出後に削除を行います。衝突用オブジェクトを削除するために先にgroupを指定しておき、最後に削除します。
![foreach.png](https://qiita-image-store.s3.amazonaws.com/0/151589/5858e3e7-3c5b-45dc-25c1-ab05e0033c53.png)

▼衝突用オブジェクトのガイド削除後
![out.png](https://qiita-image-store.s3.amazonaws.com/0/151589/807a5bfa-7949-0036-29b6-5d02f3ff4f0d.png)

##ダブルeach(old)
旧foreachサブネットにおいても同様の事が可能です。
デフォルトで入っているeachに加えてeachをもう一つ新規で作成し、feedbackにチェックをいれ、自分自身をFor pathに入れます。これで同様の動作が可能です。
![double.png](https://qiita-image-store.s3.amazonaws.com/0/151589/6ad8bb00-1b0d-b5e8-7aec-8b0777ce9c26.png)

##PolyFrameのtangentとpeakを利用した延長線
PolyFrameの接線の話は…と書こうと思ったらすでに書かれていますね。
外部リンク：http://nomoreretake.net/2015/09/07/houdini_curve_tangent/

Houdiniではcarveを利用してpolylineを簡単に削ることはできますが、伸ばす場合には少々工夫が必要です。
![peak.png](https://qiita-image-store.s3.amazonaws.com/0/151589/b9db3c5d-c8cd-fa35-f8d5-d023a094d1c4.png)

###1：PolyFrameのtangentをNにセットする

▼まずはすべてのポイントを接線の方向に向かせます。
![tan.png](https://qiita-image-store.s3.amazonaws.com/0/151589/b5709855-3a57-63c6-742d-5ec0b18b53ff.png)


###2：Wrangleで法線を整える
各primitiveの0と最後のポイントのみ法線を残し、ほかの法線は一時的に{0,0,0}をセットします。
Wrangle(Run Over:Points)

```
if(@ptnum==0){@N=-@N;}
else if(@ptnum!=npoints(0)-1){@N=set(0,0,0);}
```
###3：primitive分foreachで回す
▼foeachからの出力
![normal.png](https://qiita-image-store.s3.amazonaws.com/0/151589/3303b701-94e9-6a4a-53e8-14558ba3a320.png)


###4：peakで伸ばす
peakは各pointからの法線方向に向かって自身のpoint座標を移動させます。
先ほど先端以外は法線を除去しておいたので、先端以外が動くことはありません。
![normal2.png](https://qiita-image-store.s3.amazonaws.com/0/151589/586b40a0-f3a9-8ea7-1895-d0a3871f4022.png)


###5：法線を元に戻す
このままではこのあとのsweepに支障が出るので元に戻します。


##Sweepでpolylineからワイヤーに
polylineのprimitive attributeにCdがある場合はpoint attributeにattribute promoteを行います。primitive attributeはSweepが行われる際に破棄されます。(ただ、後ほどmaterialでCdを利用する場合はprimitive attributeである必要があるので、Sweep後に戻します。)
![tube2.png](https://qiita-image-store.s3.amazonaws.com/0/151589/ac4ebc35-9dfd-e257-d9bd-d1b645915450.png)

#まとめ
foreachはHoudiniの中でもかなり利用頻度の高いSOPのため、できるだけ早い段階で習得をオススメします。
▼全体のネットワーク
![11.png](https://qiita-image-store.s3.amazonaws.com/0/151589/36e19195-2876-385c-13bc-cbb820a76fbd.png)


以上
＊nomoreretake様、勝手にいっぱいリンク張って申し訳ありません。

hipファイル（old）
https://drive.google.com/open?id=0B8-SILG4S2_fcWU2T1ZGVkVPdlk

##追記　2018/05/18

なんか重いなと思ってたら、致命的なバグが含まれていました。
feedbackの最初にgroup化を忘れており、最終結果にガイドで利用した過去のワイヤーが含まれておりました。
大変申し訳ありません。正しくはこちら　feedback　beginブロックの次にgroupを追加しています。

![正しくはこうでした.PNG](https://qiita-image-store.s3.amazonaws.com/0/151589/2a2e7609-1067-d41a-4569-cc6003396569.png)


feedbackは全て削除する必要があったので、sphereのグループに含む必要がありました。
軽くなったので、大量にワイヤーを配置できます。



色とスケールのコントロールがしやすいように手を加えています。
Edit parameter Interfaceでfolderを利用することでパラメータの増減ができるようにすると、拡張性があって便利です。
![maincontrol.PNG](https://qiita-image-store.s3.amazonaws.com/0/151589/722d8a1a-4b6d-917f-3bcc-b9aa6fb3f9d8.png)
Folder TypeをMultiple Parm(list)にすることで+　-できるパラメータ群を作れます。NameとLabel内の#には増やした分の固有のID（1から割り振られる）が適用されます。
![mult.PNG](https://qiita-image-store.s3.amazonaws.com/0/151589/a6851596-dc9e-2400-f7a5-fd6b9e0c5d18.png)
増減するパラメータは、この変数で対応します。
一例ですが、floatとvectorで指定するサンプルを入れています。

```C:set_wire_scale_color
int wireTypeLen=chi("../Main_control/wire_scale_variety_folder");
int wireType= floor(rand(@primnum)*(wireTypeLen))+1;
f@wirescale=chf("../Main_control/wire_scale_variety"+itoa(wireType));
float wcR=chf("../Main_control/wire_color_variety"+itoa(wireType)+"r");
float wcG=chf("../Main_control/wire_color_variety"+itoa(wireType)+"g");
float wcB=chf("../Main_control/wire_color_variety"+itoa(wireType)+"b");
v@wirecolor=set(wcR,wcG,wcB);
```

新しいhipncファイルです。
hipファイル（new）
https://drive.google.com/open?id=1UM06A0Df2mfv_lILu17A61syafP-kHF8

いろんな形状を入れたりrayのパラメータを変化させていろんなワイヤー表現が可能です
![test1.PNG](https://qiita-image-store.s3.amazonaws.com/0/151589/9c58f0cf-326b-616c-6707-17573356ab30.png)