プロシージャルにメッシュ変形

#はじめに
この記事は[Houdini Apprentice Calender 2019](https://qiita.com/advent-calendar/2019/happrentice)の14日目の記事です。

この記事では、メッシュをベースにちょっとした変形を加えられるプロシージャルモデリング的ななにかをチュートリアル形式で紹介します。
完全初心者でもなるべくわかるように書いていこうと思います。
Houdiniのおもしろさが伝わっていただけるとうれしいです！

***
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/418ef304-1849-25d9-ed26-339622d7d1f7.png)
↑今回作るやつ
***

#まずは単純な形状でやってみる (基本編)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/e8b8bd8b-c49c-92b8-994e-e8656848f169.png)
作成するメインの部分を単純な形状で試しに作ってみます。(上図)
作りつつ、Houdiniの基本的なオペレーションも書いておきます。
***
####Geometryノードを作る
まずは、ノードエディターで、**[Tab]キーもしくは[右クリック]**で **TAB Menu** を出します。
そこから**Geometry**ノードを呼び出しましょう。何事もまずはここから。
ちなみに、右クリック→[G]キー→[Enter]キー×3でGeometryノードを作りつつ素早くノードの中に入れます。([Enter]キー3回分の内訳は、1.ノード確定、2.ノード配置、3.ノード内に入る、です。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/043f645c-36ea-8742-58f7-75eb8673df7d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/5d91c68e-ea6b-8fd4-1a09-279ebc1fb850.png)
というわけで、作成されたGeometryノードの中に入ります。
Houdiniでは、ノードが選択された状態で**[Enter]キーもしくは[左ダブルクリック]**でその**ノード内に入る**ことができます。
ちなみに、全てのノード内に入れるわけではないです。
***
####Gridノードを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/807a3a3d-e645-e2ed-9b91-1d8c171d617c.png)
Geometryノードと同じように**TAB Menu**から**[Grid](https://www.sidefx.com/ja/docs/houdini/nodes/sop/grid.html)**を作成します。
このノードは平面を作成してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/622353a9-9072-52a3-0f56-5128b15df157.png)
作成されたgrid1のパラメーターを少し変えます。
**Connectivity**を**Rows and Columns**
**Rows**を**2**
**Columns**を**2**
に変更しました。
これで四角のラインができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/422cb74e-8bbd-a0ba-7edc-cfec18bba9f6.png)
***
####Copy and Transformノードを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/1500234c-27b4-3b35-c9a7-ac847235e84a.png)
[**Copy and Transform**](https://www.sidefx.com/ja/docs/houdini/nodes/sop/copyxform.html)を作成します。
作成した時点では警告(△の!)が出てきますが、入力がないと結果が出せないために出ているだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/915f121d-eb74-5cc6-b933-34f69fc17fd2.png)
早速ノードを繋いでみます。
繋ぐついでに**Copy and Transform**の**ディスプレイフラグ**を**ON**にしておきましょう。(ノードの右端が青い状態)
ディスプレイフラグは**ノードの右端を[左クリック]か、リング(正式名称なんですかね？)右上の目玉アイコンを[左クリック]でON**にできます。
ディスプレイフラグがONになっているものがビューポートに表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/f09a05bf-981a-dc75-8c26-50ae8e407fa1.png)
Copy and Transformのパラメーターを変更します。
**Total Number**を**10**
**RotateのY**を**20**
**Uniform Scale**を**0.75**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/9cf3dc68-1efa-c5f4-09a8-3c846b74a1bc.png)
ここまでで上図のような結果に。
Y軸に**20**度回転しつつ全体のスケールが**0.75**倍されて複製、という処理が**10**回行われています。
***
####pointwrangle(Attribute Wrangle)ノードを作る
あともうひと手間加えます。ノード的にはこれを含めあと二つ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/9e040a2f-9fe8-3c9c-4fb9-1559a3c75ca3.png)
pointwrangle([Attribute Wrangle](https://www.sidefx.com/ja/docs/houdini/nodes/sop/attribwrangle.html))を作成し、**grid1とcopy1の間に繋ぎます。**
pointwrangleはVEXを使用してアトリビュートの設定を行うことができるノードです。
**VEXと聞いてちょっと嫌になる方がいるかも知れませんが安心してください！１行しか書きませんので！**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/877fe581-d8d1-d9ab-bd6a-853b014e723c.png)
**VEXpression**に
`@id = @ptnum;`
と入力してください。以上です。
これは、**ポイント番号(ptnum)**を **id** というアトリビュートに格納する処理を意味しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/f022f71e-2223-f556-609c-c6c4ed3e86e0.png)
実際にアトリビュートが設定されたかどうかは **Geometry Spreadsheet** タブで確認することができます。

