【Unity】【シェーダ】ビルトインのディザ抜き用テクスチャを取得する

Unityのビルトインシェーダをみていると、どうやら内部的にディザ抜き用のテクスチャをもっていることがわかります。
これを使えたら便利そうなのでどんなテクスチャなのか見てみます。

ディザ抜き用テクスチャを描画するシェーダ

ディザ抜き用テクスチャは_DitherMaskLOD2Dという名前のようです。
まずはこれをサンプリングするシェーダを書きます。

アルファ値に値が格納されているようなので、わかりやすいようにRGBに出力しています。

Shader "UnityDither"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }

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

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
   
            sampler2D _DitherMaskLOD2D;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                float value = tex2D(_DitherMaskLOD2D, i.uv).a;
                return half4(value, value, value, 1);
            }
            ENDCG
        }
    }
}

png

次にこれをスクリプトpngに変換します。
ビルトインシェーダをみる限りディザテクスチャのサイズは横4px、縦4*16pxっぽいのでこのサイズのテクスチャに格納します。

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;

public class DitherCreator
{
    [MenuItem("Assets/Create Dither Texture")]
    private static void CreateDitherTexture()
    {
        // RenderTextureにUnityのDitherテクスチャをレンダリングする
        var rt = RenderTexture.GetTemporary(4, 4 * 16);
        Graphics.Blit(rt, rt, new Material(Shader.Find("UnityDither")));

        // RenderTextureからテクスチャを作る
        var currentRT = RenderTexture.active;
        RenderTexture.active = rt;
        var texture = new Texture2D(rt.width, rt.height);
        texture.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
        texture.Apply();
        
        // テクスチャを保存する
        var bytes = texture.EncodeToPNG();
        System.IO.File.WriteAllBytes("Assets/dither_tex.png", bytes);
        AssetDatabase.Refresh();

        // 元に戻す
        RenderTexture.active = currentRT;
        RenderTexture.ReleaseTemporary(rt);
    }
}
#endif

とりあえずAssets直下に適当に保存してます。
Projectビューの右クリックからCreate Dither Textureを選択するとdither_texという名前のテクスチャが作成されます。

結果

このようなテクスチャが得られます。

f:id:halya_11:20180726014507p:plain

結果は正しそうですが、あまりに小さいので拡大してみます。

f:id:halya_11:20180726014603p:plain

これのV座標を変えて透過度に応じた4pxを取得してディザ抜きするわけです。
実際にディザ抜きに使ってみる記事は別で書こうと思います。

関連

light11.hatenadiary.com

light11.hatenadiary.com