【Unity】【シェーダ】Surface Shader入門

# はじめに
・何番せんじとか気にせず、自分の中でこのサイトさえ参照すれば事足りるを作っていきたい。要はチートシート


# ShaderLab
・Unityの全てのファイルシェーダは「ShaderLab」という宣言型言語で記述される。

 > 種類に関係無く、シェーダーのコードの中身は実際にはどれも ShaderLab にラップされています。ShaderLab はシェーダーの構造を整理するのに使われています。以下はその例です。 
ShaderLab シンタックス で ShaderLab シンタックスの基本的な概念について読んでから、以下のチュートリアルに進むことをお勧めします。
[※１](#参考サイト)


## 最小構成コード
```csharp
Shader "Custom/001_ChangeColorShader"
{
    Properties {
        _Color ("Main Color", Color) = (1,.5,.5,1)
    }
    SubShader
    {
        Pass
        {
          Tags{"RenderType"="Opaque" }
          #pragma surface surf Standard fullforwardshadows vertex:vert
          #pragma target 3.0
          ~~  
        }
    }
    SubShader {
        ~~~
    }
    Fallback "Diffuse"
}
```

## Shader
・Materialのインスペクタからシェーダを選択する際に使用される。(下図参照)
・一番外のブロックに記載する。
・「/」を付けることで階層管理できる。
・シェーダファイル名と別の名前を付けてもよいが、分かりづらくなるため統一したほうがいいかも。
・[※２](#参考サイト)

```csharp
　Shader "Custom/001_ChangeColorShader"
```

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505426/083b75f6-40fe-42e4-5c82-96679df49e28.png)

## Properties
・シェーダで使用するパラメタをインスペクタから設定可能にするための定義。
・ColorとVectorはシェーダ内では同じ型「float4」なので、プロパティの型をVectorにして色情報を設定してもエラーにはならない。
　 (分かりづらいのでそうするべきではないが。)
・[※３](#参考サイト)


```csharp:構文
  Properties {
    シェーダ内のパラメタ名 ("インスペクタに表示される文字列", 型) = 初期値
  }
```
```csharp:記述例
    Properties
    {
		// テキスト(整数)
		_Param0 ("Param0", Int) = 0
		// テキスト(小数)
		_Param1 ("Param1", Float) = 1.0
		// スライダ
		_Param2 ("Param2", Range(0.0, 10.0)) = 3.0
		// 色 (RGBA)
		_Param3 ("Param3", Color) = (1.0, 0.5, 1.0, 1.0)
		// ベクタ (XYZW)
		_Param4("Param4", Vector) = (1.0, 0.5, 1.0, 1.0)
		// テクスチャ (デフォルト値は 空文字、白、赤、グレー、バンプ、赤を設定できる。)
		_Param5 ("Param5", 2D) = "white" {}
    }
```
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/505426/857e6933-acea-358c-1c0c-1c0807ed3e3a.png)

## SubShader / Fallback
・SubShaderは複数, Fallbackは一つ定義できる。
・ユーザのPCで動作できる(スペックが満たせている)SubShaderがあればそれを1つ実行する。
・ユーザのPCのスペックが低く、どのSubShaderも実行できない場合、Fallbackシェーダと呼ばれるUnityのデフォルトシェーダを実行する。
・[※２](#参考サイト)

```csharp:構文
    SubShader { ~~~ }
    SubShader { ~~~ }
    Fallback "~~~"
```

## Pass
・SubShader内に複数定義できる。
・１つのPassで１回分の描画を行う。当然Passの定義が多いほど負荷が大きくなる。
・[※２](#参考サイト)

```csharp:構文
    SubShader
    {
      Pass { ~~~ }  
      Pass { ~~~ }
    }
```

## Tags
・シェーダの設定されたオブジェクトを「いつ」「どのように」描画するかを定義する。

### Queue
・描画順序を定義する。(番号の若い順に描画する。)

| 種類 | 使用例 | ソート番号
|:--|:--|:--|
| BackGround  | スカイボックス  | 1000 |
| Geometry  | 不透明オブジェクト  | 2000 | 
| Transparent  | 半透明オブジェクト  | 3000|
| Overlay  | オーバーレイエフェクト  | 4000 |

・プラスすることで描画順序を微調整できる。

```csharp:構文
   Tags {"Queue" = "Geometry+1"} // 2001
```

### Render Type
・まだ理解できていないが以下のお決まりの形で設定する。

| 種類 | 使用例 |
|:--|:--|
| Opaque  | 不透明オブジェクト  |
| Transparent  | 半透明オブジェクト |
```csharp:構文
   Tags {"RenderType" = "Opaque"}
```

## Pragma
### surface
・surface : 自身がsurfaceシェーダであることを宣言する。
・サーフィス関数名 : 使用するサーフィス関数名
・ライティング関数名 : ライティングに使用する関数名。デフォルトはStandard
・バーティクス関数 : フックしたい自作のバーティクス関数名
・オプション : 処理軽減等様々なオプションを指定できる。(詳細については[※7 公式リファレンス](https://docs.unity3d.com/ja/current/Manual/SL-SurfaceShaders.html)参照)

```csharp:構文
    #pragma surface サーフィス関数名 ライティング関数 [オプション] vertex:バーティクス関数
```
```csharp:記述例
    #pragma surface surf Standard fullforwardshadows vertex:vert
```

### target
・コンパイルのレベル
・より高機能な記述をする場合、高いレベルが必要になる
・[※9 公式リファレンス](https://docs.unity3d.com/ja/current/Manual/SL-ShaderCompileTargets.html)

# 変数
・SubShader内で利用する変数の型は、Propertiesのそれと異なる。

## 変数の種類
| 型 | 説明 |
|:--|:--|
| float  | 32ビット浮動小数点数 |
| half  |  16ビット浮動小数点数 |
| fixed  | 11ビット浮動小数点数 |
| float4x4 | 4x4行列  |
| sampler2D | テクスチャ | 

## 変数の操作
・複数のパラメタを保持できる。(「packed array」と呼ぶ。)
fixed3 a; (fixed型の変数を3つ代入できる。)
・fixed3にfixed4の値を代入できる。
o.Albedo =  _Color.rgb;
・変数の入れ替えができる。
o.Albedo = _Color.bgr;
・fixed4に単体の値を代入できる
o.Albedo = 1; //(1, 1, 1)
・行列の特定要素の参照
float4x4 mat;
mat._m12; (1行2列目の値)

# Cg関数, ビルドイン変数/関数
## Cg言語
・Cg言語で定義された関数を使用することができる。
・Cg言語はGPUのハードウェア上に定義されたものでNVIDIA社が作成している。
・[※4 公式リファレンス](http://developer.download.nvidia.com/cg/index_stdlib.html)

| 関数 | 例 | 意味 |
|:--------|:--|:--|
| abs(x) 　　　　　　| abx(-3) = 3 　　　　　　| 絶対値 　　　　 |
| dot(v1, v2) |   | v1とv2の内積  |
| saturate  |  saturate(-1.5) = -1 | -1以下を-1, 1以上を1として -1 ~ 1を返却する。<br> max(0, min(1, x))と同義  |
| pow(x, y)  | pow(3, 4) = 81  |  xのy乗 |
| lerp(x, y, p)  | lerp(1.0, 2.0, 0.1) = 1.1  |  線形補間  (x * p + y * (p - 1)) |
| distance(v1, v2)  |   | 2点間の距離  |
| frac(x) | frac(2.3) = 0.3  | 小数部  |
| floor(y)  | floor(2.3) = 2.0  | 整数部  |
| mul(m1, m2)  |   | 行列の積  |

## Unityが定義するビルドイン変数, 関数
・「Unityのインストールディレクトリ/Editor/Data/CGIncludes」の.cgincファイルをインクルードすることで便利な機能が利用できる。
・例) ライティング関数「Lambert」「BlinnPhong」「Standard」はLighting.cginc, UnityPBSLighting.cgincに定義されている。
・[※5 ビルドイン機能の公式リファレンス](https://docs.unity3d.com/ja/current/Manual/SL-BuiltinMacros.html)
・古いバージョンのビルドインシェーダは[※6 公式サイト](https://unity3d.com/get-unity/download/archive)からダウンロードできる。

## その他
### discard
・レンダリング処理を行わない。

# カスタムシェーダライブラリの作成
1. Unityのプロジェクト内に.cgincファイルを作成する。<br>
（エクスプローラ上で作成し、ドラッグ&ドロップする。）
2. ファイルを下記のように定義する。

```csharp:MyUtility.cginc
#ifndef ANY_UNIQUE_NAME
#define ANY_UNIQUE_NAME
　共通化したい処理
#endif
```
3.利用する側は#includeを使用する。その際のパスは利用側シェーダファイルからの相対パスを設定する。

# 参考サイト

Unity 公式リファレンス
[1. シェーダを書く](https://docs.unity3d.com/ja/2017.4/Manual/ShadersOverview.html)
[2. ShaderLabシンタックス](https://docs.unity3d.com/ja/2017.4/Manual/SL-Shader.html)
[3. ShaderLab: Properties](https://docs.unity3d.com/ja/2017.4/Manual/SL-Properties.html)
[5. 定義済みシェーダープリプロセッサーマクロ](https://docs.unity3d.com/ja/current/Manual/SL-BuiltinMacros.html)
[6. Unity download archive](https://unity3d.com/get-unity/download/archive)
[7. サーフェスシェーダーの記述](https://docs.unity3d.com/ja/current/Manual/SL-SurfaceShaders.html)
[8. ShaderLab ： SubShader 内の Tags](https://docs.unity3d.com/ja/current/Manual/SL-SubShaderTags.html)
[9. シェーダーコンパイルターゲットレベル](https://docs.unity3d.com/ja/current/Manual/SL-ShaderCompileTargets.html)
NVidea 公式リファレンス
[4. Cg 3.1 Toolkit Documentation](http://developer.download.nvidia.com/cg/index_stdlib.html)