Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

nomad-programmer

[CG/Unity] Z Buffer 본문

CG/Unity

[CG/Unity] Z Buffer

scii 2022. 2. 2. 16:16
기본적으로 게임의 오브젝트들을 그리는 순서는 정해져 있지 않고,
오브젝트가 그려질 때마다 z 버퍼를 참고로 앞뒤 판정을 한 후
그려질 픽셀과 안 그려질 픽셀을 결정한다.

 

게임이 시작되면 매 프레임마다 배경이나 캐릭터, 이펙트, UI들이 모두 그려지는 과정을 거치게 된다. 모든 것이 매 프레이마다 특정한 경로(Pipeline)를 따라서 재계산되고 화면에 그려지면서 한 프레임의 화면이 완성되는 것이다.

그렇다면 무엇인 가장 먼저 그려질까?

원론적으로 말하자면, 그리는 순서는 상당히 제멋대로라서 예측하기가 어렵다. 물론 특정한 명령이나 그룹핑에 따라 그리는 순서가 조정될 수 있지만, 기본적으로는 '계산이 끝난 것이 먼저 그려진다' 라는 원칙으로 그려지고 있으니 어떤 것이 먼저 그려질지 알 수 가 없는 것이다. 유니티에서는 '프레임 디버거'를 이요하여 매 프레임마다 그려지는 게임 오브젝트의 순서를 눈으로 확인할 수 있다.

뒤에 있는 오브젝트가 먼저 그려지고 앞에 있는 오브젝트가 그려질 때, 이것을 '오버드로우(Over Draw)' 라고 한다.

앞에 있는 오브젝트가 먼저 그려지고 뒤에 있는 오브젝트가 그려질 때, 이럴 경우에는 문제가 생긴다. 앞뒤를 판정하는 아무런 정보가 없다면 나중에 그려진 '뒤에 있는 오브젝트'가 앞의 오브젝트를 덮어 버릴 것이다. 

즉, 이런 문제를 피하려면 '앞에 이미 그려진 것이 있다' 라는 정보가 있어야 그 부분을 피해서 그릴 수 있을 것이다. 바로 이것 즉, '지금 제일 앞에 그려져 있는 것이 무엇인가' 라는 정보를 가진 정보가 필요하다. 그리고 그 정보는 픽셀 단위로 존재해야 한다.

다시 정리하면, '앞 뒤 판정을 위해서, 각 픽셀마다 카메라를 기준으로 가장 가까운 오브젝트의 깊이 값이 저장되어 있는 데이터 시트가 필요하다' 는 말이 된다. 매 픽셀의 깊이 값이 채워져 있는 엑셀표와 같은 느낌이다.

그리고 이것은 당연하게도 1.000... ~ 0.000... 의 숫자로 나타낼 수 있다. 그리고 또 그 말은 이 숫자를 '컬러' 즉, '흑백'으로 표현할 수 도 있다는 말이다. 이 '깊이값'을 각 픽셀별로 써 놓은 그림이 바로 "Z 버퍼(Z Buffer)" 라고 불린다.

그래픽 카드에 있는 깊이 버퍼를 가져와서 사용하기는 쉽지 않지만, 셰이더에서 _CameraDepthTexture를 사용하면 깊이값을 텍스처로 받아와 처리할 수 있다.

Shader "Custom/depth"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert noambient noshadow

        #pragma target 3.0

        sampler2D _CameraDepthTexture;

        struct Input
        {
            float4 screenPos;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            float2 sPos = float2(IN.screenPos.x, IN.screenPos.y) / IN.screenPos.w;
            float4 depth = tex2D(_CameraDepthTexture, sPos);
            o.Emission = depth.r;
            o.Alpha = 1;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

디퍼드 렌더링(Deferred Rendering) 모드로 해주어야 제대로 작동된다.

이것을 응용하면 실제로 거리에 따라 무언가 변화가 일어나는 셰이더를 만들 수도 있다.


Z 버퍼가 나왔으므로 뒤의 오브젝트가 나중에 그려지더라도, 앞의 오브젝트가 미리 써 놓은 Z 버퍼 값을 참조하여 해당 부분을 그리지 않으면 앞뒤 판정은 문제가 없을 것이다. 모든 오브젝트는 이렇게 그리고 있다고 해도 과언이 아니다.

'CG > Unity' 카테고리의 다른 글

[CG/Unity] 2Pass를 이용한 깨끗한 알파 블랜딩  (1) 2022.02.02
[CG/Unity] 커스텀 알파 블랜딩  (0) 2022.02.02
[CG/Unity] Cube Map  (0) 2022.02.01
[CG/Unity] Diffuse Warping  (0) 2022.02.01
[CG/Unity] Toon Shader  (0) 2022.02.01
Comments