CS/그래픽스

[Rendering Optimization] Stage 2 : Vertex Shader (Coordinate Transformation)

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

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

 

버텍스 쉐이더(HLSL/GLSL)를 통해 개발자가 직접 연산 과정을 작성할 수 있습니다.

 

따라서 불필요한 수학 연산을 줄이거나 정밀도를 조절하는 등 직접적인 코드 최적화가 가능합니다.

 

개요

이 단계는 "모양을 결정하는 단계"입니다.

 

1단계(IA)에서 조립된 정점(Vertex)들을 하나씩 넘겨받아, 월드 공간(3D)에 있는 좌표를 카메라가 보는 화면 공간(2D Clip Space)으로 변환하는 작업을 수행합니다.

 

이 단계의 연산량은 (정점의 개수) × (셰이더의 복잡도)에 비례합니다.

 

따라서 정점을 줄이거나, 정점 하나당 계산하는 수식을 가볍게 만드는 것이 최적화의 핵심입니다.

<핵심 목표>

  1. Reduce Vertex Count : 처리해야 할 정점의 절대적인 개수를 줄입니다. (LOD)
  2. Simplify Calculation : 정점 하나를 변환할 때 드는 수학적 비용을 줄입니다. (Skinning 제한, 정밀도 조절)

 

최적화 방법

1. LOD (Level of Detail)

  • 설명 : 카메라와의 거리에 따라 폴리곤 수가 다른 모델(LOD 0, LOD 1, LOD 2...)로 교체하여 렌더링하는 기법입니다. 가까이 있는 주인공은 고해상도(High Poly)로, 멀리 있는 배경 npc는 저해상도(Low Poly)로 그립니다.
  • 지금 + 이후 단계에 효과 :
    • Stage 2 (VS) : 계산해야 할 정점의 총량이 급격히 줄어들어 버텍스 쉐이더 병목을 해결합니다.
    • Stage 5 (Rasterization) : 멀리 있는 물체의 폴리곤이 너무 작아져서 생기는 'Sub-pixel' 연산 낭비(Quad Overdraw)를 방지합니다.
  • 장점 :
    • 확실한 성능 향상 : 오픈 월드나 오브젝트가 많은 게임에서 Vertex Shader 부하를 줄이는 가장 효과적이고 표준적인 방법입니다.
  • 단점 :
    • 메모리 사용량 증가 : 단계별 모델 데이터를 모두 메모리에 올려야 하므로 VRAM 사용량이 늘어납니다.
    • Popping 현상 : 모델이 교체되는 순간(LOD 0 ↔ LOD 1) 외형이 툭 바뀌는 것이 눈에 띌 수 있습니다. (Cross-fading 기술로 완화 가능)
  • ※ 헷갈리기 쉬운 포인트 : LOD(2단계) vs Tessellation(3단계)
    • LOD : "이미 만들어진" 가벼운 모델로 통째로 교체하는 것. (이산적 변화)
    • Tessellation : 하나의 모델을 GPU가 실시간으로 쪼개서 늘리는 것. (연속적 변화)
    • 최적화 관점에서는 LOD가 훨씬 가볍고 대중적입니다.

