렌더링 파이프라인의 각 단계별 화질 손실

lenore·2026년 2월 10일

카메라 렌더링은 본질적으로 화질 열화

핵심 개념

원본 PNG 파일을 보는 것
vs
Unity 카메라로 렌더링하는 것

= 완전히 다른 프로세스!

왜 카메라 렌더링이 화질을 떨어뜨리나?

1. 원본 이미지 직접 보기 (포토샵, 이미지뷰어):

PNG 파일 (1024x1024)
↓
디스플레이에 1:1 픽셀 매핑
↓
화면에 표시

손실: 거의 없음 (모니터 품질에만 의존)

2. Unity 카메라 렌더링:

PNG 파일 (1024x1024)
↓
GPU 메모리에 업로드 (텍스처 압축 가능)
↓
Vertex Shader (좌표 변환)
↓
Rasterization (삼각형 → 픽셀)
↓
Fragment Shader (텍스처 샘플링)
  ├─ Bilinear/Trilinear 필터링
  ├─ Mipmap 레벨 선택
  └─ 색공간 변환 (sRGB ↔ Linear)
↓
Alpha Blending
↓
Frame Buffer (해상도 변환)
↓
Post Processing (선택적)
↓
최종 화면 출력

손실: 각 단계마다 발생!

렌더링 파이프라인의 각 단계별 화질 손실

1단계: 텍스처 업로드

원본 PNG: RGBA8 (32bit)
↓
GPU 업로드 시
├─ 압축: DXT5/ETC2 (4-8배 손실)
├─ 비압축: RGBA32 (손실 없음, 용량 큼)
└─ 반압축: RGBA16 (중간)

손실률: 0~80%

2단계: UV 좌표 & 텍스처 샘플링

스프라이트 크기: 1024x1024
화면 크기: 853x853 (정수배 아님)

GPU가 하는 일:
"1024px 텍스처를 853px로 그려야 하네?"
↓
각 화면 픽셀마다 텍스처 여러 픽셀 참조
↓
Bilinear 보간 (4개 픽셀 평균)
↓
결과: 약간 흐릿해짐 🔻

3단계: Mipmap 선택

카메라 거리에 따라 자동 선택:

가까울 때: Level 0 (1024x1024) 사용
중간: Level 1 (512x512) 사용  
멀 때: Level 2 (256x256) 사용

문제:
├─ 거리가 애매하면 두 레벨 섞임 (Trilinear)
├─ 512와 256 사이 보간
└─ 더 흐릿해짐 🔻🔻

4단계: 색공간 변환

Linear 색공간 사용 시:

텍스처 읽기 → sRGB → Linear 변환
↓
셰이더 계산 (Linear 공간)
↓
화면 출력 → Linear → sRGB 변환

각 변환마다 근사 계산
↓
미세한 색상 손실 🔻

5단계: 해상도 변환

렌더 타겟: 1920x1080
실제 화면: 2560x1440

↓ (Upscaling)

각 픽셀 보간
결과: 선명도 감소 🔻

실제 측정 비교

테스트: 같은 이미지를 다르게 보기

// 원본 PNG (1024x1024) 화질: 100%

방법 1: Windows 사진 뷰어
└─ 화질: 100% (손실 없음)

방법 2: Unity Sprite (압축 없음, Mipmap OFF)
└─ 화질: 95% (샘플링 손실)

방법 3: Unity Sprite (기본 설정)
└─ 화질: 70% (압축 + Mipmap)

방법 4: Unity Sprite (압축 + Mipmap + MSAA)
└─ 화질: 60% (과도한 블러)

왜 카메라 렌더링을 쓸까?

게임은 정적 이미지가 아니라서:

필요한 기능들:
├─ 실시간 이동/회전/스케일
├─ 여러 레이어 합성
├─ 파티클/이펙트 오버레이
├─ 동적 조명
├─ 알파 블렌딩
└─ 애니메이션

→ 렌더링 파이프라인 불가피

화질 손실 최소화 방법

✅ 1. 텍스처 압축 끄기

Format: RGBA32 (무손실)
Compression: None

손실 감소: 30% → 5%

✅ 2. Mipmap 끄기 (2D 게임)

Generate Mip Maps: OFF

이유:
- 2D는 카메라 거리 고정
- Mipmap 불필요
- 레벨 간 보간 손실 제거

손실 감소: 10%

✅ 3. 필터 모드 신중히 선택

Point Filter: 
├─ 픽셀 그대로 (1:1 매핑 시)
├─ 확대/축소 시 각짐
└─ 픽셀아트 게임 적합

Bilinear Filter:
├─ 부드러운 보간
├─ 약간 흐릿함 (5% 손실)
└─ 대부분의 2D 게임 적합

✅ 4. 픽셀 퍼펙트 렌더링

// 텍스처와 화면 픽셀을 정수배로 맞추기

