【Unity】【シェーダ】ビルトインのディザ抜き用テクスチャを使ってお手軽ディザ抜き

f:id:halya_11:20180728125307g:plain

以前Unityのビルトインのディザ抜き用テクスチャを取得しました。

light11.hatenadiary.com

今回はこれを使って実際にディザ抜きしてみます。

Unity2017.4.1

ディザ抜き?

ディザ抜き自体は他の記事で説明しているので下記を参照してください。

light11.hatenadiary.com

シェーダ(_DitherMaskLOD2D版)

まずはシェーダを書いてみます。

Shader "Sample"
{
    Properties
    {
        _Alpha ("Alpha", Range(0.0, 1.0)) = 1.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

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

            struct appdata
            {
                float4 vertex : POSITION;
            };
            
            struct v2f
            {
            };

            sampler2D _DitherMaskLOD2D;
            half _Alpha;
            
            v2f vert (appdata v, out float4 vertex : SV_POSITION)
            {
                v2f o;
                vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            
            fixed4 frag (v2f i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target
            {
                // 4px x 4pxのブロック毎にテクスチャをマッピングする
                vpos *= 0.25;
                // ディザテクスチャのheightは4*16pxなので小数部分を16で割る(0.0625 = 1/16)
                // これでyは0 ~ 1/16の値を取る
                vpos.y = frac(vpos.y) * 0.0625;
                // Alphaに応じてyにオフセットを加える
                // Alphaが1のときはyが0.9375~1の値を取るように(0.9375 = 1 - 1/16)
                vpos.y += _Alpha * 0.9375;

                // ディザの値はAチャンネルに格納されている
                clip(tex2D(_DitherMaskLOD2D, vpos).a - 0.5);
                return 1;
            }
            ENDCG
        }
    }
}

少し複雑なのでコメントを少し細かく書いておきました。

DitherMaskLOD2Dがビルトインシェーダ内で使われている様子はUnity.cgincで見ることができます。
また、それを見ると
Alphaに0.9375を掛けていませんが、掛けないとうまくいきません。
(Unity.cgincのほうは事前計算されている?)

_DitherMaskLOD2Dがどんなテクスチャかを見たい方は下記の記事を参照してください。

light11.hatenadiary.com

シェーダ(_DitherMaskLOD版)

_DitherMaskLODという3Dテクスチャを使っている部分もあったので、
こちらを使ったソースコードも載せておきます。

Shader "Sample"
{
    Properties
    {
        _Alpha ("Alpha", Range(0.0, 1.0)) = 1.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

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

            struct appdata
            {
                float4 vertex : POSITION;
            };
            
            struct v2f
            {
            };

            sampler3D _DitherMaskLOD;
            half _Alpha;
            
            v2f vert (appdata v, out float4 vertex : SV_POSITION)
            {
                v2f o;
                vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            
            fixed4 frag (v2f i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target
            {
                // 4px x 4pxのブロック毎にテクスチャをマッピングする
                vpos *= 0.25;

                // ディザ用テクスチャは4px x 4px x 16px
                clip(tex3D(_DitherMaskLOD, float3(vpos.xy, _Alpha * 0.9375)).a - 0.5);
                return 1;
            }
            ENDCG
        }
    }
}

こっちのほうが楽かも?
ちなみにUnityStandardShadow.cginc内で使われています。

結果

上記のシェーダを適当なCubeに適用してみます。

f:id:halya_11:20180728125307g:plain

正常にディザ抜きができました。

関連

light11.hatenadiary.com

light11.hatenadiary.com

light11.hatenadiary.com