[Unity]Spriteの明度を真っ白まで上げられるシェーダーを用意する


はじめに

Unityで表示させたSpriteの明度を変えたい場合、シェーダーを使えばいろいろいじれるのですが

  • デフォルトで設定されているマテリアル(Sprites-Default)ではシェーダーがいじれない
  • シェーダー(Sprites/Default)がいじれるようになっても暗くはできるが明るくはできない

ということがあり苦戦しました。
内容はかなりシンプル && ネット上に同じような内容がありますが、自分なりの備忘録として残します。

環境

  • Unity: 2019.3.0f6 64bit

書いた内容

  • やりたかったこと
  • やったこと(ビルトインシェーダーを編集して自前のシェーダーを作成・適用した手順)

やりたかったこと

Unityでちょっとした画像(Sprites)を表示させたのですが、これを状況に応じてブラックアウト・ホワイトアウトさせたいと思いました。

やったこと

◆シェーダーがいじれない問題
画像の明度を変えるにはシェーダーをいじればいい、というようなことを見かけたので早速いじってみようとしたのですが…そもそもシェーダーがいじれませんでした。

対策:
どうやらデフォルトのマテリアル(Sprites-Default)ではシェーダーがいじれないようです。
おとなしく別のマテリアルを作成・アタッチしたところ、Sprites-Defaultをいじれるようになりました。

◆暗くはできるが明るくできない問題
実際にSprites-Defaultでカラーピックをいじってみたところ、画像を暗くはできるのですが明るくはできませんでした。
(RGB値マックスで元画像と同じ状態)

Spriteを元画像以上に明るくするにはSprites-Defaultではだめなようです。

対策:
Unityのビルトインシェーダーを参考に、自前のシェーダーを用意すればよいとのことです。
以下手順です。

1.Unityダウンロードアーカイブで任意のバージョンのビルトインシェーダーのソースコードを入手する

自分の環境に近いバージョンのものをDLすればおそらく問題ないと思います。
(少なくとも今回の件については)

2.Sprites-Defaultのソースコードを見つけて編集する
ここで少しつまづきました。
ネット上の記事(例えばこちら)を見てみると
「"DLしたバージョン\DefaultResources\Sprites-Default.shader"のfixed4 frag(v2f IN) : COLORを編集する」
というような内容が見つかったのですが
・自分がDLしたバージョン(Unity2019.3.10f1)ではDefaultResources以下にSprites-Default.shader が無い
  →DefaultResourcesExtra にいました
   (DefaultResourcesとDefaultResourcesExtraの区別って何なんでしょうね…?)
・Sprites-Default.shader の中に編集すべき関数がない
  →#include "UnitySprites.cginc" に実体があるので必要な部分をフック(?)する必要がある
というような違いがありました。

実際に編集した内容は以下の通りです。

Sprites-Default.shader
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

Shader "Sprites/Default"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
        [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
        [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
        [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
        [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
        [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Cull Off
        Lighting Off
        ZWrite Off
        Blend One OneMinusSrcAlpha

        Pass
        {
        CGPROGRAM
            #pragma vertex SpriteVert
            #pragma fragment SpriteFrag
            #pragma target 2.0
            #pragma multi_compile_instancing
            #pragma multi_compile_local _ PIXELSNAP_ON
            #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
            #include "UnitySprites.cginc"
        ENDCG
        }
    }
}

上記ソースコードに対し、Shaderの名前変更およびCGPROGRAM内の変更を行いました。

変更箇所1
Shader "Sprites/Default_Custom"
変更箇所2
        CGPROGRAM
            #pragma vertex SpriteVert
            #pragma fragment SpriteFrag_Custom  // 呼び出される関数を変える
            #pragma target 2.0
            #pragma multi_compile_instancing
            #pragma multi_compile_local _ PIXELSNAP_ON
            #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
            #include "UnitySprites.cginc"

            // 基本的にはUnitySprites.cgincからコピー
            sampler2D _MainTex_Custom;
            fixed4 SpriteFrag_Custom(v2f IN) : SV_Target
            {
                // とりあえず指定色をかける
                fixed4 c = SampleSpriteTexture(IN.texcoord) * _Color;
                // 指定色のRGB各値が0.5なら元の色、0.5を超えると白に近づくように調整
                c.rgb = c.rgb * 2.0 + max(fixed3(0,0,0), _Color.rgb - 0.5) * 2.0;
                c.rgb *= c.a;
                return c;
            }
        ENDCG

変更したファイルは"Sprites_Custom_fadeBW.shader"という名前で保存しました。
※BW=ブラックホワイト(ポケモンっぽい)

3.実際に適用
あとは単純に、上記シェーダーをプロジェクトに追加→デフォルト以外のマテリアルでシェーダー選択します。
シェーダーのカラーピックを変更してRGB値を上げると画像が白くなります。
これでやりたいことは達成できました。

最後に

シェーダーというものに初めて触れました。(正確には初めて中身をいじりました)
今回いじる範囲についてはできるだけ理解して対応できたとは思いますが、シェーダーというものは非常に奥の深い世界だということも感じました…。
いずれはもっと理解を深めて、自らの作品の表現力をアップさせられる実力をつけたいところです。

以上です。