ミップマップのLODレベルによって処理を振り分ける

環境

Unity2021.2.18f1

概要

処理の重いシェーダを作成するときにミップマップのLODレベルで処理を切り替えたい事があります。 そんな場合は、CalculateLevelOfDetailを使用します。

このシェーダはLODレベルに応じてカラーを変えているだけのものです。

Shader "Custom/MipmapLodVisualize"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    CGINCLUDE
    #pragma target 4.5
    #include "UnityCG.cginc"
    #define UNITY_LOD_TEX2D(tex,coord) tex.CalculateLevelOfDetail(sampler##tex,coord)
    #define UNITY_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) tex.SampleGrad(sampler##tex,coord,dx,dy)
    ENDCG

    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

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

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

            Texture2D _MainTex;
            SamplerState sampler_MainTex;
            float4 _MainTex_ST;
            float4 _MainTex_TexelSize;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float mipLevel;
                float mipLevelInt;
                float mipLevelFrac;
                float2 dx, dy;
#if 0   //ポイントサンプルなら合う。こちらを使いたい場合もあるかも
                float2 texCoordsPerSize = i.uv * _MainTex_TexelSize.zw;
                float2 dxSize, dySize;
                float4(dxSize, dx) = ddx(float4(texCoordsPerSize, i.uv));
                float4(dySize, dy) = ddy(float4(texCoordsPerSize, i.uv));
                float minTexCoordDelta;
                float2 texCoords;
                texCoords = dxSize * dxSize + dySize * dySize;
                minTexCoordDelta = max(texCoords.x, texCoords.y);
                mipLevel = max(0.5 * log2(minTexCoordDelta), 0);
#else
                mipLevel = UNITY_LOD_TEX2D(_MainTex, i.uv);
                dx = ddx(i.uv);
                dy = ddy(i.uv);
#endif
                mipLevelFrac = modf(mipLevel, mipLevelInt);

                fixed4 col;
                fixed4 cols[] = {fixed4(1,0,0,1), fixed4(0,1,1,1), fixed4(1,0,1,1), fixed4(0,1,0,1), fixed4(0,0,1,1), fixed4(1,1,0,1), fixed4(1,1,1,1)};
                if(mipLevel > 5)
                    col = fixed4(1,1,1,1);
                else
                {
                    fixed4 col0 = cols[mipLevelInt];
                    fixed4 col1 = cols[mipLevelInt + 1];
                    col = lerp(col0, col1, mipLevelFrac);
                }
                return col;
                //return UNITY_SAMPLE_TEX2D_GRAD(_MainTex, i.uv, dx, dy);
            }
            ENDCG
        }
    }
}

参考

textureQueryLod/CalculateLevelOfDetail in Fragment Shader - Unity Answers