LoginSignup
20
21

More than 5 years have passed since last update.

Unity でShaderの勉強 その2

Posted at

引き続き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の処理をスキップします。

20
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
21