Unity でShaderの勉強 その2

引き続きShaderを勉強していこう

###Semanticsを変えてみる
POSITIONをSV_Positionに変更してみたが失敗してしまった。

```lang:失敗例
Shader "Custom/Test1" {
	SubShader {
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			float4 vert (float4 pos : SV_Position) : SV_Position {
				return mul(UNITY_MATRIX_MVP,pos);
			}

			float4 frag() : SV_TARGET {
				return (1,1,1,1);
			}

			ENDCG
		}
	}
}
```

なんだかよく分からないものが描画された・・・
<img width="231" alt="スクリーンショット 2016-09-19 16.31.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/bc03dc56-f8a8-ca22-b111-2d65b7e5f300.png">

正しく動くやつ

```
float4 vert (float4 pos : POSITION) : SV_Position {
```

<img width="214" alt="スクリーンショット 2016-09-19 16.32.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/d0f9f017-3764-a597-9334-805eec424d0e.png">
vert関数の引数のsemanticsをPOSITIONに変更したらちゃんと動いた。
うーん、引数のsemanticsがSV_POSITIONだとsemanticsが間違ってる(存在しない)扱いになるのかな。
SV_POSITIONはvertex変換後のvertex positionだけを指すSemanticsなのかも。

###UV値をそのままSV_TARGET(COLOR)に

```lang:uv2Color
Shader "Custom/Test1" {
	SubShader {
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			struct v2f {
				float4 wpos :SV_POSITION;
				float2 uv : TEXCOORD0;
			};

			v2f vert (float4 pos : POSITION , float2 uv : TEXCOORD0) {
				v2f o;
				o.wpos = mul(UNITY_MATRIX_MVP , pos);
				o.uv = uv;
				return o;
			}

			float4 frag(v2f i) : SV_TARGET {
				return float4(i.uv.xy,0,1);
			}

			ENDCG
		}
	}
}
```

ちょっと綺麗だ
<img width="183" alt="スクリーンショット 2016-09-19 16.39.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/7fe808dc-a1f4-91cc-2867-5e13b8f1ac0b.png">

uv値を良く理解していると色による特徴を判断することができるのだろうけれどまだよく分からない。。。
return float4(i.uv.xy,0,1);となっているので
uv.xはrgbのr
uv.yはrgbのg
を指しているはず。

手が赤くなっているということは
uv.x => 1に近い => Textureの右側に手が描いてある
uv.y => 0に近い => Textureの下側に手が描いてある
ということか？

テクスチャの一部
<img width="188" alt="スクリーンショット 2016-09-19 16.41.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/dff996cb-a9fc-79c1-03ab-66a46edc7b05.png">

確かに右下に手が描いてあった。 :)
なるほどなるほど・・・


###スクリーンスペースのピクセル位置VPOSを使ってみる
フラグメントシェーダーではVPOS Semanticsを使うことでスクリーン上のピクセル位置を取得できるとのこと。
VPOSはシェーダーモデル3.0から搭載された機能なのでpragmaでシェーダー3.0であることを明示する必要があります。
VPOSの型はUNITY_VPOS_TYPEにすること(プラットフォームによってVPOSの型がfloat2だったりfloat4だったりと変化するため、UNITY_VPOS_TYPEというUnityのラッパーを使うことで差分を吸収してくれる)

実際に使ってみると、VPOSとSV_POSITIONの扱いがやっかいでした。

まずは失敗するコードを

```lang:失敗コードVPOS
Shader "Custom/Test1" {
	SubShader {
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0

			struct v2f {
				float2 uv : TEXCOORD0;
				float4 wpos : SV_POSITION;
			};

			v2f vert(float4 pos : POSITION , float2 uv : TEXCOORD0) {
				v2f o;
				o.uv = uv;
				o.wpos = mul(UNITY_MATRIX_MVP,pos);
				return o;
			}

			float4 frag(v2f i , UNITY_VPOS_TYPE vpos : VPOS) : SV_TARGET {
				return (1,1,1,1);
			}


			ENDCG
		}
	}
}
```

一見正しそうに見えますが、エラーが起こります。

エラー内容
> Shader error in 'Custom/Test1': Duplicate system value semantic definition: input semantic 'SV_POSITION' and input semantic 'VPOS' at line 21 (on glcore)

うーん。SV_POSITIONとVPOSは両方同時にはfragmentに渡せないようです。。。
そのためvertex関数でSV_POSITIONを返さずにout修飾子をつけて対応します。

```lang:エラーは起きないやつ
Shader "Custom/Test1" {
	SubShader {
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0

			struct v2f {
				float2 uv : TEXCOORD0;
				//float4 wpos : SV_POSITION;
			};

			v2f vert(float4 pos : POSITION ,out float4 wpos : SV_POSITION ,  float2 uv : TEXCOORD0) {
				v2f o;
				o.uv = uv;
				wpos = mul(UNITY_MATRIX_MVP,pos);
				return o;
			}

			float4 frag(v2f i , UNITY_VPOS_TYPE vpos : VPOS) : SV_TARGET {
				return (1,1,1,1);
			}


			ENDCG
		}
	}
}
```

