引き続きShaderを勉強していこう
###Semanticsを変えてみる
POSITIONをSV_Positionに変更してみたが失敗してしまった。
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
}
}
}
正しく動くやつ
float4 vert (float4 pos : POSITION) : SV_Position {
![スクリーンショット 2016-09-19 16.32.36.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F67575%2Fd0f9f017-3764-a597-9334-805eec424d0e.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=01c31aa369aeb2ea49f7cdc27da26538)
###UV値をそのままSV_TARGET(COLOR)に
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
}
}
}
uv値を良く理解していると色による特徴を判断することができるのだろうけれどまだよく分からない。。。
return float4(i.uv.xy,0,1);となっているので
uv.xはrgbのr
uv.yはrgbのg
を指しているはず。
手が赤くなっているということは
uv.x => 1に近い => Textureの右側に手が描いてある
uv.y => 0に近い => Textureの下側に手が描いてある
ということか?
確かに右下に手が描いてあった。 :)
なるほどなるほど・・・
###スクリーンスペースのピクセル位置VPOSを使ってみる
フラグメントシェーダーではVPOS Semanticsを使うことでスクリーン上のピクセル位置を取得できるとのこと。
VPOSはシェーダーモデル3.0から搭載された機能なのでpragmaでシェーダー3.0であることを明示する必要があります。
VPOSの型はUNITY_VPOS_TYPEにすること(プラットフォームによってVPOSの型がfloat2だったりfloat4だったりと変化するため、UNITY_VPOS_TYPEというUnityのラッパーを使うことで差分を吸収してくれる)
実際に使ってみると、VPOSとSV_POSITIONの扱いがやっかいでした。
まずは失敗するコードを
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修飾子をつけて対応します。
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
}
}
}
これで正常にコンパイルが通るようになりました。
![スクリーンショット 2016-09-19 17.07.46.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F67575%2F24a1e5f8-ae51-9d73-4caf-da6a69b8a7ec.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=95128fd7c137e6bf2c603faec1cc71be)
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 ,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
}
}
}
真ん中くらいにいるとき
![スクリーンショット 2016-09-19 17.15.35.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F67575%2F9466cc94-9d45-0ecf-3be7-05ba55657802.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=5e62d687962779e7c20a54ae9ecd3494)
面白い。
###VPOSとTextureを合わせてみる
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
}
}
}
![スクリーンショット 2016-09-19 17.19.02.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F67575%2Fbb9a5a6c-2727-035c-d1ae-12b0d75757ee.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=2168278c03f7479a14fe243edeb50b00)
ポイント
vposを正規化 => 0 ~ 1にする
vpos.xy /= _ScreenParams.xy;
_ScreenParams組み込み変数を使うことでスクリーンのwidthとheightを取得できる。
それを使ってvpos.xyを割ることでvpos.xyが0~1に正規化できる。
0~1になると色として扱いやすい。
###vposを使ってドット表現
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
}
}
}
![スクリーンショット 2016-09-19 17.46.43.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F67575%2F9f4c5676-28a6-b73b-a1e5-8c3a0ed53c4f.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=b677869b83ddcbe3480f786969b7c0c6)
ポイント
ピクセル位置によってtextureの色を返したり,黒色を返したりしてる。
###vposを使ってドット表現2
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);
}
![スクリーンショット 2016-09-19 17.57.01.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F67575%2F9c056a41-875b-38cc-5947-8d337c2af3ac.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=79bc1c98adca0f3c766db8b564ad90a5)
clipは組み込み関数で引数の値が0未満だった場合にfragmentの処理をスキップします。