ShaderForgeによる初めてのシェーダー作成

## まえがき

この記事は [VRChat Advent Calendar 2018][adcale] の5日目の記事です。

今回のAdvent Calender参加を機に、初めてのシェーダー作成にチャレンジしてみました。
主に *Shader Forge* の導入から簡単な使い方まで、一通りやったことを書いてます。

自分の思い通りになるシェーダーを作るのは難しいですが、とりあえず形にするだけなら簡単なのでやってみると楽しかったです！


## Shaderについて

Unityにおけるシェーダーは基本以下の3種類。

* サーフェスシェーダー Surface Shader
* 頂点シェーダー / フラグメントシェーダー Vertex and Fragment Shaders
* 固定関数シェーダー

またGPUパーティクルを作る際に必要となる **ジオメトリシェーダー** というものがあるらしいです。
（参考：[シェーダーを書く | Unityマニュアル](https://docs.unity3d.com/ja/current/Manual/ShadersOverview.html)）

で、上記のシェーダーを実際に形にするには主に `HLSL` 言語を用いてプログラミングする必要があります。
必要がありますが、ここで **Shader Forge** を使えばプログラミング不要でシェーダー作成可能です！


## Shader Forge

ノード（機能ごとに分けられた要素）からエッジを伸ばし出力<-->入力を接続していくことで、ユーザーがプログラムコードを書くことなくシェーダーを作成できるUnity拡張エディタ。すごい。

![node.png](https://qiita-image-store.s3.amazonaws.com/0/238841/d00540db-8cd9-6560-dc0b-d8e55a0a7d8b.png)


詳細については記事最後の参考リンク先を御覧ください。
今回の記事ではインストールから初期環境設定および使い方まで体験したことを記述しています。

* 余談  
  *Unity 2018* では同様の機能をもつ *ShaderGraph* が標準搭載されています。  
  ただ *ShaderGraph* から `.shader` ファイルへのエクスポートは現状不可かつ予定もないらしいため、*ShaderGraph* で作成したシェーダーを *Unity 5.6* や *Unity 2017* に持っていくことは無理みたいです。
（参考：[ShaderGraph export | Unity Forum](https://forum.unity.com/threads/shadergraph-export.537032/)）


### インストール

2018/12/1現在では作者さんがサポートできなくなったためにAssetからは削除されています。
その代わりに [GitHubで公開](https://github.com/FreyaHolmer/ShaderForge) されており、ダウンロードできます。

1. ダウンロード

    Zipファイルをダウンロードする方法と `git clone` を使う方法の2通り。
    * Zipファイル
    
        [GitHubのページ](https://github.com/FreyaHolmer/ShaderForge) を開き、右上にあるボタンからダウンロード。
        ![GithubDownload](https://qiita-image-store.s3.amazonaws.com/0/238841/1a117f2e-3b49-e022-78e1-025d67c17c83.png "Download zip file from github page.")
    * `git clone`

    そのまま `clone` だとサイズが大きすぎるので `--depth 1` としてシャロークローンする。
    （これを機に `git` を使おうという方は、パッケージ管理ツール [Scoop](http://scoop.sh/) からインストールするのが簡単でおすすめです）

    ```shell
    git clone --depth 1 https://github.com/FreyaHolmer/ShaderForge
    ```

1. Unity Packageの修正

    用意されているSceneファイルを開くとUnityのバージョンが異なるため警告がでてきます。
    必須ではないですが、気になるので修正しておきます。

    1. `"C:\ShaderForge\Shader Forge\Assets\ShaderForge\Example Scene.unity"` を  
       *Unity 5.6.3p1* で開く  
        （ファイルパスについては各自のダウンロード先に応じて変更してください）

    1. 作成されたバージョンが異なるので警告が表示されますが、`Continue` で大丈夫
    ![ImportShaderForge](https://qiita-image-store.s3.amazonaws.com/0/238841/bf3d1661-9211-b399-3fe2-79edc26fdb8c.png "Import example package")

    1. `Assets -> Export Package...` から *Unity 5.6.3p1* バージョンによるパッケージ出力
    
        元の `Example Scene.unity` パッケージは含めないようにする。

1. Unityプロジェクトへのインポート

    上記で作成したパッケージを、シェーダー作成用のプロジェクトでインポートする。

    `Assets -> Import Package -> Custom Package...`


## Shader Forgeでシェーダー作成

### 起動

上記のように *Shader Forge* をインポートしていれば、`Window -> Shader Forge` から *ShaderForge* のノードエディターが起動できる。
![ShaderForgeOpen](https://qiita-image-store.s3.amazonaws.com/0/238841/8349561c-aa71-34e1-367f-067f67179fcb.png "Shader Forge boot window.")


*New Shader* から新規作成。
シェーダーの種類選択では **Lit(Basic)** が基本的なシェーダーに向いてるみたいです。
![SelectShader](https://qiita-image-store.s3.amazonaws.com/0/238841/e6d7bea3-1edf-5881-4acc-182b360f52ce.png "Select kind of shader.")

シェーダーを選択すると編集画面になります。
![EditWindow](https://qiita-image-store.s3.amazonaws.com/0/238841/73f87474-0e46-714b-6b6e-ba21ba852e41.png "Edit window.")


### 環境設定

*Shader Forge* を起動後、左上の *Settings* ボタンから初期設定を行っておきます。
以下の設定項目についてチェックしておくのがいいと思われます。

|Settings |Summary |
|---|---|
|Real-time node rendering |自動プレビューをON |
|Show node browser panel |右サイドにノード一覧パネルを表示 |

また `Auto` にチェックを入れていると、編集時に `Compile shader` が自動的に行われて便利です。
マシンパワーに余裕があればこちらもチェックしておきます。
![Configuration](https://qiita-image-store.s3.amazonaws.com/0/238841/d0034f35-d848-8c34-f7fa-f2fa52b299d9.png "Editer settings.")


### シェーダーの作成

シェーダーを作成するにはノードを組み合わせて接続していきます。
各ノードの出力は最終的に *Main* ノードに接続します。

各ノードの接続が完了したら左上の `Compile shader` をクリックしてコンパイルすることでシェーダーのコードが生成されます（上記設定の `Auto` にチェックが入っている場合は自動的にコンパイルされます）。

実際にどんな風に作っていくのかは [*Shader Forge* のチュートリアル](http://acegikmo.com/shaderforge/tutorials/) などを参考にしてみるのがいいと思います。
またノードについては [公式のノード・ドキュメント][nodes] を参考にしてみてください。

下図はチュートリアルのグラデーション例。
![TutorialGradiation](https://qiita-image-store.s3.amazonaws.com/0/238841/67242aae-3eb6-621e-f358-451294097f46.png "Gradiation shader.")


## スニペット

今回作ってみた中でいろいろ使えそうだと思ったノードの組み合わせ例。
はじめは基本的なものもわからなったので載せておきます。

以下のサイトでより多くの実践的な組み合わせを紹介されているので、参考にしてみてください。

* [[ShaderForge] よく使いそうな繋ぎ方備忘録[ShaderGraph] | 弱火でじっくり][snippet] 


### 時間変数

`Time` ノードを使えば時間経過による値の変化を表現することができます。
`Time` の出力を `Sin` ノード（Sin関数）に接続して、値を *-1 ~ 1* の範囲に変換することが多いと思います。

`Time` ノードの出力は複数ありますが、出力 `t` に対して除算やべき乗してるだけです。
欲しい時間周期がなければ `Divide` ノード（除算）や `Power` ノード（べき乗）、`Multiply` ノード（乗算）などを接続して調整します。

![Timer](https://qiita-image-store.s3.amazonaws.com/0/238841/e6423af2-a7ef-9b13-23e7-33503d5752f6.png "Timer node.")


### UVスクロール

`Panner` ノードを使用してテクスチャをスクロールさせられます。
`U` , `V` にスクロール量となる値を入力。
![ScrollTexture](https://qiita-image-store.s3.amazonaws.com/0/238841/72e2fc64-6cce-9cfa-3ca5-7cdf391149bb.png "Scroll texture.")


### Vertex Offset

`Main` ノードにおけるこの項目では時間経過などで形状やアニメーションを変化させることができます。
`UV Coord.` ノードの出力とかを放り込んでやるとどんなものか簡単に確認できます。


#### 移動

XYZ方向に対する値を入力します。
動かしたい方向を制限する（たとえば縦方向のみ）ならば、その方向（Y）に対して `0` を設定します。

下図では時間経過によるY方向（縦方向）の移動アニメーションをさせています。
![VertexAnim](https://qiita-image-store.s3.amazonaws.com/0/238841/40206ea0-79f4-c919-c102-17a64fe9beea.png "Vertex Offset animation on y-axis.")


#### 拡大縮小

`Normal Dir.` ノードを利用します。
![VertexScale](https://qiita-image-store.s3.amazonaws.com/0/238841/f0c1d9ee-003f-0d05-1921-0ec45cb879a6.png "Vertex Offset scale.")


### Set/Get

これは組み合わせとは言えませんが便利だったので。

* `Set` ノードは出力値を名前をつけて保存できます。
* `Get` ノードでは保存した値を取り出して扱えるようになります。

これによってプログラミングにおける変数の働きを表現することができます。
![SetGet.png](https://qiita-image-store.s3.amazonaws.com/0/238841/77f1fd6e-ab55-793a-d3be-624dc99e86b0.png "Set/Get")


何が嬉しいかというと、ノードの配置を整理できます。
ノードを配置しているとエッジ（線）がぐちゃぐちゃになってしまい何がどうなってるのかわからなくなる、ということを防げます。


## 自作したシェーダー

今回のAdvent Calenderに合わせて、シャボン玉のような表現ができるシェーダーを作……れませんでした！
ある程度はそれっぽくなったと思うので、もう一手間二手間かけられれば……。
光の干渉・屈折を表現するのが難しそうです。

今回作成できたシェーダーでは次のようなことをやってます。

* 中心部は透過・Refractionを設定して光の屈折を表現
* 時間経過で虹色を変化させる
* 時間経過で拡大縮小を行う

*Shader Forge* 上では下図、ソースは [こちらのgist](https://gist.github.com/akiakishitai/5caadbd7cbc0ecab30b2568e2703a1b1) で公開してます。
![MyShader](https://qiita-image-store.s3.amazonaws.com/0/238841/d24685bc-a623-52a3-4e56-4e1104d24420.png "Handmaid shader.")

Unity上の *Sphere* に適用するとこんな感じです。
![MyShader.gif](https://qiita-image-store.s3.amazonaws.com/0/238841/d8752c68-7b15-d78e-fdd8-7929b804efe7.gif "Apply my shader.")


## あとがき

せっかくだからやってみるか！という心持ちでシェーダー作成に着手しましたが、シェーダー関連で記事書く予定の方々も複数人いて震えてます。
早めの日程を予約しておいてよかった、後半にしてたら死んでた。

ともあれ、初心者でもこんな感じで作れて面白いですね！
適当にノードをつないでいくだけでも形はできる・見えるので、モチベーションが保てて良かったと思います。


## 参考

* シェーダー
  * [Unityマニュアル](https://docs.unity3d.com/ja/current/Manual/index.html)
  * [HSLSのリファレンス | Microsoft](https://msdn.microsoft.com/ja-jp/library/ee418346(v=vs.85).aspx)
  * [シェーダー芸（GPUパーティクル）入門～概要編 | ニムサイト](http://nimushiki.com/2018/09/28/1203/)
  * [Unity のシェーダの基礎を勉強してみたのでやる気出してまとめてみた | 凹みTips](http://tips.hecomi.com/entry/2014/03/16/233943)

* Shader Forge 紹介
  * [ShaderForge | GitHub](https://github.com/FreyaHolmer/ShaderForge)
  * [Unity道場11 Shader Forge 101 ～ShaderForgeをつかって学ぶシェーダー入門～　基本操作とよく使われるノード編 | SlideShare][intro-2]
  * [【Unity】ノードベースのシェーダエディタ「Shader Forge」紹介 | コガネブログ][intro-1]

* Shader Forge 実践
  * [Shader Forge - Nodes][nodes]
  * [【Shader Forge】Timer + Lerp 使ってみた | Qiita](https://qiita.com/ShirakawaMaru/items/db535bab43220f51c115)
  * [【Unity】地形作りで学ぶShader Forge超入門 | おもちゃラボ](http://nn-hokuson.hatenablog.com/entry/2017/09/21/201638)
  * [【Unityアセットアドカレ】Shader Forgeでナイトプールを作ろう！ | CrossRoad](https://www.crossroad-tech.com/entry/UnityAsset_ShaderForge)
  * [[ShaderForge] よく使いそうな繋ぎ方備忘録[ShaderGraph] | 弱火でじっくり][snippet]
  * [ShaderForgeでクリスタルのマテリアルを作る -VR空間 TREASURE HUNTERの作り方- | STYLY][crystal]


[adcale]:https://qiita.com/advent-calendar/2018/vrchat
[nodes]:http://acegikmo.com/shaderforge/nodes/
[intro-1]:http://baba-s.hatenablog.com/entry/2015/06/10/102833
[intro-2]:https://www.slideshare.net/nyaakobayashi/unity11-shader-forge-101-shaderforge
[snippet]:https://yowabi.blogspot.com/2018/02/shaderforge.html
[crystal]:https://styly.cc/ja/tips/treasure_hunter_takano_unity02/