스텐실 버퍼는 픽셀을 저장 또는 폐기하기 위한 용도의 픽셀 마스크로 사용할 수 있습니다.
스텐실 버퍼는 보통 한 픽셀당 8비트 정수입니다. 이 값은 쓰기, 증가, 감소가 가능합니다. 픽셀 셰이더를 실행하기 전 어떤 픽셀이 제거되어야 할지 여부를 결정하기 위해 드로우 콜로 이 값을 테스트할 수 있습니다.
Ref referenceValue
비교될 값(Comp가 always 가 아닌 경우) 그리고/또는 버퍼에 기록될 값(Pass, Fail, Zfail 중 하나가 대체할 예정일 경우)입니다. 0255 사이의 정수입니다.
ReadMask readMask
0255 사이의 정수인 8비트 마스크이며 레퍼런스 값을 버퍼의 콘텐츠와 비교할 때 사용합니다(referenceValue & readMask) comparisonFunction (stencilBufferValue & readMask). 디폴트는 255 입니다.
WriteMask writeMask
0255 사이의 정수인 8비트 마스크이며 버퍼에 작성할 때 사용합니다. 다른 작성 마스크와 마찬가지로 스텐실 마스크의 어느 비트가 작성의 영향을 받을지 지정한다는 점을 참조하십시오. 예를 들어, WriteMask 0은 아무 비트에도 영향을 주지 않으며 0은 작성되지 않습니다. 디폴트는 255 입니다.
Comp comparisonFunction
이 함수는 레퍼런스 값을 버퍼의 현재 콘텐츠와 비교할 때 사용합니다. 디폴트는 always 입니다.
Pass stencilOperation
스텐실 테스트(와 뎁스 테스트)를 통과한다면 버퍼의 콘텐츠를 어떻게 할 것인지 지정합니다. 디폴트는 keep 입니다.
Fail stencilOperation
스텐실 테스트가 실패한다면 버퍼의 콘텐츠를 어떻게 할 것인지 지정합니다. 디폴트는 keep 입니다.
ZFail stencilOperation
스텐실 테스트를 통과했으나 뎁스 테스트에 실패한다면 버퍼의 콘텐츠를 어떻게 할 것인지 지정합니다. 디폴트는 keep 입니다.
Comp, Pass, Fail, ZFail은 Cull Front 가 지정되어 있지 않으면 전면 지오메트리에 적용되며 지정된 경우엔 후면 지오메트리에 적용됩니다. 또한 CompFront, PassFront, FailFront, ZFailFront(전면 방향 지오메트리), CompBack, PassBack, FailBack, ZFailBack(후면 지오메트리)을 정의하여 명시적으로 양면 스텐실 스테이트를 명시할 수 있습니다.
비교 함수는 다음 중 하나입니다.
Greater | 레퍼런스 값이 버퍼 안의 값보다 큰 픽셀만 렌더링합니다. |
GEqual | 레퍼런스 값이 버퍼 안의 값보다 크거나 같은 픽셀만 렌더링합니다. |
Less | 레퍼런스 값이 버퍼 안의 값보다 작은 픽셀만 렌더링합니다. |
LEqual | 레퍼런스 값이 버퍼 안의 값보다 작거나 같은 픽셀만 렌더링합니다. |
Equal | 레퍼런스 값이 버퍼 안의 값과 같은 픽셀만 렌더링합니다. |
NotEqual | 레퍼런스 값이 버퍼 안의 값과 다른 픽셀만 렌더링합니다. |
Always | 스텐실 테스트를 항상 통과하도록 만듭니다. |
Never | 스텐실 테스트를 항상 실패하도록 만듭니다. |
스텐실 동작은 다음 중 하나입니다.
Keep | 버퍼의 현재 콘텐츠를 유지합니다. |
Zero | 버퍼에 0을 작성합니다. |
Replace | 버퍼에 레퍼런스 값을 작성합니다. |
IncrSat | 버퍼의 현재 값을 증가시킵니다. 만약 값이 이미 255라면 그대로 255를 유지합니다. |
DecrSat | 버퍼의 현재 값을 감소시킵니다. 만약 값이 이미 0이면 그대로 0을 유지합니다. |
Invert | 모든 비트의 값을 반전합니다. |
IncrWrap | 버퍼의 현재 값을 증가시킵니다. 만약 값이 이미 255라면 0이 됩니다. |
DecrWrap | 버퍼의 현재 값을 감소시킵니다. 만약 값이 이미 0이면 255가 됩니다. |
디퍼드 렌더링 경로에서 렌더링된 오브젝트에 대한 스텐실 기능은 다소 제한적인데, 이는 스텐실 버퍼가 G버퍼 패스 및 조명 패스 진행 중에 다른 목적으로 사용되기 때문입니다. 이 두 단계 동안 셰이더에서 정의된 스텐실 스테이트는 무시됩니다. 이로 인해 스텐실 테스트에 기반하여 오브젝트를 마스크하는 것은 불가능합니다. 그러나 여전히 버퍼 콘텐츠를 수정하여 프레임에서 나중에 렌더링될 오브젝트에서 사용하도록 할 수 있습니다. 디퍼드 경로에 이어 포워드 렌더링 경로에서 렌더링되는 오브젝트(예: 투명 오브젝트 또는 표면 셰이더가 없는 오브젝트)는 해당 스텐실 스테이트를 대게 다시 설정합니다.
다음의 비트들이 디퍼드 렌더링 경로에서 스텐실 버퍼에 사용됩니다.
스텐실 읽기 및 쓰기 마스크를 사용하여 사용되지 않는 비트 범위 내에서 작동하거나, Camera.clearStencilAfterLightingPass를 사용하여 조명 패스 이후에 강제로 카메라가 스텐실 버퍼를 정리하도록 만들 수 있습니다.
첫 번째 예제 셰이더는 뎁스 테스트가 통과한 곳에 ’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
}
}
}
두 번째 셰이더는 ’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
}
}
}
세 번째 셰이더는 스텐실 값이 ’1’일 경우에만 통과시키므로 빨간색과 초록색 구체가 교차하는 픽셀만이 해당됩니다. 여기에서 빨간 셰이더가 스텐실을 ’2’로 설정하고 초록 셰이더가 ’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
}
}
}
결과:
더 직접적인 효과를 보여주는 다른 예제입니다. 스텐실 버퍼의 적절한 구역을 표시하기 위해 이 구체는 이 셰이더를 가지고 렌더링됩니다.
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
}
}
결과: