본문 바로가기
그래픽스

UNITY 스카이박스 외부 안보이게, 그래픽스,깊이 버퍼(ZWrite)

by 유니티세상 2025. 11. 24.
반응형

문제 상황

  • Skybox/Cubemap 셰이더를 ‘구(Sphere) 메쉬’에 적용
  • 구 안은 어둡게 보이는데, 구 밖에 있는 건물 오브젝트가 그대로 보임

해결 방법

  • Mesh 전용 Cubemap 셰이더를 만들어서
    • ZWrite On (깊이 쓰기)
    • Queue = Geometry (보통 오브젝트와 같은 레벨)
    • Cull Front (앞면 제거 → 내부가 보이게)
    • 카메라 기준 방향으로 Cubemap 샘플링

결과

  • 구 안에서는 배경 Cubemap만 보이고
  • 구 밖 오브젝트는 완전히 가려짐
Shader "Custom/InsideSkySphere"
{
    Properties
    {
        _Cube("Cubemap", CUBE) = "" {}
        _Exposure("Exposure", Range(0, 5)) = 1
    }

    SubShader
    {
        Tags { "Queue"="Geometry" "RenderType"="Opaque" }

        // 중요! 내부(Front)만 렌더 → 구 내부에서만 보임
        Cull Front

        ZWrite On
        ZTest LEqual

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            samplerCUBE _Cube;
            float _Exposure;

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldDir : TEXCOORD0;
            };

            v2f vert(appdata v)
            {
                v2f o;
                float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                // 카메라에서 구 표면까지의 방향 벡터
                o.worldDir = normalize(worldPos - _WorldSpaceCameraPos);
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            half4 frag(v2f i) : SV_Target
            {
                half4 col = texCUBE(_Cube, i.worldDir);
                col.rgb *= _Exposure;
                return col;
            }
            ENDCG
        }
    }
}

 

참고하면 좋은 영상

 

https://www.youtube.com/watch?si=8IJjQ4pS_YSleJeB&v=r3OdEzAKGBI&feature=youtu.be

 

 

깊이 버퍼, 렌더 큐, 컬링, 큐브맵 샘플링 에 대한 개념을 알아야함

깊이 버퍼(Z-buffer)와 ZWrite / ZTest

깊이 버퍼란?

  • 화면의 각 픽셀마다 카메라로부터의 거리(깊이) 를 저장하는 버퍼.
  • 렌더링할 때:
    1. 새 픽셀의 깊이와
    2. 이미 저장된 깊이를 비교(ZTest)해서 → 더 가까운 것만 화면에 남김.

그래서,

  • 먼 오브젝트 뒤에 가까운 오브젝트가 오면 자연스럽게 가려짐.

ZWrite / ZTest 의미

  • ZWrite On : 그리면서 깊이 버퍼에 값 기록
  • ZWrite Off : 색은 칠하지만 깊이 버퍼에는 기록 안 함 → 투명한 존재처럼 취급
  • ZTest LEqual : 새로 그리는 픽셀이 기존보다 “같거나 더 가까우면” 그린다(기본).

내 문제의 포인트

Skybox 셰이더는 ZWrite Off 라서,

  • 구 내부에 배경은 그렸지만 깊이가 안 찍힘
  • 뒤에 있는 건물 메쉬가 나중에 그려지면서
    → 깊이 테스트에 막히지 않고 그냥 위에 덮어 씀
    그래서 배경이 “뚫려 보이는” 것처럼 보였던것

위의 셰이더에서

  • ZWrite On + ZTest LEqual 로 바꿨기 때문에
    구가 깊이 버퍼를 차지
    구 밖 오브젝트는 그 뒤에 가려져서 안 보이는 것.

Render Queue(렌더링 순서)

기본 큐 개념

Unity는 머티리얼마다 Render Queue(숫자)를 가지고 있고 작은 숫자 → 먼저, 큰 숫자 → 나중에 렌더링한다

대표적인 값:

  • Background : 1000 (하늘, 배경)
  • Geometry : 2000 (일반 메쉬)
  • Transparent : 3000 (투명 오브젝트)

Skybox가 왜 Background에 있는가?

  • Skybox는 “제일 뒤에 깔리는 배경”이어서
    • 무조건 다른 모든 오브젝트 보다 먼저 보이도록
    • Queue = Background(1000) + ZWrite Off로 설정됨.
  • 그래서 카메라 Clear 단계에서 그냥 “배경 칠하기” 역할만 함

 바꾼 부분

  • 새 셰이더는 Tags { "Queue"="Geometry" }
    • 다른 일반 오브젝트와 같은 레벨에서 렌더링.
    • 근데 구가 카메라를 둘러싸고 있고, ZWrite도 켜져 있으니
      화면 전체 깊이를 선점
      → 뒤에 있는 어떤 Geometry도 더 뒤라서 안 보이는 구조.

 

Face Culling(전·후면 제거)과 Cull Front

 Culling이란?

  • 삼각형에는 그려지는 방향(시계/반시계)이 있고,
  • GPU는 보통 카메라에서 보이지 않는 면(뒤쪽 면) 을 자동으로 버려서 성능을 올린다.
  • 기본값: Cull Back
    → 카메라에서 보는 겉면만 렌더링.

 Inside Sphere 문제

우리는 구 안에 카메라를 두고, 구의 “내부” 표면을 보고 싶다.

하지만,

  • 기본 Cull Back이면 내부에서 보게 될 삼각형은 전부 뒷면 취급 → 안 그려짐.

해결: Cull Front

  • Cull Front : 앞면을 버리고, 뒷면만 렌더
  • 구가 카메라를 둘러싸고 있는 경우,
    • 카메라 입장에서는 사실상 “구의 내부면 = 뒷면”
    • 그래서 Cull Front를 사용하면 구 안쪽 표면만 그려짐.

즉,

  • 카메라를 속 빈 구 안에 넣고, 내부 표면에만 Cubemap을 그리는 구조가 완성됨.

Cubemap과 환경 매핑

 Cubemap 개념

  • 정육면체 6면에 이미지가 들어있는 텍스처.
  • 보통 360도 환경(스카이박스, 리플렉션) 을 표현할 때 사용.

샘플링 방식

Cubemap은 방향 벡터로 샘플한다.

  • 보통 texCUBE(_Cube, direction) 이런 형태
  • direction = (x, y, z)
    → 이 방향으로 향하는 큐브의 면과 좌표에서 색을 가져옴.

우리가 사용한 방향 벡터

셰이더에서:

 
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldDir = normalize(worldPos - _WorldSpaceCameraPos);
 
  • worldPos : 구 표면의 월드 좌표
  • worldPos - _WorldSpaceCameraPos :카메라 → 구 표면 방향 벡터
  • 이걸 정규화해서 Cubemap에 넣으면
    • 카메라가 보는 방향에 따라
    • 실내 환경이 따라 보이는 360도 배경이 됨.

여기에 col.rgb *= _Exposure; 로 밝기 조절만 추가.

 

기존 Skybox/Cubemap 셰이더 vs 우리가 만든 셰이더

항목 Skybox/Cubemap (기존) Custom/InsideSkySphere (우리가 사용)
용도 카메라 배경 Mesh(구) 내부용 배경
Queue Background(1000) Geometry(2000)
ZWrite Off On
ZTest LEqual (비슷) LEqual
Cull Back Front
깊이 역할 없음 (뒤 오브젝트 안 가림) 있음 (뒤 오브젝트 완전히 가림)
적용 대상 카메라 Skybox 슬롯 Sphere Mesh의 Material

그래서 같은 Cubemap을 써도 완전 다른 효과가 나오는 것.

 

해결 방식 흐름 정리

  1. 기존 문제 인식
    • Skybox 셰이더가 깊이 버퍼를 쓰지 않아
      → 구 밖의 오브젝트가 위에 렌더링됨.
  2. 목표 정의
    • 구 안에서만 배경을 보고
    • 구 밖의 어떤 오브젝트도 보이지 않게(완전 차단).
  3. 그래픽스 설계
    • 카메라를 덮는 거대한 구” + “내부만 렌더링” 구조 선택.
    • 깊이 버퍼를 차지해서 다른 오브젝트를 가려야 하므로
      → ZWrite On, Queue = Geometry.
  4. 셰이더 구현 포인트
    • Cull Front 로 내부 표면만 보이게.
    • ZWrite On으로 깊이 버퍼 채우기.
    • texCUBE 로 Cubemap 샘플링.
    • Exposure 프로퍼티로 밝기 조절.
  5. 결과
    • 카메라 시점에서 화면 전체가 스카이스피어의 픽셀로 채워짐.
    • 다른 Geometry는 깊이 테스트에서 모두 “더 멀다” 판정 → 렌더 안 됨.

 

 

https://illu.tistory.com/1445

 

URP Shader coding guide Basic term

URP Shader Training에 사용된 문서. 기본 Opaque, Alphatest, Transparent 3종류의 셰이더 작성과 기본 응용을 포함하고 있다. 셰이더 기초 작성에 대한 가이드이지 이걸 실제 프로젝트에 사용하기에는 무리가

illu.tistory.com

 

반응형

'그래픽스' 카테고리의 다른 글

urp 홀로그램 effect  (1) 2026.02.20
TA 문서  (0) 2026.01.21
회사 복도 쉐이더 만들기(삽질~)  (0) 2025.06.30
Camera Distance Mask  (2) 2025.06.30
Altitude Mask 그래프  (0) 2025.06.30