アヒルのある日

株式会社AHIRUの社員ブログです。毎週更新!社員が自由に思いついたことを書きます。

ポケットずかんに塗り絵機能追加!

こんにちは、ちゃらいプログラマです。 弊社で開発/運用しているスマートフォンアプリの「ポケットずかん」に塗り絵機能が追加されました。

f:id:charai_ahiru:20210721190912j:plain

技術研究の名目で2回ほど記事を書かさせて頂きましたが製品版にするにあたり色々試行錯誤をしました。
以前は
1.画面タッチした箇所の色を塗りつぶしたい色で塗りつぶす (塗りつぶし機能)
2.画面ドラッグ開始した箇所の色のみを指定した色で指定した太さで塗る(塗り機能)
でしたが製品版にするにあたり
3.消しゴム機能の追加
を行いました。

また、以前は画面タッチした座標の現在のピクセルカラーを基準としていましたが 製品版では、画面タッチした座標の基礎画像のピクセルカラーを基準とするように変更しています。

以前記事で書いたシェーダーと基礎部分は大きく変わっていませんが消しゴム機能が追加になったので拡張されています。

Shader "Custom/PaintShader"
{
    Properties
    {
        // RenderTextureが割り当てられる
        _MainTex("Texture", 2D)                         = "white" {}
        // 基礎画像が割り当てられる
        _BaseTex("Texture", 2D)                         = "white" {}
        // 出力カラー
        _OutColor("OutColor", Color)                    = (1,1,1,1)
        // 開始ブラシ情報
        // xy値:ブラシ座標
        // z値:ブラシ種類(0:太い線,1:細い線,2:塗りつぶし,3:消しゴム)
        // w値:1で塗る
        _StartBrush("StartBrush", Vector)               = (0,0,0,0)
        _CurrentBrush("CurrentBrush", Vector)           = (0,0,0,0)
        // ブラシ半径
        _BrushRadius("BrushRadius", Range(0.01, 0.1))   = 0
    }

    SubShader
    {
        Tags
        {
            "Queue" = "Transparent"
            "RenderType" = "Transparent"
        }

        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata_t
            {
                float4 vertex   : POSITION;
                float2 uv       : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                float2 uv       : TEXCOORD0;
            };

            sampler2D   _MainTex;
            sampler2D   _BaseTex;
            fixed4      _OutColor;
            fixed4      _StartBrush;
            fixed4      _CurrentBrush;
            float       _BrushRadius;

            // 頂点シェーダー
            v2f vert( appdata_t v )
            {
                v2f o;
                o.vertex = UnityObjectToClipPos( v.vertex );
                o.uv = v.uv;
                return o;
            }

            // フラグメントシェーダー
            fixed4 frag( v2f i ) : SV_Target
            {
                fixed4 col      = tex2D( _MainTex, i.uv );
                fixed4 baseCol  = tex2D( _BaseTex, i.uv );
                fixed4 uvCol    = tex2D( _BaseTex, _StartBrush.xy );

                // 塗る/塗らない判定
                float inCol = (1.0 - abs(sign( uvCol.g - baseCol.g ))) - baseCol.r;

                inCol = _StartBrush.w   == 1.0 ? inCol                                                                      : 0.0;
                inCol = _CurrentBrush.z != 2.0 ? step(distance(i.uv, _CurrentBrush.xy), _BrushRadius) * inCol               : inCol;

                // 出力カラー設定
                float fill = 1.0 - abs(sign( 1.0 - col.a ));
                fixed4 outLineCol  = fixed4( 0,0,0,1 );
                fixed4 outBaseCol  = fill == 1.0            ? col               : fixed4( 1,1,1,1 );
                fixed4 outBrushCol = _CurrentBrush.z == 3.0 ? fixed4( 1,1,1,1 ) : _OutColor;

                return ((baseCol.r >= 1.0) ? outLineCol : outBaseCol) * abs(1.0 - inCol) + outBrushCol * inCol;
            }

            ENDCG
        }
    }
}

実行するとInspecterは以下のようになります。
f:id:charai_ahiru:20210721200216p:plain

無事製品版に落とし込めてよかった・・・
ではまた次回!