GameTech/URP 渲染实战
源码 / shaders/Ch29/MipLevelViz.glsl
shaders/Ch29/MipLevelViz.glsl
// 案例 29.6:Mip 级别可视化。用屏幕空间导数估算 GPU 会选哪一级 Mip,并按级别着色。(GLSL 版,对应 Ch29/MipLevelViz.shader)
// 级别越高 = 一个像素覆盖的纹素越多;如果近处也是高级别,说明贴图分辨率给多了(浪费带宽和内存)。
Shader "Cookbook/Ch29/MipLevelViz"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }
        Pass
        {
            Name "MipViz"
            Tags { "LightMode"="UniversalForward" }
            GLSLPROGRAM
            uniform sampler2D _BaseMap;
            uniform vec4 _BaseMap_TexelSize;   // (1/w, 1/h, w, h),由引擎自动设置
            uniform vec4 _BaseMap_ST;
            uniform float _Blend;

            VARYING vec2 uv;

            #ifdef VERTEX
            void main()
            {
                gl_Position = TransformObjectToHClip(positionOS.xyz);
                uv = TransformTex(texcoord0.xy, _BaseMap_ST);
            }
            #endif

            #ifdef FRAGMENT
            float ComputeMipLevel(vec2 uv, vec2 texSize)
            {
                // 相邻像素之间 uv 变化了多少个纹素
                vec2 dx = dFdx(uv * texSize);
                vec2 dy = dFdy(uv * texSize);
                float maxSq = max(dot(dx, dx), dot(dy, dy));
                return 0.5 * log2(maxSq);   // = log2(最大纹素跨度);<0 表示放大(一个纹素盖住多个像素)
            }

            vec3 MipColor(float mip)
            {
                const vec3 c[7] = vec3[7](vec3(0.1, 0.35, 1), vec3(0.15, 0.8, 0.3), vec3(0.95, 0.9, 0.15),
                                          vec3(1, 0.55, 0.1), vec3(0.95, 0.15, 0.1), vec3(0.8, 0.1, 0.7), vec3(0.35, 0.1, 0.5));
                // c[0] 给“放大”区(mip<0),c[1] 起依次是 mip 0,1,2...
                float m = clamp(mip + 1.0, 0.0, 6.0);
                int i = int(floor(m));
                return mix(c[i], c[min(i + 1, 6)], fract(m));
            }

            void main()
            {
                vec3 albedo = texture(_BaseMap, uv).rgb;
                float mip = ComputeMipLevel(uv, _BaseMap_TexelSize.zw);
                fragColor = vec4(mix(albedo, MipColor(mip), _Blend), 1.0);
            }
            #endif
            ENDGLSL
        }
    }
}