####Addノードを作る
基本編、最後のノードです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/3404f7a7-ff7e-f7e7-b1a0-12342cac5b6c.png)
**[Add](https://www.sidefx.com/ja/docs/houdini/nodes/sop/add.html)**を作成し最後に繋ぎます。
Addはポイントを繋いで線を作成することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/a12f3cb3-0956-2e44-fdfa-ac8cfdf64e32.png)
パラメーターを変更します。
Polygons
┗ By Group
　┗ **Add** を **By Attribute** に
　┗ **Attribute Name** を **id** に
パラメーター内にフォルダが複数あるので、該当の箇所を表示し、設定します。
***
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/33f502fc-01cb-a93e-ff2b-ea82cd1e6e99.png)
これで四角の角を繋ぐことができました！
これにて基本編は終了です。一段落。
***
#####角を繋ぐ処理の解説
Addノードで角を線で繋ぐ処理をしましたが、それについて少し解説します。
まず、設定したパラメーターについてですが、Add(パラメーター名の方)は**どういったルールで繋ぐか**を選択できます。
今回は**By Attributeを選択**したので、**Attributeに基づいて線が繋がれる処理**となります。具体的には**アトリビュートの値が同じもの同士で繋いでくれます。**
では、**どのアトリビュートを参照しますか？**というのが**Attribute Nameで設定**されています。
今回は **id** を選択したので、idというアトリビュートの中で同じ値を持ったものを探し繋いでくれます。
つまり**線を繋ぐには同じ値を持ったアトリビュートを作成する必要**があります。
今回使用しているアトリビュート **id** は **pointwrangle で作成**しました。
pointwrangleに書いた処理により、**4つの点にそれぞれ、0、1、2、3**が設定されています。
この状態で、次のノード **Copy and transform によって複製されたものは同じ id アトリビュートを持った状態になります。**
まぁ複製なので当然なのかもしれませんが。
これにより同じ値をもったアトリビュートができ、Addで繋ぐことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/cebb10bc-3cdb-2d9a-b7e4-57cd44880f18.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/fe9670da-5551-e9b8-3636-974a6c6a029d.png)
**Copy and transform を選択し、Geometry Spreadsheetで確認**してみます。
Geometry Spreadsheet 内の**アトリビュート名をクリックするとそのアトリビュートでソート**できます。
**ポイント番号0,4,8,12,16,20,24,28,32,36 は id の値が 0** なのが確認できます。
***
#ブタさんでやってみる (応用編)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/471439d0-2b9e-7b3c-c122-6b7f9d1942ec.png)
この画像のワイヤーの部分を作っていきます。（画像は見やすくするために黒い豚さんを覆うようになっていますが、ワイヤー部分だけ解説します）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/c8246fda-ccc7-5933-b369-01eddf73e754.png)
ノードはこれだけ。**全部で12個**です。
上から順に軽く解説していきます。
***
#### Test Geometry: Pig Headノード
[Test Geometry: Pig Head](https://www.sidefx.com/ja/docs/houdini/nodes/sop/testgeometry_pighead.html)は豚の頭を召喚できます。
Houdinist達によくおもちゃにされてます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/22123750-b8e0-cfdb-2859-38ae8e80d747.png)
***
####For-Each Primitive (Block Begin/Block End)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/ede92167-8077-835b-1d41-bbba82377c94.png)
TAB Menuから **For-Each Primitive** を作成しています。
いくつかあるFor-Eachなんちゃらノードですが、全て**[Block Begin](https://www.sidefx.com/ja/docs/houdini/nodes/sop/block_begin.html)**と**[Block End](https://www.sidefx.com/ja/docs/houdini/nodes/sop/block_end.html)**ノードがセットで作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/a01b600c-3b0f-2f65-f7cc-bf599df91f77.png)
こんな感じに。
各種For-Eachなんちゃらの違いは、**ノードのパラメータ設定**です。あと、ものによってはBlock Begin / Block Endの他に追加でノードが作成されるものもあります。
このノードはプログラムで言うところのfor文です。
Block BeginとBlock Endの間にあるノードが条件に従って複数回実行されます。
今回は**For-Each Primitiveで呼び出しているので、primitiveの数だけ実行されます。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/6ce0ed23-5e12-7ee5-41f9-ce99874c6778.png)
**Gather : 2889** となっているので今回は**2889回**繰り返し処理されることになりますね。ブタさんは2889ポリゴンだったということですね。
**本来は特に変更するパラメーターがないのですが、今回は説明をしやすくするために一つだけパラメーターを変更します。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/dca3fad9-6d12-f8b5-70b7-69e4dd7846db.png)
**Single Pass** を **ON** にして、 **213** を設定します。
Single Pass は膨大に繰り返している中で、ある特定回の時の処理だけ取り出せるというものです。
今回は213回目の処理だけを表示して見ていきます。(最後にSingle Passはオフにします)
213は適当に選びました。別に0でも2000でもなんでもいいです。
ちなみに、説明しやすくするために使う、と書きましたが自分は実制作中よく使います。繰り返す数が多いと処理が重かったり、処理の内容がちゃんと把握できなかったりするので、制作中はむしろSingle PassをONにした状態のが多いです。

