Version: 2019.2
ShaderLab: 패스 태그
ShaderLab: 이름

ShaderLab: 스텐실

스텐실 버퍼는 픽셀을 저장 또는 폐기하기 위한 용도의 픽셀 마스크로 사용할 수 있습니다.

스텐실 버퍼는 보통 한 픽셀당 8비트 정수입니다. 이 값은 쓰기, 증가, 감소가 가능합니다. 픽셀 셰이더를 실행하기 전 어떤 픽셀이 제거되어야 할지 여부를 결정하기 위해 드로우 콜로 이 값을 테스트할 수 있습니다.

구문

Ref

    Ref referenceValue

비교될 값(Comp가 always 가 아닌 경우) 그리고/또는 버퍼에 기록될 값(Pass, Fail, Zfail 중 하나가 대체할 예정일 경우)입니다. 0255 사이의 정수입니다.

ReadMask

    ReadMask readMask

0255 사이의 정수인 8비트 마스크이며 레퍼런스 값을 버퍼의 콘텐츠와 비교할 때 사용합니다(referenceValue & readMask) comparisonFunction (stencilBufferValue & readMask). 디폴트는 255 입니다.

WriteMask

    WriteMask writeMask

0255 사이의 정수인 8비트 마스크이며 버퍼에 작성할 때 사용합니다. 다른 작성 마스크와 마찬가지로 스텐실 마스크의 어느 비트가 작성의 영향을 받을지 지정한다는 점을 참조하십시오. 예를 들어, WriteMask 0은 아무 비트에도 영향을 주지 않으며 0은 작성되지 않습니다. 디폴트는 255 입니다.

Comp

    Comp comparisonFunction

이 함수는 레퍼런스 값을 버퍼의 현재 콘텐츠와 비교할 때 사용합니다. 디폴트는 always 입니다.

Pass

    Pass stencilOperation

스텐실 테스트(와 뎁스 테스트)를 통과한다면 버퍼의 콘텐츠를 어떻게 할 것인지 지정합니다. 디폴트는 keep 입니다.

Fail

    Fail stencilOperation

스텐실 테스트가 실패한다면 버퍼의 콘텐츠를 어떻게 할 것인지 지정합니다. 디폴트는 keep 입니다.

ZFail

    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버퍼 패스 및 조명 패스 진행 중에 다른 목적으로 사용되기 때문입니다. 이 두 단계 동안 셰이더에서 정의된 스텐실 스테이트는 무시됩니다. 이로 인해 스텐실 테스트에 기반하여 오브젝트를 마스크하는 것은 불가능합니다. 그러나 여전히 버퍼 콘텐츠를 수정하여 프레임에서 나중에 렌더링될 오브젝트에서 사용하도록 할 수 있습니다. 디퍼드 경로에 이어 포워드 렌더링 경로에서 렌더링되는 오브젝트(예: 투명 오브젝트 또는 표면 셰이더가 없는 오브젝트)는 해당 스텐실 스테이트를 대게 다시 설정합니다.

다음의 비트들이 디퍼드 렌더링 경로에서 스텐실 버퍼에 사용됩니다.

  • 비트 #7(값=128)은 백그라운드가 아닌 오브젝트를 나타냅니다.
  • 비트 #6(값=64)은 라이트맵을 사용하지 않는 오브젝트를 나타냅니다.
  • 비트 #5(값=32)는 Unity에서 사용되지 않습니다.
  • 비트 #4(값=16)는 조명 패스 동안 광원 셰이프 컬링에 사용되므로 표면 지오메트리가 광원 영역 뒤에 있는 픽셀이 아니라, 광원이 터치하는 픽셀의 조명 셰이더만 실행됩니다.
  • 광원 레이어 컬링 마스크를 위해 가장 낮은 네 개의 비트(값: 1, 2, 4, 8)가 사용됩니다.

스텐실 읽기 및 쓰기 마스크를 사용하여 사용되지 않는 비트 범위 내에서 작동하거나, 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
    } 
}

결과:

ShaderLab: 패스 태그
ShaderLab: 이름