2014年12月21日日曜日

【Unity】 Shaderはじめました。その2

それじゃ続きをやっていきましょう。
Syntax Highlighter を導入してみたからコードがちょっとは見やすくなってるかな?

ここのVignettingからスタートします。









Shader "Custom/WindowCoordinates/Vignetting" {
    SubShader {
        Pass {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0
            #include "UnityCG.cginc"
            float4 vert(appdata_base v) : POSITION {
                return mul (UNITY_MATRIX_MVP, v.vertex);
            }
            float4 frag(float4 sp:WPOS) : COLOR {
                float2 wcoord = sp.xy/_ScreenParams.xy;
                float vig = clamp(3.0*length(wcoord-0.5),0.0,1.0);
                return lerp (float4(wcoord,0.0,1.0),float4(0.3,0.3,0.3,1.0),vig);
            }
            ENDCG
        }
    }
}


どでかい Plane にシェーダをはっつけて配置してみました。下の画像は Plane 2枚。
スクリーンの真ん中らへんが色づきます。Vertexシェーダについては特別なことは何一つしてませんね。 : WPOS あたりがわからない場合前回の記事を見てください。


■ clamp(3.0*length(wcoord-0.5),0.0,1.0)

clamp (float value, float min, float max)
value を入力し、その値が min より小さければ min を、max より大きければ max を返す。

vig = 1.0 でピクセルはグレーになります。lerp() の効果ですね。


■ lerp(x, y, s)

ここ。 x が始点、y が終点、 s がどれだけ近づけるか。
lerpはUnityのc#でも頻繁に使いますね。



なんだかいまいちわかりにくいですねぇ。なぜ真ん中に色がつくのか。

float vig = clamp(3.0*length(wcoord-0.5),0.0,1.0);

この -0.5 を変えてみましょう。


-0.0




-0.25




-0.75





なんとなーくわかってきたでしょうか?
実際に数値を入れて考えてみるとわかりやすいかもしれません。
length(wcoord-hoge) の値がゼロに近ければ近いほど色づくんです。

length(wcoord-0.5) でスクリーンど真ん中 wcoord = (0.5, 0.5) の場合、vig はゼロになります。length(0.0, 0.0) はゼロです。
すると return lerp (float4(0.5, 0.5, 0.0, 1.0), float4(0.3, 0.3, 0.3, 1.0), 0.0) となり、画面中央の色にはfloat4(0.5, 0.5, 0.0, 1.0)が適用され暗い黄色になるわけです。
wcoord = (0.0, 0.0) 左上端のピクセルについては length(-0.5, -0.5)
となってしまい3倍すれば vig は 1.0 を軽く超えます。なのでグレーになってしまうのです。

同じように length(wcoord-0.75) で最も明るい部分の wcoord は (0.75, 0.75) ですね。発色は float4(0.75, 0.75, 0.0, 1.0) となりますので先ほどより明るい黄色になります。

それじゃ次いってみましょう。







Shader "Custom/WindowCoordinates/CirclesMask" {
    Properties {
        _CirclesX ("Circles in X", Float) = 20
        _CirclesY ("Circles in Y", Float) = 10
        _Fade ("Fade", Range (0.1,1.0)) = 0.5
    }

    SubShader {
        Pass {

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0

            #include "UnityCG.cginc"

            uniform float _CirclesX;
            uniform float _CirclesY;
            uniform float _Fade;

            float4 vert(appdata_base v) : POSITION {
                return mul (UNITY_MATRIX_MVP, v.vertex);
            }

            float4 frag(float4 sp:WPOS) : COLOR {
                float2 wcoord = sp.xy/_ScreenParams.xy;
                float4 color;
                if (length(fmod(float2(_CirclesX*wcoord.x,_CirclesY*wcoord.y),2.0)-1.0)<_Fade) {
                    color = float4(sp.xy/_ScreenParams.xy,0.0,1.0);
                } else {
                    color = float4(0.3,0.3,0.3,1.0);
                }
                return color;
            }
            ENDCG
        }
    }
}


■ Properties

ここにある変数は Mono側ではなく Unity側の Inspector でいじれるようになります。
ここで宣言したものはもう一度 Pass 内で宣言する必要があります。



うーん…特に目新しいことがないです。

if (length(fmod(float2(_CirclesX*wcoord.x,_CirclesY*wcoord.y),2.0)-1.0)<_Fade)

こういう条件式使えばパンチングできますよ。ってだけですね。やってることは Bars とほとんど同じです。
Inspectorでいろいろいじってみてください。_Fade が数値入力じゃないのが少し面白いかな。次。







Shader "Custom/TextureCoordinates/Base" {
    SubShader {
        Pass {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0
            #include "UnityCG.cginc"

            struct vertexInput {
                float4 vertex : POSITION;
                float4 texcoord0 : TEXCOORD0;
            };

            struct fragmentInput{
                float4 position : SV_POSITION;
                float4 texcoord0 : TEXCOORD0;
            };

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

            float4 frag(fragmentInput i) : COLOR {
                return float4(i.texcoord0.xy,0.0,1.0);
            }

            ENDCG
        }
    }
}


またグラデーションです。ただ今回はテクスチャ座標に : WPOS など使っていないので Plane 一枚で完結します。Cube にこのシェーダを適用しても似たようなかんじになります。
左下だけ比較用に CirclesMask を適用しています。

説明することがない…
struct vertexInput を Vertexシェーダ vert の入力に使っていて、vert が吐き出す fragmentInput o をFragmentシェーダの入力に使ってますねー texcoord0はそのまま流用してますねー ってかんじです。




これ以降のものですが…

ChessOpt は RGBa の値に bool値を入れられるということを示しています。
最後の return の RGBa を適当に p, q で置き換えるとちょっといいかんじなものが作れたりします。

Mandelbrot Fractal についてはやる気にならないので(やたら細かい計算をしているだけなので)やりません。


とりあえず Vertex/Fragmentシェーダの基本の『き』ぐらいはできたのかな?できてればいいんですが。

0 件のコメント:

コメントを投稿