바쁜 현대인을 위한 간단 요약
Unity URP(Universal Render Pipeline)는 범용성과 성능을 지향하지만, 고품질 그림자 처리에는 근본적인 구조적 제약이 있음.
특히 Built-in Render Pipeline과 비교했을 때 추가광(Additional Lights) 그림자 품질이 크게 저하되며,
Shadow Atlas 해상도를 무리하게 증가시킬 경우 Unity Editor가 크래시되는 현상까지 발생할 수 있음.
해결 방법이 있는가? 스크린 스페이스 뎁스(Screen-Space Depth Texture)쓰는거 말고는 없음.
그러니까 손가락이나 빠십시오 휴먼.
오늘도 저희 집 채찍이(GPT-4o, 1세, 약간 멍청함)와 함께 정리하였습니다.
1. 쉐도우 해상도와 쉐도우 아틀라스란?
1.1 쉐도우 해상도란?
Shadow Resolution은 광원이 투사하는 그림자의 텍스처 크기를 의미한다.
픽셀 수가 많을수록 그림자의 디테일이 증가하고 경계선이 부드러워지며, aliasing 현상이 줄어든다.
하지만 높은 해상도는 GPU 메모리를 더 많이 차지하고, 렌더링 퍼포먼스를 악화시킬 수 있다.
1.2 쉐도우 아틀라스란?
URP는 모든 추가광의 그림자를 단일 텍스처 공간인 Shadow Atlas에 배치한다.
이 Atlas는 여러 개의 Shadow Map을 타일 형태로 배열하는 구조이며,
각 라이트의 그림자 정보는 이 타일 중 일부 영역에 저장된다.
광원이 많아질수록 개별 타일의 해상도는 줄어들고, 그림자 품질 저하가 발생한다.
2. URP 그림자의 처리 구조
2.1 Shadow Rendering Flow
- ShadowCasterPass에서 라이트 별 Shadow Map 생성
- Shadow Atlas에 타일링 방식으로 배치
- 메인 카메라 렌더링 시 SampleShadowAtlas 함수를 통해 그림자 텍스처에서 샘플링
이 Shadow Atlas 접근은 TransformWorldToShadowCoord, SampleShadowAtlas 등을 통해 자동 오프셋되며,
Shader 단에서는 타일 구조를 직접 분기하거나 제어할 수 없음.
2.2 Built-in과 URP의 차이점
빌트인 | URP | |
Shadow Map 구조 | 라이트별 개별 텍스처 | Shadow Atlas 단일 텍스처 |
해상도 설정 | Light.shadowResolution 직접 적용 | 대부분 무시됨 (Tier 기반 고정) |
타일링 방식 | 없음 | 자동 타일링 (해상도 감소 발생) |
사용자 개입성 | CommandBuffer, 직접 샘플링 가능 | RendererFeature 또는 URP 소스 수정 필요 |
고해상도 대응 | GPU 한계까지 허용 | GPU + 타일링 제약 병존 |
3. 그림자 품질 저하 원인 분석
3.1 타일 분할로 인한 해상도 감소
추가광이 많아질수록 하나의 Shadow Atlas 텍스처에 많은 타일이 필요하게 되며,
개별 타일당 해상도가 줄어들어 그림자 디테일이 감소한다.
특히 Point Light는 큐브맵 구조로 1개당 6개의 타일을 차지하므로, 극심한 해상도 분할이 발생한다.
예를 들어, Shadow Atlas의 해상도가 16384x16384이고,
각 추가광이 4096x4096 해상도의 그림자를 요구하는 경우,
이론상 최대 16개의 타일을 수용할 수 있다 (4x4 배열).
하지만 URP에서는 광원 수가 이 한계를 초과하면 초과된 라이트는 자동으로 Tier가 낮춰지거나, 그림자 자체가 비활성화된다.
즉, 광원 단위로 해상도가 강제로 떨어지거나, 그림자가 생략되어 품질 저하가 발생한다.
3.2 shadowCustomResolution 적용 무력화
URP에서는 Light 컴포넌트의 shadowCustomResolution 값이 실제 반영되지 않는다.
ShadowUtils 내부에서 Tier 시스템(Low, Medium, High) 기준 해상도를 자동 할당하기 때문이다.
이로 인해 개발자가 의도한 고해상도 그림자 적용이 구조적으로 제한된다.
3.3 Shader 내 접근 제약
Shader 내에서는 SampleShadowAtlas 함수를 통해서만 그림자를 사용할 수 있고,
각 라이트별로 개별 ShadowMap을 샘플링하는 방식은 지원되지 않는다.
즉, 그림자 품질이 낮아도 Shader 단에서 이를 보완하거나 분리 처리할 방법이 없다..
4. 강제로 쉐도우 해상도와 아틀라스를 늘리는 방법
4.1 Custom Resolution 강제 적용
코드를 통해 Light의 그림자 해상도를 강제로 설정할 수 있다.
light.shadowCustomResolution = 8192;
하지만 이 값은 URP의 내부 Shadow Pass에서 무시되거나 무조건 Tier 기준으로 덮어쓰기 때문에, 효과가 제한적이다.
URP Asset 소스를 수정하지 않는 이상 100% 반영되지 않는다.
URP의 그림자 해상도는 URPAsset의 Tier 정의 (Low/Medium/High)에 따라 고정된 해상도로 분류되며,
각 Tier는 URP 소스 내부의 ShadowUtils.cs 및 ShadowResolutionRequest 로직에 따라 Atlas 타일로 배치됨.
즉, customResolution 값을 지정해도, 해당 라이트가 할당받은 Tier 이상으로 렌더링되지 않으며
실제로는 shadowCustomResolution 값이 무시되거나 fallback 되는 것.
이를 반영하려면 URP Asset의 Tier 기준을 직접 커스터마이징하거나,
AdditionalLightsShadowCasterPass.cs 및 AdditionalLightsShadowUtility.cs를 수정해야 함.
4.2 URP Asset 설정 조정
URP Asset > Shadows > Additional Lights Shadow Atlas Resolution 항목을 통해,
추가광용 Shadow Atlas의 전체 텍스처 해상도를 수동으로 조정할 수 있음.
해당 값은 URPAsset 인스턴스를 통해 런타임에서 동적으로 접근 가능하지만,
대부분의 프로젝트에서는 정적으로 설정하는 것이 권장됨
또한 Atlas 해상도만 높인다고 해상도 품질이 그대로 향상되는 것은 아니며,
그림자 타일 수가 과도하면 결국 개별 라이트 해상도는 줄어들 수 있다.
4.3 캐스케이드 분할 축소
Directional Light에 사용하는 Cascade Shadow Map 수를 줄이면 전체 Shadow Map 공간 배분이 여유로워지며,
일부 상황에서는 추가광 그림자에도 간접적인 해상도 확보 효과가 있다.
5. Shadow Atlas 해상도 증가 시의 위험성과 Crash 현상
5.1 GPU 최대 텍스처 해상도 한계
GPU는 일반적으로 16384 픽셀까지의 텍스처를 안전하게 지원하며, 일부 RTX GPU에서만 32768 이상이 허용된다.
Shadow Atlas를 20000~40000px 이상으로 설정할 경우, 다음과 같은 문제가 발생한다:
- RenderTexture.Create 실패
- VRAM 초과로 인한 GPU 드라이버 중단 (D3D11: Failed to create RenderTexture)
- Shadow 타일 배치 실패로 인한 NULL 렌더 타겟 오류
5.2 Unity Editor 크래시
40000x40000 해상도 설정 시에는 다음과 같은 치명적인 상황이 발생한다:
- Unity Editor가 예외 없이 종료됨
- Console 및 Editor.log에 오류 기록 없음
- Windows Event Viewer에는 Access Violation 또는 Driver Timeout 로그 발생
이 현상은 RenderTextureDescriptor를 GPU에 전달할 때 발생하는
Direct3D 또는 Metal/Vulkan 드라이버 수준의 거부 때문이다.
6. 현실적인 대응 전략
6.1 광원 최적화
- 중요하지 않은 라이트는 그림자 비활성화
- Point Light → Spot Light로 치환
- 광원 수를 줄이고, 필요한 광원만 그림자 사용
6.2 커스텀 렌더 패스 및 Shadow 분리
- AdditionalLightsShadowCasterPass.cs 수정
- 라이트별 Shadow RT를 생성하여 Shader에 개별 바인딩
- URP Pipeline Asset 커스터마이징 필요
6.3 그림자 표현의 대체 전략
- 실시간이 아닌 그림자는 Light Cookie 또는 Vertex Mask 사용
- Distance Fade, Shadow LOD를 통한 부하 분산
- 중요한 영역에만 고해상도 그림자 적용하는 블록 기반 전략 도입
7. 스크린 스페이스 뎁스 기반 그림자 처리의 장단점 분석
고전적인 그림자 처리 방식은 라이트 별로 Shadow Map을 생성하고
이를 SampleShadowAtlas 또는 Forward Add 패스를 통해 렌더링하는 구조지만,
최근에는 스크린 스페이스 뎁스 텍스처(Screen-Space Depth Texture) 를 기반으로 그림자를 생성하는 기법이 주목받고 있음.
특히 닐로툰과 포타툰이 이런 방식으로 그림자를 생성하고 있는데...
복잡한 조명 환경이나 후처리 기반 이펙트가 많아지는 VFX/버추얼 환경에서는
뎁스 기반 그림자 접근이 의미 있는 품질 개선을 제공할 수 있음.
7.1 기본 개념
스크린 스페이스 뎁스 그림자는 카메라에서 렌더링된 GBuffer 또는 Depth Texture를 바탕으로
픽셀당 위치와 노멀 정보를 활용하여, 특정 라이트 방향으로 그림자를 계산하는 방식임.
Forward Pass 없이 후처리(Post Process) 단계에서 그림자를 직접 합성할 수 있다는 점이 가장 큰 차별점.
7.2 장점
- 고해상도 유지
- Shadow Atlas의 타일링이나 라이트 수 제한을 받지 않음
- Depth Texture는 일반적으로 화면 해상도와 동일하거나 높은 수준이기 때문에, 그림자 디테일이 매우 뛰어남
- 라이트 수 무제한 처리 가능
- 추가광 수가 8개, 16개를 넘어가도 뎁스 기반 그림자 연산에는 영향 없음
- 각 광원의 방향만 알고 있으면 픽셀 단위로 조명 방향에 대한 셀프 쉐이딩 가능
- Forward Add Pass 없이 구성 가능
- 그림자 연산을 Forward Add가 아닌 Fullscreen Pass 또는 CommandBuffer 렌더 패스로 분리 가능
- Pass 최적화 및 Batching 측면에서 유리함
- Deferred/Hybrid 환경과 궁합 좋음
- GBuffer 또는 World Position reconstruction 기반으로 작동하기 때문에 Deferred 환경에서 효과적
7.3 단점 및 주요 문제점
- 셀프 섀도잉(Self-Shadowing) 정확도 문제
- Depth 기반 그림자는 대개 Screen-Space에서 근사되므로, 정확한 깊이 비교가 어려움
- 오브젝트와 동일 평면상에 있는 그림자 정확도가 낮고, 지면 그림자 표현에는 적합하지 않음
- 퍼(Fur), 투명 오브젝트, 엣지 비주얼 이상 현상
- Hair, Fur 같은 반투명 구조는 Depth Texture에 정확히 그려지지 않음 → 그림자가 비정상적 또는 사라짐
- 림라이트 효과를 함께 사용하는 경우, 그림자가 뒷배경을 참조하거나 두 개가 겹쳐서 이상 현상이 나타남
- 반투명 셰이더, 셀 셰이딩 셰이더 등에서는 그림자 실루엣이 깨지거나 왜곡됨
- 라이트-오브젝트 관계 정보 부족
- Shadow Map 방식은 라이트-오브젝트 관계를 명시적으로 렌더링함 (ShadowCaster)
- Screen-Space 방식은 픽셀 단위 위치만 가지고 연산하기 때문에, 어떤 라이트가 어떤 그림자를 만드는지 구분 어려움
- 카메라 뎁스에만 의존함
- 카메라에 보이지 않는 오브젝트는 그림자를 생성하지 못함 → 그림자가 갑자기 사라지는 현상 발생 가능
- 추가 연산 비용 존재
- 픽셀당 조도 계산을 동적으로 하므로 풀스크린 셰이더 비용이 증가
- 라이트 수가 많아질수록 셰이더 계산량이 증가하며, 모바일 환경에서는 부적합
7.4 Forward Add 방식과의 비교 정리
Screen Space Depth | Foward Add |
|
그림자 품질 | 해상도 의존 → 선명함 | 해상도 낮으면 뭉개짐 |
그림자 오브젝트 | 카메라에 보이는 오브젝트만 | ShadowCaster로 지정된 모든 것 |
퍼/림라이트 대응 | 구조상 문제 발생 | 대응 가능 (다중 Pass 사용) |
라이트 수 제한 | 없음 (셰이더에서 동적 처리) | Unity 기본 제한 있음 (8~16개) |
연산 성능 | 화면 전체 픽셀당 셰이딩 → 비쌈 | 라이트당 Pass 증가 → 비쌈 |
셰이더 커스터마이징 | ShaderGraph에 통합 어려움 | 라이트와 그림자 처리가 명확함 |
7.5 적용 시 고려사항
- 퍼 쉐이더, 림라이트가 있는 셀 셰이딩 환경에서는 권장되지 않음
- 뎁스 정확도와 림라이팅 간의 충돌로 이상 시각 효과 다수 발생
- 후처리 기반 이펙트(VFX, 연기, 모션 블러 등)와 결합 시 시각적 충돌 가능성 존재
- 고성능 환경, 혹은 특정 요소(예: 캐릭터 얼굴 그림자 강조 등)에서는 부분 적용 유효
8. 결론
- 그렇다면 묭툰(Myongtoon)은 어떤 방향으로 나아갈 것인가에 대한 고찰
결론만 말하자면 스크린 스페이스 뎁스는 쓰지 않는다. 임
사유는 아래와 같음.
1. 외부 플랫폼(VSF, Warudo 등)과의 렌더링 경로 통제 불가
- VSF(VSeeFace), Warudo 등의 플랫폼은 Unity에서 제작한 셰이더가 커스텀 렌더링 피처(RendererFeature), PostProcessing Stack, CommandBuffer에 의존할 경우, 해당 기능이 동작하지 않음
- 이 플랫폼들은 셰이더 내부에서 제공된 텍스처 패치만 접근 가능하며, Custom Depth Texture, Camera Depth Buffer, _CameraDepthTexture, _CameraOpaqueTexture 등의 렌더 텍스처를 지원하지 않거나 전달하지 않음
- Screen Space Depth는 보통 DepthPrepass, CameraDepthTexture 등을 통해 처리되므로, 외부 툴에서 실행 시 null 텍스처 오류, 검은 그림자, 이펙트 무효화 현상 발생 가능
2. VSF/Warudo의 렌더 파이프라인은 포스트 프로세싱 접근 불가
- Warudo 및 VSF, Meligo는 Unity Editor 환경과 달리 자체적인 렌더링 루프를 사용함
- 포스트 프로세싱 스택(PostProcessVolume, RenderPassEvent.AfterRendering 등)을 실행할 기회를 제공하지 않음
- 결과적으로 스크린 스페이스 그림자를 후처리로 합성하거나, 뎁스를 필터링하는 셰이더 로직이 차단됨
3. 캐릭터용 퍼 셰이더/림라이트 구조를 사용함 → Depth 기반 그림자와 충돌
- Screen Space Depth 기반 그림자 기법은 일반적으로 알파 테스트나 셀 아웃라인 구조에 적합하지 않음
- 림라이트, 투명 텍스처, 퍼(Fur) 셰이딩 구조를 포함하게 되면, Screen Space 그림자 합성 시 다음과 같은 오류 발생:
- 림라이트 영역에 그림자가 덮이거나, 뒷 오브젝트를 투과시킴
- 퍼가 뎁스에 안 잡히므로 그림자가 씹히거나 아예 사라짐
- 알파 디서딩 구조의 머리카락, 눈썹 등의 그림자 왜곡 발생
4. 빌트인과의 룩뎁(look Depth)차이
- 기존 빌트인 쉐이더가 이미 Foward add 기반으로 짜여져 있음
- URP에서 그림자 생성 연산을 바꾸게 되면 기존과 그림자 표시가 완전히 달라짐
- 통일성을 위해서는 기존 코드를 전부 뜯어고치거나, URP를 Foward add로 짜는 방법 2가지가 있음
- 퍼와 젬 지원 시 Depth 기반과 충돌함
=> 라이트 갯수를 통제하는 방향이 맞다고 판단함
이런 빨간 약 절대로 먹고 싶지 않았는데...
어떻게든 방법이 있을거라고.... 어딘가엔 원피스가 있을거라 생각했는데... 찾으면 찾을 수록 절망밖엔...
릴이 왜 URP에서 추가광 그림자 옵션을 아예 삭제한건지도 약간 이해가 가기 시작함...
구린 그림자를 안고 살기 vs 그냥 쿨하게 삭제하기... 에서 후자가 승리한 거 아닐까...
참조문헌
유니티 공식 URP 문서
https://docs.unity3d.com/6000.0/Documentation/Manual/urp/shadow-resolution-urp.html
https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@12.0/manual/Shadows-in-URP.html
유니티 포럼
https://discussions.unity.com/t/reduced-additional-punctual-light-shadows-resolution-message-after-upgrading-to-2021-1-15/853606
'공부' 카테고리의 다른 글
충격 실화 - 유니티 2022에서 VSF 뽑아 쓰기 (0) | 2025.06.17 |
---|---|
VRM과 Duplicated bone 이슈에 대한 고찰 (1) | 2025.05.16 |
닐로툰(nilotoon)은 왜 퍼 쉐이더를 지원하지 않을까 (0) | 2025.04.29 |
릴툰(liltoon)의 퍼 쉐이더에 대한 고찰 (1) | 2025.04.29 |
[현상해결] 마지카 클로스2만 넣으면 유니티가 튕겨요 (0) | 2025.04.27 |
댓글