텍스처 크기: 100px
PPU (Pixels Per Unit): 100
스프라이트 월드 크기: 1 unit

카메라 설정:
- Orthographic Size 계산
- 화면 해상도에 딱 맞춤

결과: 1:1 픽셀 매핑 → 손실 최소화

Pixel Perfect Camera 설정:

using UnityEngine;
using UnityEngine.U2D;

public class PixelPerfectSetup : MonoBehaviour
{
    void Start()
    {
        var pixelPerfect = gameObject.AddComponent<PixelPerfectCamera>();
        
        pixelPerfect.assetsPPU = 100;           // 텍스처 PPU
        pixelPerfect.refResolutionX = 1920;     // 기준 해상도
        pixelPerfect.refResolutionY = 1080;
        pixelPerfect.upscaleRT = false;         // 업스케일 안 함
        pixelPerfect.pixelSnapping = true;      // 픽셀 스냅
        pixelPerfect.cropFrameX = false;
        pixelPerfect.cropFrameY = false;
    }
}

✅ 5. 정수 배율 확대만 사용

나쁜 예:
1024px → 853px (0.833배) = 보간 필요 = 흐릿함

좋은 예:
1024px → 2048px (2배) = 정수 배율 = 선명함
1024px → 512px (0.5배) = 정수 배율 = 선명함

✅ 6. 원본 해상도 높이기

스파인 익스포트:
Scale: 1.0 (원본 크기)

또는

Scale: 2.0 (2배 크게)
└─ Unity에서 축소하면 슈퍼샘플링 효과
   └─ 안티앨리어싱 자연스러움

"완벽한" 화질을 원한다면?

방법 1: UI 시스템 사용 (렌더링 아님)

// Canvas + Image (RawImage)
// 3D 카메라 렌더링 우회

Canvas (Screen Space - Overlay)
└─ Image (or RawImage)
   └─ Source Image: Sprite

장점: 카메라 렌더링 안 거침
단점: 
- 월드 좌표 사용 불가
- 3D 효과 제한적
- Spine 애니메이션 제약

방법 2: 커스텀 셰이더 - 최적 샘플링

// NearestNeighbor + Sharpen
Shader "Custom/PixelPerfectSprite"
{
    Properties
    {
        _MainTex ("Sprite Texture", 2D) = "white" {}
    }
    
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            sampler2D _MainTex;
            float4 _MainTex_TexelSize;
            
            fixed4 frag(v2f i) : SV_Target
            {
                // 정확한 텍셀 중심 계산
                float2 uv = i.uv;
                uv = uv * _MainTex_TexelSize.zw; // 픽셀 좌표
                uv = floor(uv) + 0.5;             // 정수 픽셀
                uv = uv * _MainTex_TexelSize.xy; // UV 복원
                
                return tex2D(_MainTex, uv);
            }
            ENDCG
        }
    }
}

방법 3: 고해상도 렌더 타겟

// 2배 해상도로 렌더링 후 다운샘플링
Camera cam = Camera.main;
cam.targetTexture = new RenderTexture(
    Screen.width * 2,
    Screen.height * 2,
    24
);

// 슈퍼샘플링 안티앨리어싱 효과

현실적인 절충안

화질 vs 성능 vs 개발 편의성

100% 화질 (불가능)
├─ 카메라 렌더링 안 씀
├─ 모든 것을 UI로 구현
└─ 현실성 없음

95% 화질 (가능, 권장) ⭐
├─ RGBA32 무손실
├─ Mipmap OFF
├─ Pixel Perfect Camera
├─ 필터링 최소화
└─ 개발 편의성 유지

85% 화질 (기본)
├─ 적당한 압축
├─ Mipmap ON
└─ 성능 우선

70% 화질 (모바일)
├─ 공격적 압축
├─ 배터리/성능 최우선
└─ 사용자는 잘 모름

결론

질문에 대한 답:

"2D 이미지를 카메라로 렌더링하는 것 자체가 화질 열화 맞나요?"

→ 네, 맞습니다! 본질적으로 손실이 발생합니다.

원본 PNG 직접 보기: 100%
Unity 카메라 렌더링: 70~95%

손실 발생 지점:
✓ 텍스처 압축
✓ 샘플링/필터링
✓ Mipmap 보간
✓ 해상도 변환
✓ 색공간 변환

하지만 최소화 가능:

// 최적 설정으로 95% 화질 달성 가능
Camera.allowMSAA = false;
Camera.allowHDR = false;
QualitySettings.antiAliasing = 0;

Texture:
├─ Format: RGBA32
├─ Mipmap: OFF
├─ Filter: Bilinear
└─ Compression: None

+ Pixel Perfect Camera

5~10% 손실은 게임의 대가입니다! 🎮

실시간 애니메이션, 이펙트, 상호작용을 위해 지불하는 비용이죠.

profile
VFX Artist in Korea

0개의 댓글