스텐실 버퍼는 픽셀을 저장 또는 폐기하기 위한 용도의 픽셀 마스크로 사용할 수 있습니다.
스텐실 버퍼는 보통 한 픽셀당 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가 됩니다. |
디퍼드 렌더링 경로에서 렌더링된 오브젝트에 대한 스텐실 기능은 다소 제한적인데 스텐실 버퍼가 베이스 패스 및 라이팅 패스 진행 중에 다른 목적으로 사용되기 때문입니다. 이 두 단계 동안 셰이더에서 정의된 스텐실 스테이트는 무시되며 최종 패스 진행 중에만 고려됩니다. 이로 인해 스텐실 테스트에 기반하여 오브젝트를 마스크하는 것은 불가능합니다. 그러나 여전히 버퍼 내용을 수정하여 프레임에서 나중에 렌더링될 오브젝트에서 사용하도록 할 수 있습니다. 디퍼드 경로에 이어 포워드 렌더링 경로에서 렌더링되는 오브젝트(예: 투명 오브젝트 또는 표면 셰이더가 없는 오브젝트)는 해당 스텐실 스테이트를 대게 다시 설정합니다.
디퍼드 렌더링 경로는 스텐실 버퍼의 최상위 3개 비트를 사용하며 씬에서 사용하는 광원 마스크 레이어의 수에 따라 추가로 상위 비트를 최대 4개까지 사용합니다. 스텐실 읽기 및 쓰기 마스크를 사용하여 “클린” 비트의 범위상 조작하거나 라이팅 경로 진행 후 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
}
}
결과: