ShaderLab: Stencil

xiaoxiao2021-02-27  173

ShaderLab: Stencil

可以使用stencil buffer作为通用像素掩码来保存或丢弃像素。

Stencil buffer通常为8 bit整数每像素。该值可以被写为递增或递减。后续的调用,可以测试该值,来决定运行pixel shader前,是否应该将像素丢弃

Syntax

Ref

Ref referenceValue

该值用来比较(当 Comp 设置为非always)并/或 用来写入到buffer(如果任何Pass,Fail,ZFail被设置来代替他)。为 0–255 整数.

WriteMask

WriteMask writeMask

一个8 bit的mask,值为0-255的整数,当写入buffer时使用。注意,和其他写掩码一样,它指定的模版缓冲(stencil buffer)会被写操作影响。(例如:WriteMask 0 意味着没有bit会受影响,而不是0值会被写入)。 默认值为: 255.

Comp

Comp comparisonFunction

该函数用来比较reference值和当前buffer中的内容。默认为: always.

Pass

Pass stencilOperation

表示要做什么,当buffer内容通过了测试(以及深度测试)。 默认: keep.

Fail

Fail stencilOperation

表示要做什么,当buffer的内容没有通过测试。 默认: keep.

ZFail

ZFail stencilOperation

做什么当buffer内容通过了stencil测试,但是没通过深度测试。 默认: keep.

Comp, Pass, Fail 和 ZFail 将被提供给前前置几何图像,除非 Cull Front被指定,在这种情况下是提供给后置几何图像。你也可以明确的指出前后两面的stencil通过定义 CompFront, PassFront, FailFront, ZFailFront (for front-facing geometry), 和 CompBack, PassBack, FailBack, ZFailBack (for back-facing geometry).

Comparison Function

比较函数表格:

functiondescriptionGreater只渲染reference值比buffer中值大的像素。GEqual只渲染reference值比buffer中值大或等于的像素。Less只渲染reference值比buffer中值小的像素。LEqual只渲染reference值比buffer中值小或等于的像素。Equal只渲染reference值比buffer中值等于的像素。NotEqual只渲染reference值比buffer中值不等于的像素。Always让stencil测试总是通过。Never让stencil测试总是失败

Stencil Operation

Stencil 操作表格:

operationdescriptionkeep保留当前buffer内容。Zero写入0到当前buffer。Replace写入reference值到当前buffer。IncrSat增加当前buffer的值。如果已经达到255则保持255。DecrSat减少当前buffer的值。如果已经达到0则保持0。Invert反转所有位。IncrWrap增加当前buffer的值。如果已经达到255则变为0。DecrWrap减少当前buffer的值。如果已经达到0则变为255。

Deferred rendering path(延迟渲染路径)

Stencil 功能用在对象在延迟渲染路径的渲染有一定的限制,比如在 base pass或 lighting pass过程中用于其他用途。在这两个阶段stencil状态被定义在shader中会被忽略并且只有在最终的pass中才会被考虑到。因为这样不可能在stencil测试掩码输出这些对象,但是stencil还是可以改变buffer内容,会在每帧对象渲染的最后被调用。对象在deferred path之的的forward rendering path(例如:transparent objects or objects without a surface shader)中将会把他们的stencil设置会正常状态。

延迟渲染路径,使用三个高位的stencil buffer bits,再加上四个最高位 - 这取决于有多少光照遮罩层在该场景被使用。 它可能实现“clean” bits操作通过stencil的read和wirte mask,或者你可以强制相机清除stencil buffer 在光照pass后使用Camera.clearStencilAfterLightingPass.

Example

第一个例子,将写入值 ‘2’无论深度测试在哪通过。模板测试总是通过。

Shader "Red" { SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry"} Pass { Stencil { Ref 2 Comp always Pass replace } CGPROGRAM #pragma vertex vert #pragma fragment frag struct appdata { float4 vertex : POSITION; }; struct v2f { float4 pos : SV_POSITION; }; v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); return o; } half4 frag(v2f i) : SV_Target { return half4(1,0,0,1); } ENDCG } } }

第二个shader将通过只当上一个shader(red)通过时,因为它检查了值是否等于‘2’。如果z测试失败,它也会降低缓冲区中的值。

Shader "Green" { SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry+1"} Pass { Stencil { Ref 2 Comp equal Pass keep ZFail decrWrap } CGPROGRAM #pragma vertex vert #pragma fragment frag struct appdata { float4 vertex : POSITION; }; struct v2f { float4 pos : SV_POSITION; }; v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); return o; } half4 frag(v2f i) : SV_Target { return half4(0,1,0,1); } ENDCG } } }

第三方shader将在模板值为‘1’时通过,所以只有, 所以只有红色和绿色球体相交处的像素 - 因为, 该模版被red shader设置为 ‘2’ 并且被green shader减到‘1’。

Shader "Blue" { SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry+2"} Pass { Stencil { Ref 1 Comp equal } CGPROGRAM #include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag struct appdata { float4 vertex : POSITION; }; struct v2f { float4 pos : SV_POSITION; }; v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); return o; } half4 frag(v2f i) : SV_Target { return half4(0,0,1,1); } ENDCG } } }

The result:

另一个更直接效果的例子。 首先用这个着色器渲染球体,以标记模板缓冲区中的适当区域:

Shader "HolePrepare" { SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry+1"} ColorMask 0 ZWrite off Stencil { Ref 1 Comp always Pass replace } CGINCLUDE struct appdata { float4 vertex : POSITION; }; struct v2f { float4 pos : SV_POSITION; }; v2f vert(appdata v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); return o; } half4 frag(v2f i) : SV_Target { return half4(1,1,0,1); } ENDCG Pass { Cull Front ZTest Less CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG } Pass { Cull Back ZTest Greater CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG } } }

然后再作为一个完全的标准表面着色器渲染一次, 除了正面的剔除, 停用深度测试和模版测试,丢弃之前标记的像素:

Shader "Hole" { Properties { _Color ("Main Color", Color) = (1,1,1,0) } SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry+2"} ColorMask RGB Cull Front ZTest Always Stencil { Ref 1 Comp notequal } CGPROGRAM #pragma surface surf Lambert float4 _Color; struct Input { float4 color : COLOR; }; void surf (Input IN, inout SurfaceOutput o) { o.Albedo = _Color.rgb; o.Normal = half3(0,0,-1); o.Alpha = 1; } ENDCG } }

The result:


转载请注明原文地址: https://www.6miu.com/read-16826.html

最新回复(0)