2. Skinning Optimization (스키닝 웨이트 제한)

  • 설명 : 캐릭터 애니메이션 시, 하나의 정점이 몇 개의 뼈(Bone)에 따라 움직일지 제한하는 것입니다. 보통 품질을 위해 4개의 뼈(4-Bones)를 쓰지만, 이를 2개(2-Bones) 혹은 1개(1-Bone)로 줄입니다.
  • 지금 단계에 효과 :
    • Stage 2 (VS) : 스키닝은 버텍스 쉐이더에서 가장 비싼 행렬 곱셈(Matrix Multiplication) 연산입니다. 웨이트 개수를 줄이면 연산 비용이 정비례해서 감소합니다.
  • 장점 :
    • 군중 렌더링 필수 : MMORPG의 공성전이나 무쌍류 게임처럼 수많은 캐릭터가 등장할 때 프레임 방어에 필수적입니다.
  • 단점 :
    • 애니메이션 품질 저하 : 관절이 굽혀지는 부분(팔꿈치, 무릎)이 부드럽게 꺾이지 않고, 종이 접듯이 딱딱하게 꺾이거나 찌그러질 수 있습니다.
  • ※ 헷갈리기 쉬운 포인트 : GPU Skinning vs Animation Instancing(Baker)
    • GPU Skinning : 매 프레임 버텍스 쉐이더가 뼈 위치를 계산함. (일반적 방식)
    • Animation Instancing : 애니메이션 결과를 텍스처(Texture)로 구워놓고, 쉐이더는 텍스처만 읽어서 위치를 잡음. (VS 연산을 텍스처 읽기로 대체하는 초고성능 최적화 기법)

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

  • 설명 : 버텍스 쉐이더 코드(HLSL/GLSL) 내부에서 연산할 때 float(32bit) 대신 half(16bit) 혹은 fixed(구형 11bit) 자료형을 사용하는 기법입니다.
    • Position : 반드시 float 사용 (위치 정확도 유지)
    • Normal, Tangent, Color, UV : half 사용 권장
  • 지금 단계에서 효과 :
    • Stage 2 (VS) 자체 : 모바일 GPU는 half 연산을 float보다 최대 2배 빠르게 처리하며, 레지스터(임시 저장소) 사용량이 줄어들어 병렬 처리 효율(Occupancy)이 높아집니다.
  • 장점 :
    • 모바일 최적화 : PC보다 모바일 환경에서 성능 향상 폭이 매우 큽니다. 전력 소모도 줄어듭니다.
  • 단점 :
    • 위치 오차 (Jittering) : 월드 좌표(Position) 계산에 half를 쓰면, 원점에서 멀어질수록 물체가 덜덜 떨리는 현상이 발생합니다. 위치 계산은 무조건 float를 써야 합니다.
  • ※ 헷갈리기 쉬운 포인트 : Vertex Format(1단계) vs Vertex Precision(2단계)
    • 아까 1단계에서 정리했듯이, 1단계는 "저장 용량"을 줄이는 것이고, 2단계는 "연산 정밀도"를 줄이는 것입니다. 둘은 세트로 움직이는 경우가 많습니다.

4. Minimize Complex Math (복잡한 수학 연산 최소화)

  • 설명 : sin, cos, pow, sqrt, normalize 같은 무거운 수학 함수 사용을 버텍스 쉐이더에서 줄이는 것입니다.
    • Pre-computation : 변하지 않는 값은 CPU(0단계)에서 미리 계산해서 Uniform 변수로 넘깁니다.
    • Approximation : 정확한 값 대신 근사 식(Fast Math)을 사용합니다.
  • 지금 단계에서 효과 :
    • Stage 2 (VS) : 정점 하나당 소요되는 GPU 사이클(Clock Cycle)이 줄어들어 처리 속도가 빨라집니다.
  • 장점 :
    • 티끌 모아 태산이라고, 수만 개의 정점에 대해 연산이 줄어들면 전체 프레임 타임이 개선됩니다.
  • 단점 :
    • 정확도 감소 : 근사 식을 사용할 경우 조명이나 반사 효과가 미세하게 부정확할 수 있습니다.
  • ※ 헷갈리기 쉬운 포인트 : Vertex Shader vs Pixel Shader 연산 이동
    • 가능하다면 Pixel Shader(6단계)에 있는 연산을 Vertex Shader(2단계)로 옮기는 것이 좋습니다. (정점 수 < 픽셀 수 이기 때문)
    • 하지만 Vertex Shader에서도 무거운 연산은 피해야 합니다. 즉, "픽셀보다는 버텍스가 낫지만, 버텍스도 CPU보다는 못하다"는 위계질서를 기억해야 합니다.