Unityの超基礎的なShader

主に[凹みtips](http://tips.hecomi.com/entry/2014/03/16/233943) からのコピペですが、自分用にまとめます。

先の記事は情報が多くて理解するのが難しいので、ここでは頂点シェーダー・フラグメントシェーダーの基礎的なコードを書いておきます。



##単色シェーダー
```hlsl
Shader "Custom/SolidColor" {
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            float4 vert(float4 v:POSITION) : POSITION {
                return mul (UNITY_MATRIX_MVP, v);
            }
            fixed4 frag() : COLOR {
                return fixed4(1.0,0.0,0.0,1.0);
            }
            ENDCG
        }
    }
}
```

* #pragmaはよくわからないんですが、ここではvertex,fragmentの関数を指定するものらしい。
* UNITY_MATRIX_MVP というのはあらかじめ定義されている値であり、MVP行列（モデル・ビュー・プロジェクション行列）のこと。そのほかの組み込み変数は[ここ](https://docs.unity3d.com/ja/current/Manual/SL-UnityShaderVariables.html)に書いてある。 
* 「:POSITION」 とはセマンティクスと呼ばれ、その変数が何に使われるかを示す。

### セマンティックの種類は、こんなものがある
* float4	vertex : POSITION
* float3	normal : NORMAL
* float4	texcoord : TEXCOORD0
* float4	texcoord1 : TEXCOORD1	
* float4	tangent : TANGENT
* float4	color : COLOR

[セマンティック参考](http://wiki.unity3d.com/index.php?title=Shader_Code)

##単色シェーダー + 構造体を自分で定義

頂点シェーダー,フラグメントシェーダーの引数には構造体が使える。自分で定義したり、すでにあるものを使ったりできるようだ。#include "UnityCG.cginc"と書くと、あらかじめ用意されてるものが使える。ちなみにUnityCg.incの中身は[こんな感じらしい](https://gist.github.com/hecomi/9580605)。 

以下では、単に頂点シェーダーの入力に自分で定義した構造体を指定している。

```hlsl
Shader "Custom/SolidColor2" {
    SubShader {
        Pass {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            struct appdata_base {
                float4 vertex   : POSITION;
                float3 normal   : NORMAL;
                float4 texcoord : TEXCOORD0;
            };

            float4 vert(appdata_base v) : SV_POSITION {

                float4 p = v.vertex;
                return mul (UNITY_MATRIX_MVP, p);

            }

            fixed4 frag() : COLOR {
                return fixed4(1.0,0.0,0.0,1.0);
            }

            ENDCG
        }
    }
}
```
### UnityCG.cgincで定義されてる構造体appdataは以下

```
struct appdata_base {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
};

struct appdata_tan {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
};

struct appdata_full {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
    float3 normal : NORMAL;
    float4 texcoord : TEXCOORD0;
    float4 texcoord1 : TEXCOORD1;
    fixed4 color : COLOR;
};
```

##テクスチャをつけてみる

Propetiesという所に変数を宣言するとインスペクタより選択できるようになる。以下ではテクスチャを設定できるようにしている。
インスペクタからテクスチャを設定したら、フラグメントシェーダーの中でtex2D関数とuvから色を取得している。

あと頂点シェーダーでreturn（出力）した変数はfragmentへ送られるようだ。以下ではfragmentInputという構造体。glslのvarying変数のように頂点シェーダーからフラグメントシェーダーに値を渡せる。

```hlsl
Shader "Custom/TexColor" {
    Properties {
        //インスペクタに表示する,uniform
        _MainTex("Base (RGB)", 2D) = "white" {}
    }
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct vertexInput {
                float4 vertex : POSITION;
                float2 uv     : TEXCOORD0;
            };

            struct fragmentInput {
                float4 position : SV_POSITION;
                float2 uv       : TEXCOORD0;
            };

            //uniform として宣言
            uniform sampler2D _MainTex;

            fragmentInput vert(vertexInput v) {
                fragmentInput o;
                o.position = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                return o;
            }

            float4 frag(fragmentInput i) : COLOR {
                //インスペクタから入力された _MainTex を使ってる
                return tex2D(_MainTex, i.uv);
            }

            ENDCG
        }
    }
}
```

## 外部からuniform変数をいじる(インスペクタから)

上記サンプルで書いたように、インスペクタからいじりたい場合、[Properties](https://docs.unity3d.com/jp/current/Manual/SL-Properties.html) というところに定義する。使える種類は以下。

* name ("display name", Range (min, max)) = number
* name ("display name", Float) = number
* name ("display name", Int) = number
* name ("display name", Color) = (number,number,number,number)
* name ("display name", Vector) = (number,number,number,number)
* name ("display name", 2D) = "defaulttexture" {}
* name ("display name", Cube) = "defaulttexture" {}
* name ("display name", 3D) = "defaulttexture" {}


## 外部からuniform変数をいじる(Scriptから)

「material.Setなんとか」でuniformを設定できる。

たとえば、こんなふうに

```hlsl
uniform float _Rad;
```

が、定義されてたら、

```csharp
var mat = GetComponent<Renderer>().material;
mat.SetFloat("_Rad", 3.14);
```

あるいは配列もいける。（情報があまりなくてちょっと迷った）

```hlsl
uniform float _Hoge[32];
```

```csharp
var hoge = new float[32];
_mat.SetFloatArray("_Hoge",f);
```


## HLSLの組み込み関数

ここを見る。
https://msdn.microsoft.com/ja-jp/library/bb509611(v=vs.85).aspx

glslとの対応表
https://qiita.com/kitasenjudesign/items/89297f239059662cd38e


## Unityですでに定義されている変数

http://qiita.com/edo_m18/items/591925d7fc960d843afa

* _Time = 時間
* _ScreenParams　= xyはピクセル幅、高さ

など便利。

## サーフェイスシェーダーとは。

頂点・フラグメント（ピクセル）シェーダーは、なんとなくわかった。で、サーフェイスシェーダーとは何なのか。

シェーダーをお手軽に書くもので、細かいことはできないけど、面倒なことは自分で書かなくてすんだりもする。結局最終的にコンパイルされて頂点・フラグメントシェーダーになるようだ。だいたいのブログの情報は先にサーフェイスシェーダーが書いてあって謎で混乱してしまった。