勾配(Gradient)アレコレ

# Merry X'mas & Happy Houdini!!

今年は個人的にUE4のプロジェクトで死にかけててHoudiniはあまり触れませんでした。
大変悲しいのでせめてアドベントカレンダーくらいは書かなきゃ！と思っていたら最終日のオオトリに当たりましたね。
なのでちょっとは役立ちそうなネタをご提供したいと思います。

本日のお題は **勾配** です。

勾配というネタをやろうと思った理由としてはPolyFrameとGradientでググってみて
日本語の記事があまりなさそうだったのと
新しく出来たTangent Field SOPがお祈り要素強めだったので
個人的にはこちらのやり方がまだ現役かなーという気持ちからですね。

## 勾配って何？
普段の会話中で **勾配** って言ったら坂道の斜面の角度のきつさくらいでしか使われることはないと思います。
<img src="https://2.bp.blogspot.com/-78mChg3NsLQ/VGLMgDJiciI/AAAAAAAApBk/3zAG9kQK1Fg/s800/noborizaka_saka.png"  width=300>
英語では勾配は **Gradient** と言います。
wikipediaではこの様に記載されています。

```
勾配（こうばい、gradient, en:grade (slope)）とは
水平面に対する傾きの度合いをいう[1]。地形や土構造物、人工的な構造物、建造物の傾き（傾斜）について言うことが多い。
```
UnrealEngineやUnityでもグラデーションの関数やノードとして知られています。
概念的には値の高低の傾きの分布です。
天気図の気圧配置と同時に出る風向きや風の強さなんかが馴染み深いのではないでしょうか？
<img src="https://1.bp.blogspot.com/-liFU57C_IsU/Ur1GFHnxsCI/AAAAAAAAcW8/hTvjknYnVdI/s800/job_otenki_oneesan.png" width=300>
数式上では∇(ナブラ)で表されます。
詳細は下記のページがわかりやすいです。

https://batapara.com/archives/vector-gradient.html/


## Houdini上での勾配の作り方
メッシュ上の勾配であれば **PolyFrame** という便利なノードがあります。
StyleをAttributeGradientにして、vectorのポイントアトリビュートをAttributeNameのパラメータに指定すると
それを元にGradientを計算してくれます。
3次元上の勾配であれば **VDB Analysis** というノードを使ってDensityアトリビュートなんかを使って
ボリュームの勾配が簡単に作れます。

## 実例 - 勾配で何が出来るの？
何らかの値の分布から傾きを生成して例えばある点から距離に応じて削っていったり削った方向に粒を飛ばしたり
絵の輪郭線をシャープにしたり草や毛や鱗を生やして傾けたり出来ます。
VFX的な使い方では流体の制御や群衆の進む方向の制御、紙が燃え広がる表現、植物の植生を決定付ける要素に使えたりすると思います。
ＣＧやゲームを生業としている方々なら汎用的に日常的に使用している概念でしょう。
プロの方々には釈迦に説法なところはご愛敬;-)

#### メッシュ上の勾配(PolyFrame)の例
##### ・EdgeTransport でポイントグループからの距離アトリビュート出して勾配を作る方法
FindShortestPathでも距離を計算してくれますけどEdgeTransportの方が楽で早いのでこちらを使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/bf4b3cc9-0a9d-a039-0989-cfe9d280e2a8.png)
この様なstartというポイントグループを鼻先に作って
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/ed5e1085-16d9-2e91-d2aa-d62951fcb369.png)
startから@distという距離のポイントアトリビューを作ります。
distの値は鼻先から首の下の方にかけて数値が大きくなっていきますね。
このdistの勾配を取得したい訳です。
ここでPolyFrameを使います。