より詳細なBlock Begin / Block End に関しては今回のアドカレの6日目に[@MIN0NIUM](https://qiita.com/MIN0NIUM)さんが記事を書いてくれています。
ご参照くださいませ。
[Houdini はじめてのBlock Begin/End](https://qiita.com/MIN0NIUM/items/e7c94f3b3470dae642f6)
***
####Normalノード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/0741bad6-4455-0643-7a78-e17fa397cbb8.png)
[Normal](https://www.sidefx.com/ja/docs/houdini/nodes/sop/normal.html)は法線を設定できます。(そのまんま)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/293fa194-66e2-58ea-aa2f-c076828b0c52.png)
ここでは **Add Normals to** を **Primitives** に変更し、プリミティブレベルに法線を設定します。(アトリビュートNが作られる)
以降の回転を求める処理でこの値が必要になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/a8adfcf7-4407-ca9b-ef38-f6d7935f4d70.png)
設定された法線
***
####Attribute VopノードA
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/1f670a47-9bbf-1458-4281-5084c9d59406.png)
[Attribute Vop](https://www.sidefx.com/ja/docs/houdini/nodes/sop/attribvop.html)はVopネットワークを使ってアトリビュートの設定ができます。簡単に言うとAttribute Wrangleのノードバージョンです。
入力が4つありますがノードの中に入った際にこの入力をもとに値をとったりすることができます。今回は使いません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/f90b88ff-51bf-62d0-f718-a7dddde9754c.png)
まず、 **Run Over** を **Detail(only once)** に変更しましょう。
Run Overはどの単位で処理するか設定できるパラメーターです。例えば、Run Over を Points にしたとすると、全てのポイントに対して処理が行われます。これはポイントの数だけ処理が行われることでもあります。
今回設定したDetailは全体を表しています。そして処理の回数は必ず1回です。
***
次にAttribute Vop内に入ってみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/df31a5f2-8d25-038d-fc4b-c296ca5ec028.png)
Attribute Vop内の初期はこんな感じですね。
ざっくり言うと、**geometryvopglobal** は入力で、 **geometryvopoutput1** は出力です。この間にいろんなノードを繋げてアトリビュートの設定などができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/1a08dd93-e309-c32e-5d64-95afdc998fb3.png)
ということでこんな感じで繋ぎます。
左から

* [Bounding Box](https://www.sidefx.com/ja/docs/houdini/nodes/vop/bbox.html)
* [Average](https://www.sidefx.com/ja/docs/houdini/nodes/vop/avg.html)
* [Bind Export](https://www.sidefx.com/ja/docs/houdini/nodes/vop/bind.html#outputs)

です。
バウンディングボックスから最小と最大の座標をとり、それの平均をとることでオブジェクトの中心点をとっています。
Bind Exportを使うことで任意の名前のアトリビュートとして出力できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/ecce63a8-f829-9624-4ca6-2f11cae0edef.png)
***
####Attribute VopノードB
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/5b001d62-2eab-efc3-c4b7-27b68b9a7c9b.png)
もう一つ Attribute Vop を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/e0a02332-bbe0-eeac-3fb9-e587d9076515.png)
今回は Run Over を Primitives にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/52c2f44a-2c07-84e6-16a7-a000da047adc.png)
Vopネットワークはこんな感じです。
これは解説すると長くなってしまうので割愛させていただきます・・・。
処理としては
1.あらかじめ設定しておいたプリミティブの法線を(@N)を取得
2.取得した法線が真上に向くような回線行列を作成
3.X軸周りの回転値、Y軸周りの回転値、Z軸周りの回転値を取得
4.取得した回転値を**Rotate**という名前のアトリビュートとして**Detailレベルに設定**
というようなことをしています。
***
####ここまでで・・・
だいたい下準備が終わりました。
プロシージャルモデリングではこのように下準備が結構必要です。いろんな条件でしっかり動作するように設定しないといけません。どこまでやるかの線引きもある程度必要です。
今回の二つ下準備が必要でした。

*オブジェクトの中心座標を求める
*オブジェクトの回転を求める

以上二点です。
基本編でやったように、 Copy and Transform で複製するのですが、この二つの両方がないと破綻してしまいます。

