峰埋姚 发表于 4 天前

【渲染流水线】[逐片元阶段]-[模版测试]以UnityURP为例


[*]用于精确控制像素丢弃的逐片元操作,通过模板缓冲区(8位整数/像素)实现复杂遮罩效果。
[*]支持8种比较函数和6种缓冲操作‌
[*]当前模版操作,只能在Shader文件中书写操作,ShaderGraph中无法直接使用模版指令。
【从UnityURP开始探索游戏渲染】专栏-直达
核心配置预览


[*]核心配置所有配置列出(非全必要):
Stencil {
    Ref 2 // 必要模版数值
    ReadMask 255
    WriteMask 255
    Comp Greater // 必要比较操作符
    Pass Replace // 必要通过后的操作
    Fail Keep
    ZFail DecrSat
}‌1. 核心配置命令‌


[*]Ref:设置参考值(0-255整数),用于与模板缓冲区比较
[*]ReadMask:读取掩码(0-255),按位与操作后比较(默认255)
[*]WriteMask:写入掩码(0-255),控制可修改的缓冲区位(默认255)
‌2. 比较函数命令‌

Comp支持以下枚举值:

[*]Always/Never:始终通过/拒绝
[*]Less/Greater:小于/大于时通过
[*]Equal/NotEqual:等于/不等于时通过
[*]LessEqual/GreaterEqual:小于等于/大于等于时通过
‌3. 操作命令‌

Pass/Fail/ZFail支持的操作:

[*]Keep:保持原值
[*]Zero:置零
[*]Replace:用Ref值替换
[*]IncrSat/DecrSat:饱和增减(0/255边界)
[*]IncrWrap/DecrWrap:循环增减
[*]Invert:按位取反
模板测试具体过程‌


[*]‌缓冲区初始化‌

[*]清除模板缓冲:GL.Clear(ClearBufferMask.StencilBufferBit)
[*]设置初始值:GL.StencilMask(0xFF)(默认全255)

[*]‌测试阶段-逐片元‌
plaintext
if (片元模板值 [比较函数] 参考值) {
    执行通过操作(如保留像素)
} else {
    执行失败操作(如丢弃像素)
}
[*]‌缓冲更新‌

[*]根据测试结果修改模板缓冲值(可选)

‌比较函数(StencilFunc)‌

函数含义OpenGL常量Never永远不通过GL_NEVERAlways永远通过GL_ALWAYSLess模板值 < 参考值GL_LESSLEqual模板值 ≤ 参考值GL_LEQUALGreater模板值 > 参考值GL_GREATERGEqual模板值 ≥ 参考值GL_GEQUALEqual模板值 == 参考值GL_EQUALNotEqual模板值 != 参考值GL_NOTEQUAL‌缓冲操作(StencilOp)‌

操作组合含义Keep保持当前模板值不变(默认)Zero将模板值设为0Replace用参考值替换模板值Incr/IncrWrap模板值+1(超过255时,前者截断后者循环)Decr/DecrWrap模板值-1(低于0时,前者截断后者循环)Invert按位取反(~操作)示例1


[*]遮罩区域shader
Shader "Custom/StencilMask" {
    SubShader {
      Tags { "Queue"="Geometry-1" } // 优先渲染
      ColorMask 0 // 不写入颜色
      ZWrite Off

      Stencil {
            Ref 1
            Comp Always
            Pass Replace // 将模板值设为1
      }
      Pass {} // 空Pass仅用于写入模板
    }
}

[*]物体模版测试shader,该Shader仅在模板值为1的区域内渲染物体。
Shader "Custom/StencilObject" {
    SubShader {
      Stencil {
            Ref 1
            Comp Equal // 仅渲染模板值=1的区域
            Pass Keep
      }
      Pass {
            // 正常着色代码...
      }
    }
}示例2 外轮廓描边

Shader "Custom/StencilOutline" {
    Properties {
      _MainTex ("Base Texture", 2D) = "white" {}
      _OutlineColor ("Outline Color", Color) = (1,0,0,1)
      _OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.05
    }

    SubShader {
      Tags {
            "RenderPipeline"="UniversalRenderPipeline"
            "RenderType"="Opaque"
      }

      // Pass 1: 正常渲染角色并写入模板
      Pass {
            Name "Character"
            Tags
            {
                "LightMode" = "UniversalForward"
            }
            Stencil {
                Ref 1
                Comp Always
                Pass Replace
                ZFail Keep
            }

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes {
                float4 positionOS : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct Varyings {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            TEXTURE2D(_MainTex);
            SAMPLER(sampler_MainTex);

            Varyings vert(Attributes IN) {
                Varyings OUT;
                OUT.positionCS = TransformObjectToHClip(IN.positionOS.xyz);
                OUT.uv = IN.uv;
                return OUT;
            }

            half4 frag(Varyings IN) : SV_Target {
                return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
            }
            ENDHLSL
      }

      // Pass 2: 渲染轮廓
      Pass {
            Name "Outline"
            Cull Front
            Stencil {
                Ref 1
                Comp NotEqual
                Pass Keep
            }

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes {
                float4 positionOS : POSITION;
                float3 normalOS : NORMAL;
            };

            struct Varyings {
                float4 positionCS : SV_POSITION;
            };

            CBUFFER_START(UnityPerMaterial)
                float4 _OutlineColor;
                float _OutlineWidth;
            CBUFFER_END

            Varyings vert(Attributes IN) {
                Varyings OUT;
                float3 posWS = TransformObjectToWorld(IN.positionOS.xyz * (1 + _OutlineWidth));
                float3 normalWS = TransformObjectToWorldNormal(IN.normalOS);
                // posWS += normalWS * _OutlineWidth; // 沿法线方向扩展
                OUT.positionCS = TransformWorldToHClip(posWS);
                return OUT;
            }

            half4 frag(Varyings IN) : SV_Target {
                return _OutlineColor;
            }
            ENDHLSL
      }
    }
}【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 【渲染流水线】[逐片元阶段]-[模版测试]以UnityURP为例