しかしただ普通に使っただけだとこの様にWarningが出てしまい勾配は計算できません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/da779f95-5017-089c-6397-85abb2030bf8.png)
公式のドキュメントには記載されていないのですが
https://www.sidefx.com/ja/docs/houdini/nodes/sop/polyframe
指定するアトリビュートはベクターじゃないと動作しません。
なのでPointWrangleで
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/29b004e5-1fa5-f541-91bd-dace6dc9dd98.png)
v@distv = set(@dist,0,0);
などとして別のベクターのポイントアトリビュートを用意してあげてPolyFrameに食わせると勾配(@gradient)を出してくれます。
@gradientが計算されて出力されるクラスはVertexなのでAttributePromoteでPointに戻してあげると処理しやすいでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/8046eb94-192a-5559-8f45-06d78e9ecf68.png)

EdgeTransportでdistanceを使う代わりにNoiseを使うとこの様な表現も可能です。
まるで草原に風が吹いている様ですね。

![gradient01b.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/9ce8a1ad-7a80-66b4-e97b-3efae50f0f83.gif)

この様にメッシュ上の勾配を作ってあげることで草や毛や鱗など様々な表現に応用することができます。
下記の動画はメッシュ状の勾配(Gradient)をパーティクルの初速に当てはめた例です。

https://youtu.be/F1y1teRlYzg

また自分の趣味の取り組みとしてはこの様にラフ画の線を取りやすい様にする仕組みの部分に白黒の値を用いた勾配を利用しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/53e6006b-3774-1277-d236-8b796e52c98c.png)

本当はOLMさんの様にAIなんかを使ってやった方が良いのでしょうが趣味で土日にやるのはこれが精一杯でした。
線をシンプルにしたあとパスに変換する様な仕組みもやってました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/74eca577-5200-2faa-b7f7-93c1952ba48a.png)

勘の良い人はピンと来るかもしれませんが線に沿って生成した点群を線の中心寄せる際に勾配を用いています。
ぼかして白黒の値で@gradientを生成して点群をgradientの方向に動かして線をシンプルにシャープにしているのです。

AfterEffectのCC Vector Blur、SubstanceDesignerのVectorWarpやVectorMorph,SlopeBlueがまさにこんな感じです。

https://twitter.com/ijiVFX/status/1230734135343243265/photo/1

#### Volume上の勾配(VDB Anaylysis)の例
上記のラフ画の線をシンプルに細くする例に近い感じの処理を使って煙をよりタバコの煙っぽくシャープにする
(AEのCC VectorBlurやSubstanceDesignerでいうところのVectorWarpやVectorMorphに近いことの３Ｄ版)ことができます。

Aligator Noiseを勾配で濃い方に寄せたもの(右)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/29755d6e-3f61-265f-e569-58b29b15578e.png)

Spars Convolution Noiseを勾配で濃い方に寄せたもの(右)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/43d974f2-eee0-61a0-4910-c29cd4071326.png)

PyroのBillowySmokeにDensityのGradientで調整をかけるとこの様な質感が得られます。

https://youtu.be/bSDtT85c2-0

たばこの煙の様な質感ですね

https://twitter.com/Louloum91871589/status/1605470838911864832

下のLoulouさんのタバコの煙が近い様に思えます。

## まとめ
Houdiniなら勾配の計算も瞬時に行ってくれるのでいろいろ短時間に試せていろんな表現の幅が広がっていくことと思います。
皆さんにとって勾配が身近なものになって良い作品作りの一助となれば幸いです。
(使用したバージョン Houdini Indie 19.5.403)

### hip配布
[メッシュ状の勾配のhiplc](https://drive.google.com/file/d/1EuCxJ0b73vplX_mdYI_lBv43vN4us7nK/view?usp=sharing)

[３Ｄの勾配のhiplc](https://drive.google.com/file/d/1BmrMs5Wb_IEntjdhu7ZAAXFs3BdxjIRJ/view?usp=sharing)


### 謎→解明

~~この勾配できゅっとさせるアルゴリズムって名前なんていうんでしょうね？~~

記事の公開初日に [さはら](https://twitter.com/shr_id) さんに教えて頂きました。

https://twitter.com/shr_id/status/1607086954067419136

**勾配降下法 (gradient descent)** というのだそうです。

ググったらHoudiniのチュートリアルでもありますね。

https://www.sidefx.com/tutorials/pragmatic-vex-1-gradient-ascent-descent-planar-geometry/

いろんな学びがあります。