ディザインリング - saitocastel1900/UnityShader GitHub Wiki

  • 等間隔でピクセルを歯抜けにすることで、半透明っぽく見せる技術のことらしい
  • ゼルダとかで木とかの障害物がカメラの視界を遮ることを防ぐために使われたりする 
  • 今回は、BayerMatrixパターンで実装してみる
  • キーになりそうなコードは「 float2 viewPortPos = i.screenPos.xy / i.screenPos.w; float2 screenPosInPixel = viewPortPos.xy * _ScreenParams.xy; 」。カメラ目線でディザリングをしたいので、スクリーン座標をつかって色々したいのですが、問題があります。実際ほしいのは画面単位での座標(1980*1020的な)なのですが、現在の座標(スクリーン座標)は0.0~1.0なので、それを変換したい。なので_ScreenParamsxyには画面サイズが入っているので、これをかけて求めているみたい。
  • あとは、ピクセル単位で描画する・しないをするだけ。今回のディザリングパターンでは4×4を採用しているので、4で割ったあまりを求めて、それを基に配列インデックスを計算して、パターンを求める。「int ditherUV_x = (int)fmod(screenPosInPixel.x,_DitherSize); int ditherUV_y = (int)fmod(screenPosInPixel.y,_DitherSize); float dither = pattern[ditherUV_x+ditherUV_y*_DitherSize]; clip(dither - _DitherLevel);」
Shader "Unlit/DitheringUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _DitherLevel("DitherLevel",Range(0,16)) = 1
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _DitherLevel;

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

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

            static const int pattern[16]=
                {
                0,8,2,10,
                12,4,14,6,
                3,11,1,9,
                15,7,13,5
                };

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.screenPos = ComputeScreenPos(o.vertex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                float2 viewPortPos = i.screenPos.xy / i.screenPos.w;
                float2 screenPosInPixel = viewPortPos.xy * _ScreenParams.xy;

                int ditherUV_x = (int)fmod(screenPosInPixel.x,4.0f);
                int ditherUV_y = (int)fmod(screenPosInPixel.y,4.0f);
                float dither = pattern[ditherUV_x+ditherUV_y*4];

                clip(dither - _DitherLevel);
                
                fixed4 col = tex2D(_MainTex, viewPortPos);
                return col;
            }
            ENDCG
        }
    }
}