Unity Shader之模板测试

Unity Shader之模板测试

一沙一世界,一花一天堂

一、Stencil testing

 

渲染管线
渲染管线

    当片段着色器处理完一个片段之后,模板测试(Stencil Test)会开始执行,和深度测试一样,它也可能会丢弃片段。接下来,被保留的片段会进入深度测试,它可能会丢弃更多的片段。模板测试是根据又一个缓冲来进行的,它叫做模板缓冲(Stencil Buffer),我们可以在渲染的时候更新它来获得一些很有意思的效果。
    一个模板缓冲中,(通常)每个模板值(Stencil Value)是8位的。所以每个像素/片段一共能有256种不同的模板值。我们可以将这些模板值设置为我们想要的值,然后当某一个片段有某一个模板值的时候,我们就可以选择丢弃或是保留这个片段了。

 

二、模板函数

2.1 调用函数

  1. Stencil 
  2. { 
  3. Ref 1//Reference Value ReadMask 255 WriteMask 255 Comp Always //Comparison Function Pass Replace 
  4. Fail Keep 
  5. ZFail Replace 
  6. } 

2.2 参数说明

Ref :就是参考值,当参数允许赋值时,会把参考值赋给当前像素
ReadMask: 对当前参考值和已有值进行mask操作,默认值255,一般不用
WriteMask: 写入Mask操作,默认值255,一般不用

Comp: 比较方法。是拿Ref参考值和当前像素缓存上的值进行比较。默认值always,即一直通过。
-- Greater - 大于

  • GEqual - 大于等于
  • Less - 小于
  • LEqual - 小于等于
  • Equal - 等于
  • NotEqual - 不等于
  • Always - 永远通过
  • Never - 永远通不过

Pass: 当模版测试和深度测试都通过时,进行处理

Fail :当模版测试和深度测试都失败时,进行处理

ZFail: 当模版测试通过而深度测试失败时,进行处理

pass,Fail,ZFail都属于Stencil操作,他们参数统一如下:

  • Keep 保持(即不把参考值赋上去,直接不管)
  • Zero 归零
  • Replace 替换(拿参考值替代原有值)
  • IncrSat 值增加1,但不溢出,如果到255,就不再加
  • DecrSat 值减少1,但不溢出,值到0就不再减
  • Invert 反转所有位,如果1就会变成254
  • IncrWrap 值增加1,会溢出,所以255变成0
  • DecrWrap 值减少1,会溢出,所以0变成255

    !!!若果发现Unity下你的模板测试效果不对,但模板里Ref这些都没问题的话,那估计是RenderQueue设置的不合适。一般Mask的RenderQueue低于被Mask的对象。

三、案例

3.1 描边

 

渲染管线
渲染管线

 

  1. Shader "ShaderCookbook/stencil_outline" { 
  2. Properties { 
  3. _MainTex("Texture", 2D) = "white" {} 
  4. _OutLineWidth("Width", float) = 0.01  
  5. _OutLineColor("Color", color) = (1, 1, 1, 1) 
  6. } 
  7. SubShader { 
  8. Tags { 
  9. "RenderType" = "Opaque" 
  10. } 
  11. LOD 100 
  12.  
  13. Stencil { 
  14. Ref 0 Comp Equal Pass IncrSat 
  15. } 
  16.  
  17. Pass { 
  18. CGPROGRAM 
  19. #pragma vertex vert 
  20. #pragma fragment frag 
  21. #include "UnityCG.cginc" 
  22.  
  23. struct appdata { 
  24. float4 vertex: POSITION; 
  25. float2 uv: TEXCOORD0; 
  26. }; 
  27.  
  28. struct v2f { 
  29. float2 uv: TEXCOORD0; 
  30. float4 vertex: SV_POSITION; 
  31. }; 
  32.  
  33. sampler2D _MainTex; 
  34. float4 _MainTex_ST; 
  35. v2f vert(appdata v) { 
  36. v2f o; 
  37. o.vertex = UnityObjectToClipPos(v.vertex); 
  38. o.uv = TRANSFORM_TEX(v.uv, _MainTex); 
  39. return o; 
  40. } 
  41. fixed4 frag(v2f i) : SV_Target { 
  42. // sample the texture 
  43. fixed4 col = tex2D(_MainTex, i.uv); 
  44. return col; 
  45. } 
  46. ENDCG 
  47. } 
  48.  
  49. Pass { 
  50. CGPROGRAM 
  51. #pragma vertex vert 
  52. #pragma fragment frag 
  53.  
  54. struct appdata { 
  55. float4 vertex: POSITION; 
  56. float4 normal: NORMAL; 
  57. }; 
  58.  
  59. struct v2f { 
  60. float4 vertex: SV_POSITION; 
  61. }; 
  62.  
  63. fixed4 _OutLineColor; 
  64. float _OutLineWidth; 
  65. v2f vert(appdata v) { 
  66. v2f o; 
  67. v.vertex = v.vertex + normalize(v.normal) * _OutLineWidth; 
  68. o.vertex = UnityObjectToClipPos(v.vertex); 
  69. return o; 
  70. } 
  71. fixed4 frag(v2f i) : SV_Target { 
  72. // sample the texture 
  73. fixed4 col = _OutLineColor; 
  74. return col; 
  75. } 
  76. ENDCG 
  77. } 
  78. } 
  79. } 

3.2 百宝箱

 


渲染管线

 

