Game Dev/Unity Shader

09. Depth Buffer 심화 (3) - 다니엘 릿 쉐이더 프로젝트

Septentrions 2025. 10. 16. 18:34

X-Ray Effet Using Depth

여러 게임들을 보면, 벽을 통해서도 오브젝트를 볼 수 있능 기능이 있다.

벽 너머에 있는 오브젝트를 렌더링 하기 위해서, Depth Buffer를 이용하면 된다.

오브젝트가 다른 벽보다 앞에 있으면 Less-Equal Depth Testing을 이용하고, 벽 뒤에 있게 되면 Greater Depth Testing을 진행하면 된다.

 

이 기능 또한 Render Object 를 이용하면 되지만, 쉐이더에서 한번 만들어보도록 하자.

 

Built-in 파이프라인에서는 2개의 Pass를 붙여서 사용해도 되지만, URP에서는 Normal 관련 이펙트는 여러 패스가 Single Shader로 묶여 처리된다.

 

이를 해결하기 위해 2개의 Shader 파일을 만들도록 하자.

 

XRay Effect Shader

Shader "Lucid-Boundary/DepthBuffer_XRay"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _BaseColor("Base Color", Color) = (1, 1, 1, 1)
        _XRayColor("Xray Color", Color) = (1, 1, 1, 1)
    }
    SubShader
    {
        Tags 
        { 
            "RenderType"="Opaque" 
            "Queue" = "Geometry"
            "RenderPipeline" = "UniversalPipeline"    
        }
        
        // XRay Pass
        Pass
        {
            ZTest Greater
            ZWrite Off

            Tags
            {
                "LightMode" = "UniversalForward"    
            }

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            texture2D _MainTex;

            CBUFFER_START(UnityPerMaterial)
                float4 _XRayColor;
            CBUFFER_END

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex.xyz);

                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                return _XRayColor;
            }
            ENDHLSL
        }
    }

    
}

 

더할나위 없이 쉬운 코드이다.

딱 하나 추가 된점은 ZTest 와 ZWrite 뿐이다.

ZTest가 Greater 이므로 Depth Testing의 조건은 Depth Value가 해당 쉐이더보다 높을 때, 렌더링 하도록 하며

Testing을 통과 했더라도 덮어 쓰기는 하지 않는다로 되어 있다.

 

이 뜻은, 오브젝트가 벽 뒤에 가려진 부분은 _XRayColor 로 출력되며 그 외에 부분은 렌더링 하지 않는다. 이다.

만약에 XRay Texture Shader를 추가로 만들지 않으면 투명화된 오브젝트가 벽 뒤에 있을 때만 표시되는 현상이 발생한다.

 

XRay Texture Shader

Shader "Lucid-Boundary/DepthBuffer_XRayTexture"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _BaseColor("Base Color", Color) = (1, 1, 1, 1)
    }
    SubShader
    {
        Tags 
        { 
            "RenderType"="Opaque" 
            "Queue" = "Geometry"
            "RenderPipeline" = "UniversalPipeline"    
        }

        // Textured Pass
        Pass
        {
            ZTest LEqual
            ZWrite On

            Tags
            {
                "LightMode" = "UniversalForward"    
            }

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            texture2D _MainTex;
            SamplerState sampler_MainTex;

            CBUFFER_START(UnityPerMaterial)
                float4 _MainTex_ST;
                float4 _BaseColor;
            CBUFFER_END

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = TransformObjectToHClip(v.vertex.xyz);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                float4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
                return col * _BaseColor;
            }
            ENDHLSL
        }
    }

    
}

 

아주 심플하게 Texture를 표시하는 쉐이더이다.

추가 된 점은 역시나 ZTest, ZWrite 뿐이다.

 

ZTest LEqual은 일반적인 디폴트 값으로 앞에 나와있으면 렌더링 하는 Depth Test 조건이고,

ZWrite On 이므로 Testing 에 통과 했다면 Depth Value를 덮어쓰도록 설정된다.

 

이 두 쉐이더를 같이 매트리얼에 적용 시켜보자.

 

XRay 효과


URP Render Object를 이용한 X-Ray 이펙트 넣기

 

URP Render Object에 대해 지난 포스팅에서 다루었으니 바로 써먹어보자.

벽 역할의 오브젝트, XRay 대상이 될 오브젝트를 준비
XRay란 이름으로 레이어를 미리 하나 추가해놓자.

 

URP 세팅에 들어가 XRay 레이어를 꺼주자.

 

URP 세팅에 Render Object 피쳐를 2개 추가하고 XRay 컨셉에 맞게 설정을 바꾸자.
Shader 없이 만든 XRay 이펙트

 

Render Pass 가지고 노는 것만으로도 XRay 이펙트를 구현 할 수 있었다.

Depth Buffer에 대해 이해하게 된 이상...생각해보니 정말 편한 방식이다...!!

 


마치며

Depth Buffer는 쉐이더에서 정말 중요한 구간이다.

Depth Buffer / Stencil Buffer / Depth Testing / Render Feature 까지

우리의 입맛대로 렌더링을 결정할 수 있는 유용한 파트였다.

그리고 쉐이더 내부 동작에 대해서도 좀 더 이해 할 수 있었던.. 이론적으로 재미있고 유익한 구간이였다.