GameTech/URP 渲染实战
源码 / shaders/Ch01/PerspectiveInterp.glsl
shaders/Ch01/PerspectiveInterp.glsl
// 第 1 章 案例 1.4:透视校正插值 vs 仿射插值
// 同一份 UV,一份用默认插值(透视校正),一份加 noperspective 修饰(屏幕空间线性插值),
// 用 _Affine 选择用哪一份去采样棋盘格。
// (GLSL 版)WebGL2 的 GLSL ES 3.00 没有 noperspective 修饰符,这里用等价的写法模拟:
// 顶点里输出 uv·w 和 w 两个(默认透视校正插值的)变量,片元里相除,结果正好是屏幕空间线性插值。
Shader "Cookbook/Ch01/PerspectiveInterp"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }

        Pass
        {
            Name "Interp"
            Tags { "LightMode"="UniversalForward" }
            Cull Off

            GLSLPROGRAM
            uniform sampler2D _MainTex;
            uniform float _Tiling;
            uniform float _Affine;

            VARYING vec2 uv;            // 默认:透视校正插值
            VARYING vec2 uvAffineW;     // noperspective 的模拟:uv × w
            VARYING float clipW;        //                      w

            #ifdef VERTEX
            void main()
            {
                gl_Position = TransformObjectToHClip(positionOS.xyz);
                uv = texcoord0.xy * _Tiling;
                uvAffineW = texcoord0.xy * _Tiling * gl_Position.w;
                clipW = gl_Position.w;
            }
            #endif

            #ifdef FRAGMENT
            void main()
            {
                // 透视校正插值后 (uv·w) / w 的结果 = uv 在屏幕空间里线性插值(PS1 时代的效果)
                vec2 uvAffine = uvAffineW / clipW;
                vec2 st = _Affine > 0.5 ? uvAffine : uv;
                fragColor = texture(_MainTex, st);
            }
            #endif
            ENDGLSL
        }
    }
}