これで正常にコンパイルが通るようになりました。

<img width="188" alt="スクリーンショット 2016-09-19 17.07.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/24a1e5f8-ae51-9d73-4caf-da6a69b8a7ec.png">

VPOSを使って何かやってみます。

```lang:スクリーン位置によって色を変える
Shader "Custom/Test1" {
	SubShader {
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0

			struct v2f {
				float2 uv : TEXCOORD0;
				//float4 wpos : SV_POSITION;
			};

			v2f vert(float4 pos : POSITION ,out float4 wpos : SV_POSITION ,  float2 uv : TEXCOORD0) {
				v2f o;
				o.uv = uv;
				wpos = mul(UNITY_MATRIX_MVP,pos);
				return o;
			}

			float4 frag(v2f i , UNITY_VPOS_TYPE vpos : VPOS) : SV_TARGET {
				vpos.xy /= _ScreenParams.xy;
				return float4(vpos.xy,0,1);
			}


			ENDCG
		}
	}
}
```

左端にいるとき
<img width="417" alt="スクリーンショット 2016-09-19 17.14.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/c5f1472e-4cd6-18a1-b94d-458be3c0142b.png">

真ん中くらいにいるとき

<img width="435" alt="スクリーンショット 2016-09-19 17.15.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/9466cc94-9d45-0ecf-3be7-05ba55657802.png">

右端にいるとき
<img width="424" alt="スクリーンショット 2016-09-19 17.15.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/c9c140ef-1db4-d062-3f55-2452d47875d9.png">

面白い。


###VPOSとTextureを合わせてみる

```lang:VPOSXTEXTURE
Shader "Custom/Test1" {
	Properties {
		_MainTex("main" , 2D) = "white" {}
	}
	
	SubShader {
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0

			uniform sampler2D _MainTex;

			struct v2f {
				float2 uv : TEXCOORD0;
				//float4 wpos : SV_POSITION;
			};

			v2f vert(float4 pos : POSITION ,out float4 wpos : SV_POSITION ,  float2 uv : TEXCOORD0) {
				v2f o;
				o.uv = uv;
				wpos = mul(UNITY_MATRIX_MVP,pos);
				return o;
			}

			float4 frag(v2f i , UNITY_VPOS_TYPE vpos : VPOS) : SV_TARGET {
				vpos.xy /= _ScreenParams.xy;
				return tex2D(_MainTex,i.uv) * float4(vpos.xy,0,1);
			}


			ENDCG
		}
	}
}
```

<img width="412" alt="スクリーンショット 2016-09-19 17.19.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/bb9a5a6c-2727-035c-d1ae-12b0d75757ee.png">
かわいい。

ポイント
vposを正規化 => 0 ~ 1にする

```lang:vpos正規化
    vpos.xy /= _ScreenParams.xy;
```

_ScreenParams組み込み変数を使うことでスクリーンのwidthとheightを取得できる。
それを使ってvpos.xyを割ることでvpos.xyが0~1に正規化できる。
0~1になると色として扱いやすい。

###vposを使ってドット表現

```lang:ドット表現
Shader "Custom/Test1" {
	Properties {
		_MainTex("main" , 2D) = "white" {}
	}
	
	SubShader {
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0

			uniform sampler2D _MainTex;

			struct v2f {
				float2 uv : TEXCOORD0;
				//float4 wpos : SV_POSITION;
			};

			v2f vert(float4 pos : POSITION ,out float4 wpos : SV_POSITION ,  float2 uv : TEXCOORD0) {
				v2f o;
				o.uv = uv;
				wpos = mul(UNITY_MATRIX_MVP,pos);
				return o;
			}

			float4 frag(v2f i , UNITY_VPOS_TYPE vpos : VPOS) : SV_TARGET {
				if(vpos.x % 1.2 < 0.7) {
					if(vpos.y % 1.2 < 0.7){
						return tex2D(_MainTex,i.uv);		
					}
				} 
				return float4(0,0,0,1);

			}


			ENDCG
		}
	}
}
```

<img width="210" alt="スクリーンショット 2016-09-19 17.46.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/9f4c5676-28a6-b73b-a1e5-8c3a0ed53c4f.png">


ポイント
ピクセル位置によってtextureの色を返したり,黒色を返したりしてる。


###vposを使ってドット表現2

```lang:clipする
			float4 frag(v2f i , UNITY_VPOS_TYPE vpos : VPOS) : SV_TARGET {
				if(vpos.x % 1.2 < 0.7) {
					if(vpos.y % 1.2 < 0.7){
						clip(-1);

					}
				} 

				return tex2D(_MainTex,i.uv);		
			}
```

<img width="437" alt="スクリーンショット 2016-09-19 17.57.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/67575/9c056a41-875b-38cc-5947-8d337c2af3ac.png">

clipは組み込み関数で引数の値が0未満だった場合にfragmentの処理をスキップします。