Posted at

Unity でShaderの勉強 その2

More than 3 years have passed since last update.

引き続き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
}
}
}


なんだかよく分からないものが描画された・・・

スクリーンショット 2016-09-19 16.31.45.png

正しく動くやつ

float4 vert (float4 pos : POSITION) : SV_Position {

スクリーンショット 2016-09-19 16.32.36.png

vert関数の引数のsemanticsをPOSITIONに変更したらちゃんと動いた。

うーん、引数のsemanticsがSV_POSITIONだとsemanticsが間違ってる(存在しない)扱いになるのかな。

SV_POSITIONはvertex変換後のvertex positionだけを指すSemanticsなのかも。


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


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
}
}
}


ちょっと綺麗だ

スクリーンショット 2016-09-19 16.39.05.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の下側に手が描いてある

ということか?

テクスチャの一部

スクリーンショット 2016-09-19 16.41.08.png

確かに右下に手が描いてあった。 :)

なるほどなるほど・・・


スクリーンスペースのピクセル位置VPOSを使ってみる

フラグメントシェーダーではVPOS Semanticsを使うことでスクリーン上のピクセル位置を取得できるとのこと。

VPOSはシェーダーモデル3.0から搭載された機能なのでpragmaでシェーダー3.0であることを明示する必要があります。

VPOSの型はUNITY_VPOS_TYPEにすること(プラットフォームによってVPOSの型がfloat2だったりfloat4だったりと変化するため、UNITY_VPOS_TYPEというUnityのラッパーを使うことで差分を吸収してくれる)

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

まずは失敗するコードを


失敗コード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修飾子をつけて対応します。


エラーは起きないやつ

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

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.14.39.png

真ん中くらいにいるとき

スクリーンショット 2016-09-19 17.15.35.png

右端にいるとき

スクリーンショット 2016-09-19 17.15.47.png

面白い。


VPOSとTextureを合わせてみる


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
}
}
}


スクリーンショット 2016-09-19 17.19.02.png

かわいい。

ポイント

vposを正規化 => 0 ~ 1にする


vpos正規化

    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

ポイント

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


vposを使ってドット表現2


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);
}


スクリーンショット 2016-09-19 17.57.01.png

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