遮罩层:

  1. Shader "ShaderCookbook/StencilEnumMask" 
  2. { 
  3. Properties 
  4. { 
  5. _MainTex ("Texture", 2D) = "white" {} 
  6. [ForceInt] 
  7. _StencilRef("StencilRef",float) = 0 
  8. [Enum(UnityEngine.Rendering.CompareFunction)] 
  9. _StencilComp("StencilComp",int) =0 
  10. [Enum(UnityEngine.Rendering.StencilOp)] 
  11. _StencilOp("StencilOp",int)=0 
  12.  
  13. [ForceInt] 
  14. _StencilReadMask("ReadMask",int)=255 
  15. [ForceInt] 
  16. _StencilWriteMask("WriteMask",int)=255 
  17. [MaterialToggle] 
  18. _ZWrite("zWrite",float)=0 
  19. } 
  20. SubShader 
  21. { 
  22. Tags { "RenderType"="StencilMaskOpaque" 
  23. "Queue" = "Geometry-100" 
  24. "IgnoreProjector" = "True" } 
  25. LOD 100 
  26.  
  27.  
  28. Pass 
  29. { 
  30. ColorMask 0 
  31. ZWrite [_ZWrite] 
  32.  
  33. Stencil{ 
  34. Ref [_StencilRef] 
  35. Comp[_StencilComp] 
  36. Pass[_StencilOp] 
  37. ReadMask[_StencilReadMask] 
  38. WriteMask[_StencilWriteMask] 
  39. } 
  40.  
  41. CGPROGRAM 
  42. #pragma vertex vert 
  43. #pragma fragment frag 
  44. // make fog work 
  45. #pragma multi_compile_fog 
  46. #include "UnityCG.cginc" 
  47.  
  48.  
  49. struct appdata 
  50. { 
  51. float4 vertex : POSITION; 
  52. float2 uv : TEXCOORD0; 
  53. }; 
  54.  
  55. struct v2f 
  56. { 
  57. float2 uv : TEXCOORD0; 
  58. UNITY_FOG_COORDS(1) 
  59. float4 vertex : SV_POSITION; 
  60. }; 
  61.  
  62. sampler2D _MainTex; 
  63. float4 _MainTex_ST; 
  64. v2f vert (appdata v) 
  65. { 
  66. v2f o; 
  67. o.vertex = UnityObjectToClipPos(v.vertex); 
  68. o.uv = TRANSFORM_TEX(v.uv, _MainTex); 
  69. UNITY_TRANSFER_FOG(o,o.vertex); 
  70. return o; 
  71. } 
  72. fixed4 frag (v2f i) : SV_Target 
  73. { 
  74. // sample the texture 
  75. fixed4 col = tex2D(_MainTex, i.uv); 
  76. // apply fog 
  77. UNITY_APPLY_FOG(i.fogCoord, col); 
  78. return col; 
  79. } 
  80. ENDCG 
  81. } 
  82. } 
  83. } 

显示层:

  1.  
  2.  
  3. Shader "ShaderCookbook/StencilEnum" 
  4. { 
  5. Properties 
  6. { 
  7. _MainTex ("Texture", 2D) = "white" {} 
  8. [ForceInt] 
  9. _StencilRef("StencilRef",float) = 0 
  10. [Enum(UnityEngine.Rendering.CompareFunction)] 
  11. _StencilComp("StencilComp",int) =0 
  12. [Enum(UnityEngine.Rendering.StencilOp)] 
  13. _StencilOp("StencilOp",int)=0 
  14.  
  15. [ForceInt] 
  16. _StencilReadMask("ReadMask",int)=255 
  17. [ForceInt] 
  18. _StencilWriteMask("WriteMask",int)=255 
  19. } 
  20. SubShader 
  21. { 
  22. Tags { "RenderType"="opaque" } 
  23. LOD 100 
  24.  
  25.  
  26. Pass 
  27. { 
  28.  
  29. Stencil{ 
  30. Ref [_StencilRef] 
  31. Comp[_StencilComp] 
  32. Pass[_StencilOp] 
  33. ReadMask[_StencilReadMask] 
  34. WriteMask[_StencilWriteMask] 
  35. } 
  36.  
  37. CGPROGRAM 
  38. #pragma vertex vert 
  39. #pragma fragment frag 
  40. // make fog work 
  41. #pragma multi_compile_fog 
  42. #include "UnityCG.cginc" 
  43.  
  44.  
  45. struct appdata 
  46. { 
  47. float4 vertex : POSITION; 
  48. float2 uv : TEXCOORD0; 
  49. }; 
  50.  
  51. struct v2f 
  52. { 
  53. float2 uv : TEXCOORD0; 
  54. UNITY_FOG_COORDS(1) 
  55. float4 vertex : SV_POSITION; 
  56. }; 
  57.  
  58. sampler2D _MainTex; 
  59. float4 _MainTex_ST; 
  60. v2f vert (appdata v) 
  61. { 
  62. v2f o; 
  63. o.vertex = UnityObjectToClipPos(v.vertex); 
  64. o.uv = TRANSFORM_TEX(v.uv, _MainTex); 
  65. UNITY_TRANSFER_FOG(o,o.vertex); 
  66. return o; 
  67. } 
  68. fixed4 frag (v2f i) : SV_Target 
  69. { 
  70. // sample the texture 
  71. fixed4 col = tex2D(_MainTex, i.uv); 
  72. // apply fog 
  73. UNITY_APPLY_FOG(i.fogCoord, col); 
  74. return col; 
  75. } 
  76. ENDCG 
  77. } 
  78. } 
  79. } 

Ad

这里推荐一款可视化shader编程工具,对美术同学非常友好,就像建模工具中的材质编辑器一样

posted @ 2019-05-05 21:26  世纪末の魔术师  阅读(1950)  评论(0)    收藏  举报