GameTech/URP 渲染实战
源码 / shaders/Ch16/BlendModes.glsl
shaders/Ch16/BlendModes.glsl
// 混合模式实验台:源/目标因子和混合运算都做成材质属性,同一个 Shader 切出所有常见模式。(GLSL 版)
// _Output 决定片元输出的形式:直通(rgb, a)/ 预乘(贴图已预乘)/ 乘法就绪(lerp(1, rgb, a))。
Shader "Cookbook/Ch16/BlendModes"
{
    SubShader
    {
        Tags { "RenderType"="Transparent" "RenderPipeline"="UniversalPipeline" "Queue"="Transparent" "IgnoreProjector"="True" }

        Pass
        {
            Name "Blend"
            Tags { "LightMode"="UniversalForward" }
            BlendOp [_BlendOp]
            Blend [_SrcBlend] [_DstBlend]
            ZWrite Off
            Cull Off

            GLSLPROGRAM
            #pragma shader_feature_local_fragment _OUTPUT_STRAIGHT _OUTPUT_PREMULTIPLY _OUTPUT_MULTIPLYREADY

            uniform vec4 _BaseMap_ST;
            uniform vec4 _BaseColor;
            uniform sampler2D _BaseMap;

            VARYING vec2 uv;

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

            #ifdef FRAGMENT
            vec4 frag()
            {
                vec4 tex = texture(_BaseMap, uv);
                vec3 rgb = tex.rgb * _BaseColor.rgb;
                float a  = tex.a * _BaseColor.a;
            #if defined(_OUTPUT_PREMULTIPLY)
                // 预乘:贴图的 rgb 已经乘过 alpha(导出时完成),这里只再乘上材质的不透明度。
                // 于是 rgb 可以“大于” alpha——alpha = 0 而 rgb > 0 的像素就是纯叠加的辉光
                return vec4(tex.rgb * _BaseColor.rgb * _BaseColor.a, a);
            #elif defined(_OUTPUT_MULTIPLYREADY)
                return vec4(mix(vec3(1.0), rgb, a), a);  // 乘法类:透明处输出白色(乘 1 不变)
            #else
                return vec4(rgb, a);                     // 直通
            #endif
            }
            void main() { fragColor = frag(); }
            #endif
            ENDGLSL
        }
    }
}