まず中心点をとらずに複製すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/6cabf495-938f-ecc3-3203-3c3fc4238ea5.png)
こうなります。
遥か彼方に複製されてしまい、求めているものとはかけ離れてしまいます。

そして、中心点をとっても回転をとらずに複製すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/98f54752-6481-04d6-fa11-2c6f2d31bfb9.png)

このように捻じれて複製されてしまいます。

しかし、中心点と回転値を求めて活用すれば解決できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/cc8046b0-659c-0f5c-6aef-a5e8dbc99e4f.png)
今回は基本編で作った形状をブタさんに適用するのが目的ですので、こちらのふたつの情報が必要でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/111cf139-85a5-4324-4dad-27c3f1ef5f1f.png)
上図は回転値を考慮せずに作成されたものですが、これはこれでアリという場合もあります。
どんな情報が必要かは自分の求めるものによって変わってきます。
***
####Convert Lineノード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/3239f89b-5ef1-9dee-e641-7325c1ae9702.png)
[Convert Line](https://www.sidefx.com/ja/docs/houdini/nodes/sop/convertline.html)は線に変換できるノードです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/d1b6c7db-93c0-dfd0-52f5-1ba125bb7a43.png)
これにより基本編でのGridとほぼ同じ状態にすることができました。
***
####形状作成
基本編でやったものと同じですのでいっきにいきます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/cff359a5-89cd-b1e0-74e7-0eeb4e65f2cb.png)
pointwrangleでidアトリビュートを設定し
Copy and Transformで複製し
Addで角を繋ぎます。
最後にBlock Endに繋げば、形状作成の処理はほぼ完了です。

ひとつだけ基本編から変更していることがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/c109320d-2382-8e93-e105-2594c45906a8.png)
Copy and Transformのパラメーターで
**Pivot Translate** と **Pivot Rotate** です。
ここにはエクスプレッションが入力されており、前述の中心座標と回転値の設定がしてあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/6c93fd93-eaac-16b3-5364-51769e76d4da.png)
中心点のX,Y,Z
回転値のX,Y,Z
をそれぞれ設定しなければいけません。
というわけで入力します。
**Pivot Translate**左から順に
`detail(0,"Center",0)`
`detail(0,"Center",1)`
`detail(0,"Center",2)`
**Pivot Rotate**左から順に
`detail(0,"Rotate",0)`
`detail(0,"Rotate",1)`
`detail(0,"Rotate",2)`

ここで使っているのは**[detail](https://www.sidefx.com/ja/docs/houdini/expressions/detail.html)**というエクスプレッション関数です。
試しに`detail(0,"Center",1)`を和訳っぽくしてみると、
`detail(0番目の入力の, Centerというアトリビュートの, 1番目の値)`
というような意味になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/1bab6a7d-5b78-788e-e93e-e961914f4ac9.png)
**0番目の入力**というのはそのまま入力されているノードの事を表しています。(今回の場合はpointwrangle4のこと)
複数入力ピンがあった場合、左から順に0,1,2,3と数えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/3a50defd-419f-33f6-7f7a-46208085c03c.png)
1番目の値というのは、上図の**Center[1]**の**1**です。
同じアトリビュート名で配列のように複数値を持っているときはこの数字によって取り出す値を決めることができます。
***
ここまで設定し、Block End のSingle Passを外すとだいたいできていると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/f555e599-6c0c-ef38-ddb6-ab8f436e5e17.png)
ワイヤーだけだとなにがなんだか・・・。
***
####Fuseノード
残り2つです。おまけみたいのものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/b9120c92-7ff1-1f01-ff3f-b7276ca666a8.png)
[Fuse](https://www.sidefx.com/ja/docs/houdini/nodes/sop/fuse.html)はポイントを結合することができます。
プリミティブごとに処理したことにより、プリミティブの境界でポイントやエッジがダブっているのでこのノードで結合します。
***
####Colorノード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/3885f6ed-be36-4335-19cf-5299922af5ff.png)
[Color](https://www.sidefx.com/ja/docs/houdini/nodes/sop/color.html)で色を付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/dd56aaea-12d9-79fe-976e-8134bd439b01.png)
お好みの色をどうぞ。
以上で終了です！おつかれさまでした！

#まとめ
ブタさんをつかってやってきましたが、ブタさんを他のオブジェクトに変えるだけで同じ変形がかかります。
異なるオブジェクトで同じような結果を得るのに最低限の作業で済むのはプロシージャルの強みですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548340/ef40eedd-bcd3-0295-39aa-34587df56a71.png)

本当はワイヤー以外の部分も解説しようと思っていたのですが力尽きました・・・。
それでも、この記事が少しでもHoudiniの学習に役立てば幸いです。

もし記事内で間違いや不明点等あれば書き込んでいただけるとうれしいです。
最後までお読みいただきありがとうございました。