找回密码
 立即注册
首页 业界区 业界 【渲染流水线】[逐片元阶段]-[模版测试]以UnityURP为例 ...

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

峰埋姚 4 天前

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


  • 核心配置所有配置列出(非全必要):
  1. Stencil {
  2.     Ref 2 // 必要模版数值
  3.     ReadMask 255
  4.     WriteMask 255
  5.     Comp Greater // 必要比较操作符
  6.     Pass Replace // 必要通过后的操作
  7.     Fail Keep
  8.     ZFail DecrSat
  9. }
复制代码
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)

  • 测试阶段-逐片元
    1. plaintext
    2. if (片元模板值 [比较函数] 参考值) {
    3.     执行通过操作(如保留像素)
    4. } else {
    5.     执行失败操作(如丢弃像素)
    6. }
    复制代码
  • 缓冲更新

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

‌比较函数(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
  1. Shader "Custom/StencilMask" {
  2.     SubShader {
  3.         Tags { "Queue"="Geometry-1" } // 优先渲染
  4.         ColorMask 0 // 不写入颜色
  5.         ZWrite Off
  6.         Stencil {
  7.             Ref 1
  8.             Comp Always
  9.             Pass Replace // 将模板值设为1
  10.         }
  11.         Pass {} // 空Pass仅用于写入模板
  12.     }
  13. }
复制代码

  • 物体模版测试shader,该Shader仅在模板值为1的区域内渲染物体。
  1. Shader "Custom/StencilObject" {
  2.     SubShader {
  3.         Stencil {
  4.             Ref 1
  5.             Comp Equal // 仅渲染模板值=1的区域
  6.             Pass Keep
  7.         }
  8.         Pass {
  9.             // 正常着色代码...
  10.         }
  11.     }
  12. }
复制代码
示例2 外轮廓描边
  1. Shader "Custom/StencilOutline" {
  2.     Properties {
  3.         _MainTex ("Base Texture", 2D) = "white" {}
  4.         _OutlineColor ("Outline Color", Color) = (1,0,0,1)
  5.         _OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.05
  6.     }
  7.     SubShader {
  8.         Tags {
  9.             "RenderPipeline"="UniversalRenderPipeline"
  10.             "RenderType"="Opaque"
  11.         }
  12.         // Pass 1: 正常渲染角色并写入模板
  13.         Pass {
  14.             Name "Character"
  15.             Tags
  16.             {
  17.                 "LightMode" = "UniversalForward"
  18.             }
  19.             Stencil {
  20.                 Ref 1
  21.                 Comp Always
  22.                 Pass Replace
  23.                 ZFail Keep
  24.             }
  25.             HLSLPROGRAM
  26.             #pragma vertex vert
  27.             #pragma fragment frag
  28.             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  29.             struct Attributes {
  30.                 float4 positionOS : POSITION;
  31.                 float2 uv : TEXCOORD0;
  32.             };
  33.             struct Varyings {
  34.                 float4 positionCS : SV_POSITION;
  35.                 float2 uv : TEXCOORD0;
  36.             };
  37.             TEXTURE2D(_MainTex);
  38.             SAMPLER(sampler_MainTex);
  39.             Varyings vert(Attributes IN) {
  40.                 Varyings OUT;
  41.                 OUT.positionCS = TransformObjectToHClip(IN.positionOS.xyz);
  42.                 OUT.uv = IN.uv;
  43.                 return OUT;
  44.             }
  45.             half4 frag(Varyings IN) : SV_Target {
  46.                 return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
  47.             }
  48.             ENDHLSL
  49.         }
  50.         // Pass 2: 渲染轮廓
  51.         Pass {
  52.             Name "Outline"
  53.             Cull Front
  54.             Stencil {
  55.                 Ref 1
  56.                 Comp NotEqual
  57.                 Pass Keep
  58.             }
  59.             HLSLPROGRAM
  60.             #pragma vertex vert
  61.             #pragma fragment frag
  62.             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
  63.             struct Attributes {
  64.                 float4 positionOS : POSITION;
  65.                 float3 normalOS : NORMAL;
  66.             };
  67.             struct Varyings {
  68.                 float4 positionCS : SV_POSITION;
  69.             };
  70.             CBUFFER_START(UnityPerMaterial)
  71.                 float4 _OutlineColor;
  72.                 float _OutlineWidth;
  73.             CBUFFER_END
  74.             Varyings vert(Attributes IN) {
  75.                 Varyings OUT;
  76.                 float3 posWS = TransformObjectToWorld(IN.positionOS.xyz * (1 + _OutlineWidth));
  77.                 float3 normalWS = TransformObjectToWorldNormal(IN.normalOS);
  78.                 // posWS += normalWS * _OutlineWidth; // 沿法线方向扩展
  79.                 OUT.positionCS = TransformWorldToHClip(posWS);
  80.                 return OUT;
  81.             }
  82.             half4 frag(Varyings IN) : SV_Target {
  83.                 return _OutlineColor;
  84.             }
  85.             ENDHLSL
  86.         }
  87.     }
  88. }
复制代码
【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册