Houdini 19.5で追加されたTangent Field SOPについて

この記事は[Houdiniアドベントカレンダー2022](https://qiita.com/advent-calendar/2022/houdini)  12日目の記事です。

# はじめに
[Procedural Design](https://www.procedural-design.com/)の[Akira Saito](https://twitter.com/a_saito)です。
Houdini等を使用しロボットなどのメカデザインを自動で行う研究をしています。
![collageFg01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/4e950509-1ec2-51ee-d1b0-3c92407f7566.png)

今回はHoudini 19.5で追加されたtangent field SOPについて簡単に紹介したいと思います。

### 動作環境
Houdini Indy 19.5.499(apple silicon)
macOS Monterey バージョン12.51
MacBook Pro (16-inch, 2021)
プロセッサ Apple M1 Max
メモリ 64 GB


# 形状に沿ったベクトルがほしい

動物の体毛や魚類の鱗など、曲面上にオブジェクトを有機的に配置したいとき、その向きを定義する情報(ベクトル)が欲しい。

# Houdini 19.0の場合
![スクリーンショット 2022-12-11 1.54.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/f91f29de-56cc-0601-a176-2c991e124317.png)

Measure SOPのCavatureでprincipal を選択し、Direction を設定することで、２種類のベクトルを求めることができます。

Smallerで主曲率が低い方の主方向(ドーナツの輪に沿う方向)
![スクリーンショット 2022-12-11 2.35.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/19a03604-8d44-d8a4-0362-abf6ce99a42b.png)

Lrgerで主曲率が高い方の主方向(ドーナツの輪に対して直行する方向)
![スクリーンショット 2022-12-11 2.35.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/54de1f9f-628a-cec0-d2ab-e8c2e389a8fa.png)

曲率が低い方の主方向で、毛並みや鱗の方向を決定すれば良さそうですが、問題がありました。
以下の画像で示すように、各頂点での方向がバラバなのです。
![スクリーンショット 2022-12-11 3.09.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/80a70610-9a71-5104-82dd-36d4fb6112ad.png)
この問題に対し、VEXなどを使い方向を揃える処理を実装しましたが、完璧なものにならず部分的に破綻してしまう物でした。

自身の実力不足に打ちひしがれていたとき…
# Tangent Field SOP登場
Houdini19.5に新たにTangent FieldというSOPノードが追加されました。
![スクリーンショット 2022-12-11 3.31.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/f595d0bf-b673-57a4-507a-c6761ec34cce.png)
基本的にこのノードは各頂点、もしくはプリミティブに対し、全体的に滑らかに連続する接線ベクトルを生成するものなのですが、その生成にCavatureを加味することができ、結果的に形状に添いつつ全体的に連続した主方向を得ることができるのです。
rubbertoyで生成したTangent Fieldを可視化すると、複雑な形状が整った毛並みのようなベクトルで包まれています。
![スクリーンショット 2022-12-11 12.50.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/8a3d0325-ec84-894d-1d55-25748511f268.png)

# tangent field SOPのパラメーター

https://www.sidefx.com/docs/houdini/nodes/sop/tangentfield.html

公式マニュアルをざっくりと翻訳

| パラメーター名 | 機能 |備考|
|:-|:-|:-|
|Group|フィールド属性値が設定される入力ジオメトリのプリミティブのサブセット（またはそのポイント）。入力のすべての閉じたポリゴンの属性値に影響を与える場合は、空白のままにします。||
|Carried On|生成されたフィールドがポイントまたはプリミティブのどちらに引き継がれるかを決定する。｜
|Directions|出力フィールドの方向の数。通常のベクトル場では1を使用します。このノードでは、最大8方向まで指定できます。実際には、1, 2, 4, まれに 6 以外の値を使用することはほとんどない。|
|Global Rotation|このパラメータを使用すると、生成されたすべての方向を、それぞれの接線空間で一貫して回転させることができます。｜

**Guides**
ガイドがない場合、つまりすべてのガイド強度パラメータがゼロに設定されている場合、このノードはサーフェス上の「最も滑らかな」フィールドを見つけます。この最も滑らかなフィールドは、Global Rotationパラメータを使用して、どのマウントでグローバルに回転させても同じように滑らかになるように構成されています。

| パラメーター名 | 機能 |備考
|:-|:-|:-|
|Curvature|生成されたフィールドに影響を与える曲率方向の力を設定します。このオプションはフィールドの数が２つ以上の時にのみ有効であることに注意してください。フィールドが最大または最小の主曲率方向に従う必要があるかどうかを指定することができます。4-vectorフィールドでは、2つの主曲率方向は互いに直交しており、フィールドをどちらかに合わせても同じ効果があるため、この選択は無意味であることに注意してください。
|Boundary|生成されるフィールドに影響を与える境界接線の力を設定します。接線は各境界のループを中心に時計回りか反時計回りに方向付けることができ、反時計回りの方向付けでは、表面はループの横断方向の右側になります。同様に、境界の方向をサーフェスに対して内側または外側に向けることで、フィールドが境界に直交するように強制することができます。
|Attribute|ガイド属性の影響力を設定する。ガイド属性は、フィールドがガイドされる点またはプリミティブに非ゼロのベクトルを割り当てるvector-3属性でなければならない。ゼロの値はこのノードでは無視され、塗りつぶされる。非ゼロのガイド値を持つ点またはプリミティブに割り当てられた出力方向は、入力値と正確に一致せず、その大きさが大きく異なる可能性があることに注意すること。|重力方向や進行方向等の影響を与えたい場合に、設定します。<br>ここで設定するベクトルに平行になるだけで、前後は維持されない気がする(要検証)。<bR>出力されたTangent Fieldを反転したい場合はGlobal Rotationで回転させる。
|Attribute Name	|ガイドに使用するアトリビュートの名称。


**Output Attributes and Groups**
| パラメーター名 | 機能 |備考
|:-|:-|:-|
|Field Attribute|作成する方位属性名。生成される方向の数に応じて、個々の方向の属性名にインデックス番号が付加される。
|Normalize|オンに設定すると、生成されたフィールドベクトルはすべて単位長になります。そうでない場合は、滑らかに変化する大きさで計算されたものとして報告され、通常、特異点付近で低下します。
|Generate|出力に属性として生成されるフィールドインスタンスベクトルの数を決定します。方向は反時計回りに0, 1, ...と番号付けされる。
|Singular Group|有効にすると，特異な要素（フィールドがプリミティブ上に生成されている場合はポイント，フィールドがポイント上に生成されている場合はプリミティブ）のリストがグループとして報告されます．	|Tangent FieldをPointに生成した場合、特異点のグループはprimに、Tangent FieldをPrimに生成した場合は、特異点のグループはPointに生成されます。<br>特異点の正負の区別がないと思われる。(要検証)何らかの方法で区別したい。
|Discontinuity|有効にすると、方向数が1より大きい場合、フィールド方向インデックスの不連続性を示すエッジグループが報告される。ほとんどの場所で、個々のフィールド方向ベクトルは滑らかに変化するベクトルフィールドのように動作する。しかし、これはグローバルには実現できないことが多く、個々の方向が90度などジャンプしているように見える場所があるはずである。点の上に生成されたフィールドの場合、これらのエッジは、エッジの一端から他端へのジャンプを示す。面上のフィールドの場合、これらのエッジは、エッジの両側の面間のジャンプを示す。

**Visualization**
これらのパラメータは、Tangent Fieldのビューポート状態によって使用され、変更してもオペレータの再クッキングは起こりません。
| パラメーター名 | 機能 |備考
|:-|:-|:-|
|Visualize Field|有効にすると、ノードのビューポート状態がアクティブのときに、フィールドがジオメトリの上に表示されます。複数のベクトルフィールドを表示する場合、最初のインスタンスのベクトルフィールドは赤で描画され、他のすべてのインスタンスは青で描画されます。プリミティブ上で計算されたフィールドを表示する場合、4頂点以上の面の内部三角形分割の各メンバーの三角形のインスタンスのセットが表示されます。
|Display Normalized|有効にすると、計算値が単位長でない場合でも、すべてのフィールドベクトルが単位長で表示されます。
|Prescale for Viewing|有効にすると、ベクターは事前に計算された縮尺で表示され、乱雑になるのを防ぐことができます。
|Vector Scale|ベクターの現在の表示スケールを任意の係数で再スケーリングできるようにする。
|Show Singularities|有効にすると、各特異点のおおよその位置にドットが表示されます。赤い点は正の指数を持つ特異点、青い点は負の指数を持つ特異点を示します。


# 実践編(Rubber toyをウロコで覆う)

### 準備
Rubbertoyのデフォルト状態は各パーツがブッ刺さった状態なので、全てのメッシュが地続きになった状態に変換します。


初期状態
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/db55b282-effc-c26b-bea7-1bb7ae19b545.png">
vdb from polygonsでVDB(SDF)に変換
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/f788953d-9662-0e27-6c7f-a5c0779a8534.png">
convert　SOPでポリゴンにコンバート
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/99456f1f-11c8-e005-b351-db47c2619a0a.png">


### tangent field SOPの設定
tangent field SOPのデフォルトから変更するパラメーターは２つ
Directions を２に。
Output Attribute and Groups の GenerateをOne Direction Per Symmetric Pairに
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/6b40dec8-2fdc-b429-a33e-9b6cbfc1a59f.png">

Enterキーを押してエディットモードに入れば、生成されたTangent Fieldが可視化される。必要があればcurvatureなどのパラメーターを調整する(この時点ではウロコの配置としては少し破綻します。気にせず次に進みましょう)。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/3e0f7a51-0a51-9a53-2eef-be8b5d755063.png">

### Copy To Pointへの準備
Copy To Point　SOPで必要なpointアトリビュートNとupを用意します。

attribute rename SOPでtangent field SOP　で作られたアトリビュートfield0を配置物のZ方向を指定するポイントアトリビュートNにリネーム。
normal SOPで配置物のY方向を指定するポイントアトリビュートupを生成します。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/f8e6ad63-c197-bf38-168f-3693c989bd1c.png">
ウロコを配置しする場所として、scatter SOPでポイントをばら撒きます。デフォルトの設定で、事前に用意したpointアトリビュートは各ポイントに転写されます。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/7aa501fe-1ba3-be3f-a89e-5a7b891d181d.png">

### ウロコのモデリング
今回はシンプルかつ方向がわかりやすい棘状のウロコにします。
![スクリーンショット 2022-12-11 21.47.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/77d353d7-cd21-2900-113f-d2fbe6e8772c.png)
Z+方向に向いた棘状のモデルを用意
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/078ba10f-caa7-1611-151d-ed3c6422cba2.png">


### copy to points SOPを使用してウロコの配置
copy to points SOPの左側のインプットにウロコモデルを、右側に、scatter SOPで生成した点群を接続します。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/ecc2bf99-7cca-158c-da9b-6efdf04bce0f.png">
ウロコがRubber toyの表面に沿うように配置されました。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/f03e1b98-865b-5591-1a5d-f5c966291796.png">
しかし、後ろ足に配置されたウロコは足先にから付け根にかけて逆行しています。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/48e37482-9d9a-e92e-d5ab-1cb7ef243a76.png">

### ガイドアトリビュートを用意しウロコの向きを整えます。
tangent field SOPの直前にattribute crete SOPを挿入し、guideという名称でベクトル型のpointアトリビュートを生成し {0,0,1}という値を設定します。
tangent field SOPのGuidesパラメーター内の、attribute nameで新たに用意したアトリビュート、guideを指定。
![スクリーンショット 2022-12-11 22.41.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/feac9f5a-7bfa-b094-ab6f-d0e68e545bc9.png)
tangent field SOPのGuidesパラメーター内のCurvatureとAttributeを調整し、ウロコの向きを整えていきます。
![スクリーンショット 2022-12-11 23.06.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/e9806ad2-3567-806d-7ab6-784a9c63cd8e.png)


### 末端のばらつきを抑える
足のさきなどにウロコの先のばらつきが散見できるので、そちらを解消していきます。
![スクリーンショット 2022-12-11 23.21.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/a5432dd6-1ee6-c776-e35f-63c001b471a2.png)
ばらつきのが起きている場所は、足や尾などの先端でtangent field のベクトルが集中している所になります。
![スクリーンショット 2022-12-11 23.33.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/ccded852-378d-32ed-ef1c-a137bcab68a3.png)
ベクトルが集中している部分を、tangent field SOP　の Singular Groupを設定することで、primグループに格納することが可能です。
![スクリーンショット 2022-12-11 23.34.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/8951944a-f568-951b-5e14-641ced6f41cf.png)
group expand SOPを使い、ベクトルが集中するprimグループsingularを拡張します。
![スクリーンショット 2022-12-11 23.35.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/99619cab-a7c6-7225-8916-aa88c9242da2.png)
scatter SOPのグループ指定を!singularとすることで、ベクトルが集中しない場所のみにポイントを発生させます。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/ac47ee02-6182-0db6-beda-9050bec538b2.png">
ここまでの対策のおかげで、先端部分のばらつきを抑えることができました。
![スクリーンショット 2022-12-11 23.43.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/89c198cc-52f9-f4c8-41c2-73f18ff17b16.png)

### 更なる改良
詳細は割愛しますが、ウロコモデルをより自然な形状に。
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/3872c331-8eb5-ac29-7914-5fc1c3afdc46.png">
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/31f96fd6-e3d8-a1ed-a5f4-acf89e901dba.png">
生成されたTangent fieldをsmooth SOPなどでより滑らかにする。
![スクリーンショット 2022-12-12 0.26.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/1eeeaa01-0be2-b3ce-68ea-9a32a3cc1c50.png)
![tbrender_1375.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/24493c18-cbcf-ffa2-b36e-8614b1e908e3.png)
![tbrender_1377.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/4296e500-6444-185d-f1e3-bc91bf540bfa.png)
![tbrender_1376.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/779b79ff-ab8f-9b5c-a43f-962cc1c71141.png)

# まとめ
新しく追加されたtangent field SOP。
簡単な手順で物体表面の繋がりを表すベクトルを求めることができます。
今回、具体的に解説したウロコ以外にも体毛や血管など有機的な物の配置はもちろん、
形状のエッジなどを検出することができるのでハードサーフェスモデリングなどでも有効だと思われます。今後も、様々な活用法を模索していきたいと考えています。

この記事が、皆様の何らかのお役に立てれば何よりです。
![tbrender_1378.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/bf76108f-f5b7-ebbf-1b01-6a5e4361a383.png)
![tbrender_1379.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918826/5d871c55-2796-442f-68e3-ad757fc0859a.png)