CS/그래픽스

[Rendering Optimization] Stage 6 : Fragment (Pixel) Shader (Pixel Processing)

tae-woong 2026. 1. 20. 18:43

개발자가 쉐이더 코드로 제어 가능한 영역입니다.

 

HLSL/CG/GLSL 등을 통해 픽셀의 색상을 결정하는 코드를 직접 작성합니다.

 

조명(Lighting), 텍스처(Texture), 그림자(Shadow) 등 그래픽의 핵심이 여기서 결정됩니다.

 

개요

이 단계는 "색칠을 하는 단계"입니다.

 

5단계(Rasterization)를 통과한 픽셀들에게 최종 색상 값을 부여합니다.

 

화면 해상도가 높을수록, 혹은 화면을 덮는 물체가 많을수록(Overdraw) 실행 횟수가 폭발적으로 증가하므로 "필 레이트(Fill Rate = 초당 화면에 렌더링되고 비디오 메모리에 기록될 수 있는 화소의 수)" 싸움이 일어나는 곳입니다.

 

<핵심 목표>

  1. Reduce Instruction Count : 픽셀 하나를 칠할 때 수행하는 연산(사칙연산, 텍스처 읽기)의 횟수를 줄입니다.
  2. Optimize Memory Bandwidth : 텍스처를 읽어오는 과정에서 대역폭 낭비를 줄입니다. (밉맵, 압축)
  3. Preserve Early-Z : 5단계의 최적화를 방해하는 코드를 작성하지 않습니다.

 

최적화 방법

1. Mipmapping (밉맵)

  • 설명 : 텍스처의 원본 해상도(Level 0) 외에, 해상도를 절반씩 줄인 사본들(Level 1, 2, 3...)을 미리 메모리에 만들어두는 기법입니다. 카메라와 멀리 있는 물체는 작은 텍스처(높은 Level)를 읽어서 색을 입힙니다.
  • 지금 단계에서 효과 :
    • Stage 6 (PS) 자체 : 픽셀 쉐이더가 텍스처를 읽을 때 텍스처 캐시 적중률(Texture Cache Hit Rate)이 비약적으로 상승하여 연산 속도가 빨라집니다.
  • 장점 :
    • 렌더링 속도 증가 : 캐시 효율 덕분에 대역폭 병목을 해소합니다.
    • 품질 향상 : 멀리 있는 물체의 텍스처가 자글거리는 현상(Aliasing/Moire)을 제거합니다.
  • 단점 :
    • 메모리 사용량 증가 : 원본 텍스처보다 약 33% 더 많은 메모리 공간을 차지합니다. (1/4 + 1/16 + ... = 1/3)
  • ※ 헷갈리기 쉬운 포인트 : Mipmapping(6단계) vs LOD(2단계)
    • LOD : "멀리 있으면 간단한 메쉬를 씀" (버텍스 줄이기)
    • Mipmapping : "멀리 있으면 작은 텍스처를 씀" (대역폭 줄이기)
    • 보통 둘을 같이 씁니다.

2. Texture Compression (텍스처 압축)

  • 설명 : JPG나 PNG 같은 파일 압축이 아니라, GPU가 압축된 상태 그대로 읽어서 해독(Decode)할 수 있는 전용 포맷(ASTC, ETC2, BC7 등)으로 텍스처를 저장하는 것입니다.
  • 지금 단계에서 효과 :
    • Stage 6 (PS) 자체 : 텍스처 데이터를 메모리에서 가져오는 대역폭(Bandwidth) 소모량을 1/4 ~ 1/8 수준으로 줄입니다.
  • 장점 :
    • 발열 및 배터리 최적화 : 모바일 게임에서 발열을 잡는 가장 핵심적인 기술입니다.
    • 메모리 절약 : VRAM 사용량을 대폭 줄여 튕김 현상(OOM)을 방지합니다.
  • 단점 :
    • 화질 저하 : 손실 압축이므로 원본보다 색감이 탁해지거나 노이즈(Artifact)가 생길 수 있습니다. (UI나 노말맵은 압축 시 주의 필요)
  • ※ 헷갈리기 쉬운 포인트 : 압축(Zip) vs 텍스처 압축(ASTC)
    • Zip/PNG : CPU가 풀어서 메모리에 올려야 함. (로딩 느림, 메모리는 원본 크기로 차지)
    • ASTC/ETC : GPU가 압축된 채로 메모리에 올리고, 쉐이더가 읽을 때 즉시 풂. (메모리 작게 차지, 대역폭 이득)

3. Precision Reduction (연산 정밀도 최적화)

  • 설명 : 2단계(VS)와 마찬가지로, 픽셀 쉐이더 코드 내부에서도 변수 선언 시 float(Highp) 대신 half(Mediump)나 fixed(Lowp)를 적극적으로 사용합니다.
    • 색상(Color), 라이팅 연산 : 대부분 half로 충분함.
    • 월드 좌표(World Pos), Depth : float 권장.
  • 지금 단계에 효과 :
    • Stage 6 (PS) 자체 : 모바일 GPU(Adreno, Mali 등)에서 연산 속도(Throughput)가 2배 가까이 빨라지고 전력 소모가 줄어듭니다.
  • 장점 :
    • 모바일 필수 테크닉 : PC에서는 큰 차이가 없으나, 모바일에서는 프레임 방어의 핵심입니다.
  • 단점 :
    • Color Banding : 그라데이션 표현 시 색이 부드럽게 이어지지 않고 층이 지는 현상(등고선)이 생길 수 있습니다.
  • ※ 헷갈리기 쉬운 포인트 : 셰이더 코드 상의 float vs C# 코드 상의 float
    • C#의 float는 32bit입니다.
    • 셰이더(HLSL)의 float도 32bit지만, half는 16bit입니다. C#에는 half 타입이 기본적으로 없으므로 셰이더 작성 시에만 신경 쓰면 됩니다.

4. discard 사용 자제

  • 설명 : 픽셀 쉐이더 코드에서 clip()이나 discard 명령어를 사용하여 픽셀을 강제로 지우는(구멍 뚫는) 행위를 피합니다. (나뭇잎, 찢어진 천 등을 표현할 때 주로 쓰던 방식입니다.)
  • 이전 + 지금 단계에서 효과 :
    • Stage 5 (Rasterization) : Early-Z(깊이 미리 검사) 및 HSR(모바일 타일 최적화) 기능이 깨지지 않고 정상 작동하게 합니다.
    • Stage 6 (Pixel Shader) : Early-Z가 작동하므로, 가려진 픽셀에 대해 쓸데없는 쉐이더 연산(Overdraw)을 안 하게 됩니다.
  • 장점 :
    • Overdraw 방지 : 하드웨어의 자동 최적화 기능을 살려서 전체적인 렌더링 효율을 높입니다.
  • 단점 :
    • 표현의 제약 : 알파 테스트(Cutout)를 못 쓰면, 알파 블렌딩(Transparent)을 써야 하는데, 이는 렌더링 순서 문제(Sorting Issue)나 성능 비용이 또 다르게 발생할 수 있습니다.
  • ※ 헷갈리기 쉬운 포인트 : Alpha Test vs Alpha Blending
    • Alpha Test (= discard) : 픽셀을 "안 그리고 취소"함. (Early-Z 깸, 모바일 성능 나쁨, 외곽선 거침)
    • Alpha Blending : 픽셀을 "뒤랑 섞음". (Early-Z는 되지만 오버드로우 발생, 외곽선 부드러움) -> 상황에 따라 골라 써야 하는 딜레마가 있음.