Unity Shader入門した頃の自分に教えたい事

# はじめに
この記事は[VRChat Advent Calendar 2018](https://qiita.com/advent-calendar/2018/vrchat)の23日目の記事です。
昨日の記事は、@synqark さんの[「VRChatの皆に手軽に綺麗になってほしくて作ったシェーダーの話」](https://qiita.com/synqark/items/de1bfb6966669b8606a8)でした。

この記事を書いてみて、実践的な内容が含まれてない事に気付いてつまらないなぁと思ったので急遽[UnityでGANTZ風シェーダー解説](https://qiita.com/kajitaj63b3/private/1c836a07b9164755b8a7)という記事も併せて書きました。Unityシェーダーを触って雰囲気分かってきた人向けの内容です。良ければこちらも読んでみて下さい。

こんにちは、[梶田悠](https://twitter.com/kajitaj63b3)です。
今年の6月頃からUnityにおけるShaderをしっかり勉強し始めました。
12月現在まででシェーダーで作ったものを以下にいくつか抜粋します。
半年くらいのシェーダー経験を踏まえて、これから学習する人向けにガイドラインを作る事が本記事の目的です。
厳密には間違った表現をしていたり書いていたりするかもしれませんが、厳密性よりとりあえずシェーダーを書けるようになる事を目指して書きます。

VRC アドカレですが、VRChatユーザー以外のUnityユーザーにも参考になるように書くつもりです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">GPUパーティクルアトラクターの最終調整版<br>これの解説本に入れておけば恥ずかしくないな<a href="https://twitter.com/hashtag/unity3d?src=hash&amp;ref_src=twsrc%5Etfw">#unity3d</a> <a href="https://twitter.com/hashtag/madewithunity?src=hash&amp;ref_src=twsrc%5Etfw">#madewithunity</a> <a href="https://twitter.com/hashtag/VRC?src=hash&amp;ref_src=twsrc%5Etfw">#VRC</a> <a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://t.co/wwO8Ava1ZZ">pic.twitter.com/wwO8Ava1ZZ</a></p>&mdash; 梶田悠 haruka kajita (@kajitaj63b3) <a href="https://twitter.com/kajitaj63b3/status/1031576533448544256?ref_src=twsrc%5Etfw">2018年8月20日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr">WIP<a href="https://twitter.com/hashtag/unity?src=hash&amp;ref_src=twsrc%5Etfw">#unity</a> <a href="https://twitter.com/hashtag/madewithunity?src=hash&amp;ref_src=twsrc%5Etfw">#madewithunity</a> <a href="https://twitter.com/hashtag/VRC?src=hash&amp;ref_src=twsrc%5Etfw">#VRC</a> <a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://t.co/Nc2mlV9Hsn">pic.twitter.com/Nc2mlV9Hsn</a></p>&mdash; 梶田悠 haruka kajita (@kajitaj63b3) <a href="https://twitter.com/kajitaj63b3/status/1053849873819164673?ref_src=twsrc%5Etfw">2018年10月21日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">綺麗な球体を作りました。<a href="https://twitter.com/hashtag/generativeart?src=hash&amp;ref_src=twsrc%5Etfw">#generativeart</a> <a href="https://twitter.com/hashtag/unity?src=hash&amp;ref_src=twsrc%5Etfw">#unity</a> <a href="https://twitter.com/hashtag/unity3d?src=hash&amp;ref_src=twsrc%5Etfw">#unity3d</a> <a href="https://twitter.com/hashtag/madewithunity?src=hash&amp;ref_src=twsrc%5Etfw">#madewithunity</a> <a href="https://twitter.com/hashtag/VRC?src=hash&amp;ref_src=twsrc%5Etfw">#VRC</a> <a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://t.co/dFs79qg50m">pic.twitter.com/dFs79qg50m</a></p>&mdash; 梶田悠 haruka kajita (@kajitaj63b3) <a href="https://twitter.com/kajitaj63b3/status/1065357383130443777?ref_src=twsrc%5Etfw">2018年11月21日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">初トレイルを作りました。<br>VRCでも使えます！<a href="https://twitter.com/hashtag/generativeart?src=hash&amp;ref_src=twsrc%5Etfw">#generativeart</a> <a href="https://twitter.com/hashtag/unity?src=hash&amp;ref_src=twsrc%5Etfw">#unity</a> <a href="https://twitter.com/hashtag/unity3d?src=hash&amp;ref_src=twsrc%5Etfw">#unity3d</a> <a href="https://twitter.com/hashtag/madewithunity?src=hash&amp;ref_src=twsrc%5Etfw">#madewithunity</a> <a href="https://twitter.com/hashtag/VRC?src=hash&amp;ref_src=twsrc%5Etfw">#VRC</a> <a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://t.co/ReiwUePZAJ">pic.twitter.com/ReiwUePZAJ</a></p>&mdash; 梶田悠 haruka kajita (@kajitaj63b3) <a href="https://twitter.com/kajitaj63b3/status/1066842357666967552?ref_src=twsrc%5Etfw">2018年11月25日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">Feeling Flow<a href="https://twitter.com/hashtag/unity?src=hash&amp;ref_src=twsrc%5Etfw">#unity</a> <a href="https://twitter.com/hashtag/unity3d?src=hash&amp;ref_src=twsrc%5Etfw">#unity3d</a> <a href="https://twitter.com/hashtag/madewithunity?src=hash&amp;ref_src=twsrc%5Etfw">#madewithunity</a> <a href="https://twitter.com/hashtag/shader?src=hash&amp;ref_src=twsrc%5Etfw">#shader</a> <a href="https://twitter.com/hashtag/VRC?src=hash&amp;ref_src=twsrc%5Etfw">#VRC</a> <a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://t.co/HPy2Uw8EBJ">pic.twitter.com/HPy2Uw8EBJ</a></p>&mdash; 梶田悠 haruka kajita (@kajitaj63b3) <a href="https://twitter.com/kajitaj63b3/status/1070482853882814465?ref_src=twsrc%5Etfw">2018年12月6日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 目次
- シェーダーを学ぶ際にまず抑えたい事
 - そもそもシェーダーってどんなものなのか
 - レンダリングパイプライン
 - 学習の指針


- 挫折要因
 - そもそもプログラミング未経験(VRCユーザー向け)
 - ドキュメントの状況がよろしくない
 - 数学的知識が必要になることがある
 - デバッグの難しさ

- 僕が勝手に話したい事
 - シェーダーの知識と作るもののロジックの知識は別
 - 更に先に進む為にできそうなこと



# シェーダーを学ぶ際にまず抑えたい事
とりあえずこれ知っておかないと混乱したりもやもやしたままの状態で学習する事になりそうだなぁという要素についてです。
## そもそもシェーダーってどんなものなのか
### ざっくり
シェーダーはグラフィクスの描画に関するプログラムでシェーダーの処理はGPUが担います。
Unityで作った映像は元はオブジェクトが何処に合って、どれくらい回転していて、どれくらいの大きさなのかという3次元的な情報から作られている訳ですが、最終的に色が映し出されるディスプレイは縦と横の2次元的な色(ピクセル)の並びです。
この色が映し出されるまでの過程でGPUが担っている部分の内、プログラムを書くことである程度処理を自由に変えられる工程をプログラマブルシェーダーと言って一般的にはこの部分を「シェーダー」と呼んでいます。
少し具体的に何ができるかを紹介します。
ざっくり言うと、オブジェクトの形と色をいじくれます。例えば、下記のツイートのシェーダーは人型のオブジェクトの表面を面(ポリゴン)ではなく点(頂点)で表示するようにして、その点の位置を条件によって移動させているので形を変えていると考えることができます。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr">WIP<a href="https://twitter.com/hashtag/unity?src=hash&amp;ref_src=twsrc%5Etfw">#unity</a> <a href="https://twitter.com/hashtag/madewithunity?src=hash&amp;ref_src=twsrc%5Etfw">#madewithunity</a> <a href="https://twitter.com/hashtag/VRC?src=hash&amp;ref_src=twsrc%5Etfw">#VRC</a> <a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://t.co/Nc2mlV9Hsn">pic.twitter.com/Nc2mlV9Hsn</a></p>&mdash; 梶田悠 haruka kajita (@kajitaj63b3) <a href="https://twitter.com/kajitaj63b3/status/1053849873819164673?ref_src=twsrc%5Etfw">2018年10月21日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### 用途
シェーダーは「Shader」と書き読んで字の如く陰影をCGで再現するもののではありますが、GPUの性能が上がるにつれて他にも様々な用途に利用されていて、陰影処理以外でシェーダーを使う事は珍しくなくモダンな用途として当然なものになっています。シェーダーの用途は大別すると以下の3種類の使い方が多いように感じます。

- 陰影処理(ライティング処理)
- VFX(エフェクトとか)
- ポストプロセス

陰影処理は3D空間上のどこにライトがあって何色の光を発してるか、オブジェクトは何色か、オブジェクトのどこにテクスチャのどの部分を貼り付けるかなどのオブジェクトそのものの見た目を作る処理です。
VFXはパーティクルなどの視覚的なエフェクトです。GPUパーティクルとかはこれにあたります。
ポストプロセスはディスプレイに映し出す画が出来上がった後に実際にディスプレイに表示する前に画全体に処理をかけて全体の雰囲気を変えるものです。BloomやDOF(被写界深度)などがあります。インスタのフィルターみたいに画全体を加工するイメージです。

## レンダリングパイプライン
前項で、以下の説明をしました。
>GPUが担っている部分の内、プログラムを書くことである程度処理を自由に変えられる工程をプログラマブルシェーダーと言って一般的にはこの部分を「シェーダー」と呼んでいます。

これら工程全体をレンダリングパイプラインと言います。グラフィクスパイプラインと書かれている場合もあるみたいでうす。各工程に名前が付けられていてこれらを○○ステージと言ったりもします。この工程全体を細かく覚える必要はないですが、「頂点シェーダーの後にフラグメントシェーダーが実行される」というように各シェーダーの実行順序を把握したり、処理全体を何となくでも把握している事は無駄な混乱を回避出来たり何ができないかを判断する事に役立ちます。
また、GPUの処理の特性についても気にしておくと良いと思います。処理の並列性とか。

## 学習の指針
### 好きな用途に絞る
これは個人差あると思いますが、
シェーダーは前述したように用途が広くその分情報も多く、知識と知識が結びつきづらい場合も少なくないように感じます。C#に比べて所謂"おまじない"的な記述も最初は多く感じてモヤモヤする部分もあります。
去年の僕は色んな領域について調べたり"おまじない"について調べたりを同時並行して情報過多な割に要領を得ずﾜｶﾗﾝ...ってなったので、焦らず今勉強している事について何か収穫があればそれを一個ずつ吸収していく方が良いように思います。"おまじない"も慣れれば分かってくるので、なるべく近い領域のものを勉強して進めるのが良いかもです。

### ググってみてやる
検索すると「○○シェーダーを作ってみた」みたいな記事も多いですし、シリーズになっている記事もいくつかあります。この中から分かりやすそうなものを選んでやる。
慣れてくればUnity以外の環境でのシェーダーも参考にできるようになりますし、英語圏の資料は丁寧に解説されていたり高品質なものも多いのでおすすめです。
シリーズになってるもので学ぶのが良いと思います。理由は前述したように関連性の低い情報をなるべく省いて着実に学べるからです。

### 本を読む
日本語で書かれたUnityシェーダー専門の書籍は多分すべて下記のリンクにまとめてあります。
基本的な内容を解説しているものから応用的な作例の解説をしているものもあります。これらを読むのも良いと思います。一度読むとアレについてはあの本に書いてあるみたいな感じで辞書みたいになるのでそういう意味でもおすすめです。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">さっきツイートすると約束したので<br>日本語Unityシェーダー書籍の簡単な紹介資料<a href="https://t.co/gmrx5HEZYU">https://t.co/gmrx5HEZYU</a></p>&mdash; 梶田悠 haruka kajita (@kajitaj63b3) <a href="https://twitter.com/kajitaj63b3/status/1040675338437636096?ref_src=twsrc%5Etfw">2018年9月14日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

これらの本のほとんどは技術同人誌で、技術書典という技術同人誌即売会に合わせて新刊が出ることが多いので著者の方々をSNSでフォローしたり技術書典をチェックするといいです。


### 他の環境も検索対象にする
他の環境のシェーダーもロジックやプログラム自体は参考にできるので関心を持っておくと得られる情報が増えます。
サイトで言えば[shadertoy](https://www.shadertoy.com/)なんかが有名どころですが、レベルが高いものが目立ちます。
他には、僕の観測範囲ではtouchDesigner、openframeworks、WebGL、とかですかね。
他の環境のシェーダーは言語はGLSLが採用されている事が多いです。(Unityはシェーダーの部分はcg/HLSL)なのでGLSLについても少し勉強しておくと他環境のシェーダーも読み易くなります。UnityでもGLSLでシェーダーを書くことはできます。


# 挫折要因
## そもそもプログラミング未経験(VRCユーザー向け)
VRCユーザーは特にこれに当てはまる人が多いと思いますが、Unityでシェーダー開発をする場合はコードを書くかノードベースのツールを使ってGUIで開発するかのどちらかです。
それぞれのメリット・デメリットについて考えてみます。

### ノードベース
ノードベースのツールは下記の3つを目にすることが多いのです。

- shader forge (開発中止になって現在無料)
- amplify shader editor (有料アセット)
- shader graph (Unity公式のツール。VRC用ならこれは現状使えません)

#### メリット
プログラミングの経験が無くてもツールの使い方を覚えれば使える事。学習コストはコードに比べて低いと思います。
視覚的にプログラムを理解しやすい。誰かが作ったシェーダーを理解する時に、視覚的にプログラムを追えると嬉しかったりする。(但し、同じツールで作られたシェーダーでないとツール上でファイルを開けないです。)
難しいこと考えずにポチポチ作れて気楽。

#### デメリット
自由度はコードベースに比べれば下がるので変わった事をやる場合に出来なかったりすることもある。
開発元の動向に左右されることもある。ノードベースのシェーダー開発ツールのshader forgeは開発中止を発表したのですが、その後に別のノードベース開発ツールに移行する開発者も多く見かけます。
複雑なプログラムをノードベースで開発すると寧ろごちゃごちゃして見づらくなったり理解しづらくなったりする。ごちゃごちゃした状態をよくスパゲッティって表現してることありますよね。
コードで作られたシェーダーはツールで開けないので得られる情報はコードに比べれば少ないです。

### コードベース
#### メリット
情報量が多い。
ノードで開発したシェーダーもコードに展開できるのでノードで作ったシェーダーも読める。ただ、ノードで作ったシェーダーはコードに展開するとめちゃくちゃ読みづらい事が頻繁にあるので読みづらい。
ノードで出来て、コードにできない事はない。

#### デメリット
ノードなら内部的によしなにやってくれる部分も自分で書かないといけないのでそういう意味では比較的学習コスト高いかも。

### 補足
プログラミング未経験でコードベースでシェーダーを作れるようになりたい場合は、以下の項目を理解しておけばとりあえず問題ないと思います。

- 型と変数
- 四則演算
- 関数
- if分岐
- for文
- 構造体

これらは細かい部分に違いはありますがシェーダーに限らず大抵のプログラミンにおいて共通の概念なので、Unity使えるわけなので一旦C#で上記の扱いを学んで見るのも良いと思います。シェーダーを通してこれらを学ぶよりC#で学んだ方が良いと思う理由は後述するシェーダーにおけるデバッグの不便さです。

## ドキュメントの状況がよろしくない
シェーダーについて調べると体系的にまとまった資料は少ないように感じます。これが結構つらいなぁと思います。英語のサイトなら体系的にまとまったサイトも見つかりますが日本語情報だと微妙です。Unityのドキュメントもざっくりしていて初学者には優しくないです。
日本語の情報で丁寧に学習するなら前述した本を読むのがいいなと僕は思いました。

## 数学的知識が必要になることがある
シェーダーではベクトル、行列を扱う事が多いです。数学的な分野で言うなら、高校レベルのベクトルと、線形代数でしょうか。
数学が苦手な人はこれが壁になるかもしれないですが、行列はベクトルを一定のルールで別のベクトルに変換するフィルターだと思って入門解説をちゃんと読み進めれば意外とできます。
基本的にはシェーダーで扱う行列は行列の基本的な部分なので線形代数をみっちり勉強する必要はありません。
趣味でシェーダーを触るなら(VRC向けの開発をするなら)、最悪理解しきれなくても使えれば問題ないと思いますし、ノードベースならコードベースより行列を気にする事は少ないです。

## デバッグの難しさ
シェーダー開発をしていて辛いのはデバッグの不便さです。
結論バグの回避策は、こまめに実行して実行結果を確認しながら開発する。拡張アセットを使う。ロジックを小分けにしてそれぞれを単体で実装して挙動を確認する。値は色で出力してみる。とかです。
VSCodeを使っているなら下記のアセットを使うのがおすすめです。
[ShaderlabVSCode](https://assetstore.unity.com/packages/tools/utilities/shaderlabvscode-94653)

シェーダーは、Debug.Log()のようなコンソール出力もないし入力補完などのサポートもデフォルトだとあまり優しくないです。
例えば、以下のようなコードを書いたとします。

```
float  vector  = float3(1,0,1);
```
一行目で3次元ベクトルを宣言したつもりですがコンストラクタはfloat3()ですが、行の先頭でfloatで宣言していてvector変数はベクトルとして機能していないです。ですが、この記述はコンパイルエラーにはならず実行出来ます。当然予想外の実行結果になります。こういう記述ミスは往々にして自分だと気づかず数時間溶けたりしますが、実装したロジックが間違っているのか記述ミスしているのか分からず辛いです。
コードだとこういうデメリットもありますね。
デバッグには気を使いましょう。。。

#僕が勝手に話したい事
ここ一番書くの楽しみにしてたけど疲れてきた...

## シェーダーの知識と作るもののロジックの知識は別
当然といえば当然で筆と絵の具の使い方を知っていれば誰でも絵師になれるなんて事はないのと同じでシェーダーも書き方知ってれば良いモノ作れるってこともないです。
色々なロジックを知っている事が大事だと思っているんすが
個人的に気にしてるキーワードは

- シミュレーション
- CG
- 数学
- ジェネラティブアート
- モーショングラフィック
- デモシーン

とかです。元々ジェネをしていたのでほぼジェネが中心になってますが。
これらの分野のロジックや現象をシェーダーで実装するなどすると面白いもの出来たり完成度上がったりすると思ってます。

SNSやらで見かけたキーワードを逐一メモしておくと良いです。僕は気になったツイートをそのままツイッター上の自分のDMに送信して貯めています。
SNSでシェーダーデベロッパーをフォローするのも刺激にもなりますし、作例や解説を公開してくださっている方もいらっしゃるので得られるものは多くあります。

## 更に勉強する為にできそうなこと
ある程度慣れてくるともっと面白いモノを知りたいと思ってきますが、個人的に高品質な情報源として気にしているのは、海外のデベロッパーのSNSとカンファレンスです。
海外のデベロッパーをSNSで追ってみると日本語で調べてた時には出てこなかったテクニックが出てきて興味深いです。twitterでgame devとかunity3dとかで検索するとデベロッパーを見つけられると思います。pixiv fanboxのようなサービスでシェーダーの解説を公開していたりもするので土下座しながら読んでます。
Unite、GDC、CEDECなどのカンファレンスの講演も実践的な内容があって興味深いです。アーカイブやスライドが公開されている事も多いのでチェックすると良いと思います。

# おわり
なんか実際のシェーダーの解説とか全く書いてなくて面白くない内容になっちゃいましたが、去年の自分、勉強し始めた頃の自分に伝えたい事を書きました。来年の技術書典で記事の最初に貼った作例の解説本を書いてみようにゃん。
情報を公開して下さっている皆さんに土下座しながらこれからも勉強します。ありがとうございます。

明日は、@LinaTsukusu さんの記事になります。