NinaLabo

個人ゲーム開発者の技術メモ

【memo6】フラグメントシェーダーで四角形を描く(Unity)

【今日のまとめ】

・足しても掛けても四角形は描ける模様

 

------------------------------------

Unity でゲームは作っていますが、Shader も 画像処理も初心者です。

アウトプットばかりだと腐っていくので、毎日1時間程度は自分の知らないことを少しずつインプットしていこうかと思ってます。

タイトルに【memo】とあるものはほぼ自分用の備忘録なので他の記事よりも殴り書きなのはご容赦ください。

------------------------------------

 

 

前回は黒い円を描きました。

f:id:ninagreen:20180919192749p:plain

「まる」の次は「さんかく」を描きたい!と思ったのですが、どう書いたら良いかよくわらかなかったのでまずは簡単そうな四角にしたいと思います。

 

前回のstep関数を使えばできそう。 

            float4 frag_test (v2f_img i) : SV_Target
            {
                float d = step(i.uv.x, 0.2) + step (0.8, i.uv.x) + step(i.uv.y, 0.2) + step (0.8, i.uv.y);
                return d;
            }

 

四角形の周囲の領域 (x <= 0.2 || x >= 0.8|| y <= 0.2 || y >= 8) が 1以上(白)になるように足してみました。一応うまくいってるっぽい。

f:id:ninagreen:20180920193857p:plain

 

あ、いやよく見ると、隅の部分がなんかはみ出してて汚い。clamp しないとダメですかね。

float4 frag_test (v2f_img i) : SV_Target
{
    float d = clamp(step(i.uv.x, 0.2) + step (0.8, i.uv.x) + step(i.uv.y, 0.2) + step (0.8, i.uv.y), 01);
    return d;
}

綺麗になった!

f:id:ninagreen:20180920195227p:plain

 

もう少し簡潔に書けそうです。

 step関数にはfloatNのvector型を渡すこともできて、それぞれのpropertyごとに計算してくれるっぽいです。

            float4 frag_test (v2f_img i) : SV_Target
            {
                float2 d = step(i.uv, float2(0.20.2)) + step (float2(0.80.8), i.uv);
                return clamp(d.x + d.y, 01);
            } 

 というか、xもyも同じ値であればこうするほうがもっと簡潔かも。

            float4 frag_test (v2f_img i) : SV_Target
            {
                float2 d = step(i.uv, 0.2) + step (0.8, i.uv);
                return clamp(d.x + d.y, 01);
            }

 

黒い四角じゃなくて青い四角もできますね

            float4 frag_test (v2f_img i) : SV_Target
            {
                float2 d = step(i.uv, 0.2) + step (0.8, i.uv);
                return d.x + d.y >= 1 ? 1 : float4(0011);
            }

f:id:ninagreen:20180921184223p:plain

 

 調べてたら、四角形を書いているコードを他にも発見

nn-hokuson.hatenablog.com

 

まったく別のアプローチですね。まず、こういう画像を作って、

            float4 frag_test (v2f_img i) : SV_Target
            {
                fixed2 size = fixed2(0.3,0.1); // 中心の四角形のサイズ(横、縦の長さ)を定義

 

                 // 四角形の左下の座標を取得(中心座標からサイズの半分をマイナスした箇所)
                fixed2 leftbottom = fixed2(0.5,0.5) - size * 0.5;

 

                // leftbottom <= i.uv ならば1 (四角形の左下座標より右上にいる場合は白にする)
                fixed2 uv = step(leftbottom, i.uv); 

 

                return uv.x*uv.y; // x=1&&y=1の場合のみ塗りつぶす
            }

f:id:ninagreen:20180921185437p:plain

 

こういうコードで上下左右した画像ができるから、

           float4 frag_test (v2f_img i) : SV_Target
            {
                fixed2 size = fixed2(0.3,0.1);
                fixed2 leftbottom = fixed2(0.5,0.5) - size * 0.5;
                fixed2 uv = step(leftbottom, 1 - i.uv); // 1 - i.uv にすると上下左右反転できる
                return uv.x*uv.y;
            } 

f:id:ninagreen:20180921185626p:plain

 

それを掛け算で掛け合わせると四角ができますってことだと思う

            float4 frag_test (v2f_img i) : SV_Target
            {
                fixed2 size = fixed2(0.3,0.1);
                fixed2 leftbottom = fixed2(0.5,0.5) - size * 0.5;
                fixed2 uv = step(leftbottom, i.uv);
                uv *= step(leftbottom, 1 - i.uv);
                return uv.x*uv.y;
            }

f:id:ninagreen:20180921185834p:plain

 

最後反転すれば白い背景の黒い四角になりますね

            float4 frag_test (v2f_img i) : SV_Target
            {
                fixed2 size = fixed2(0.3,0.1);
                fixed2 leftbottom = fixed2(0.5,0.5) - size * 0.5;
                fixed2 uv = step(leftbottom, i.uv);
                uv *= step(leftbottom, 1 - i.uv);
                return 1 - uv.x*uv.y;
            }

f:id:ninagreen:20180921190017p:plain

 

 他にも色々なアプローチがありそうですが、四角形はひとまずここまで。