PART 3 · 강의 3/3

SWidget 렌더링

Slate의 렌더링 파이프라인, 레이아웃 패스, Paint 시스템, 그리고 Invalidation 메커니즘을 심층 분석합니다.

01

Slate 렌더링 파이프라인

프레임당 Slate가 수행하는 단계별 프로세스

1. Prepass
ComputeDesiredSize
(Bottom-Up)
2. Layout
ArrangeChildren
(Top-Down)
3. Paint
OnPaint
(Top-Down)
4. Batch
Element 배칭
& GPU 전송
C++ - 레이아웃 패스 핵심 함수
// Pass 1: ComputeDesiredSize (리프 → 루트) // 각 위젯이 "이 만큼의 공간이 필요합니다"라고 선언 virtual FVector2D ComputeDesiredSize(float LayoutScaleMultiplier) const { // 자식 위젯들의 DesiredSize를 기반으로 계산 FVector2D ChildDesiredSize = ChildSlot.GetWidget()->GetDesiredSize(); return ChildDesiredSize + Padding.GetDesiredSize(); } // Pass 2: ArrangeChildren (루트 → 리프) // 부모가 할당된 공간 내에서 자식의 실제 위치와 크기를 결정 virtual void OnArrangeChildren( const FGeometry& AllottedGeometry, FArrangedChildren& ArrangedChildren) const { const FVector2D ChildSize = ChildSlot.GetWidget()->GetDesiredSize(); ArrangedChildren.AddWidget( AllottedGeometry.MakeChild( ChildSlot.GetWidget(), FVector2D::ZeroVector, // 오프셋 ChildSize // 할당 크기 ) ); } // Pass 3: OnPaint (루트 → 리프) // 위젯 트리를 순회하며 FSlateDrawElement를 수집
FGeometry 이해하기

FGeometry는 위젯의 위치, 크기, 스케일, 회전 정보를 캡슐화합니다. GetLocalSize()로 로컬 크기를, AbsoluteToLocal()로 화면 좌표를 위젯 로컬 좌표로 변환할 수 있습니다. Paint/Layout 패스에서 핵심적으로 사용됩니다.

02

FSlateDrawElement 상세

Slate 렌더링의 기본 단위인 Draw Element

메서드 용도 핵심 파라미터
MakeBox 텍스처/색상 사각형 PaintGeometry, Brush, Tint
MakeText 텍스트 렌더링 PaintGeometry, Text, Font, Color
MakeLines 직선/폴리라인 Points, Color, Thickness, bAntialias
MakeSpline 3차 베지어 곡선 P0, P1, P2, P3, Thickness, Color
MakeGradient 그래디언트 사각형 GradientStops, Orientation
MakeCustomVerts 커스텀 버텍스 메시 Vertices, Indices, Texture
C++ - 다양한 Draw Element 사용
// Box: 텍스처/색상으로 채운 사각형 FSlateDrawElement::MakeBox( OutDrawElements, LayerId, AllottedGeometry.ToPaintGeometry(), &BrushResource, // FSlateBrush ESlateDrawEffect::None, FLinearColor::White // Tint ); // Text: 폰트와 색상으로 텍스트 렌더링 FSlateDrawElement::MakeText( OutDrawElements, LayerId, AllottedGeometry.ToPaintGeometry(), DisplayText, FontInfo, ESlateDrawEffect::None, FLinearColor::White ); // Gradient: 수평/수직 그래디언트 TArray<FSlateGradientStop> GradientStops; GradientStops.Add(FSlateGradientStop(FVector2D::ZeroVector, FLinearColor::Red)); GradientStops.Add(FSlateGradientStop(LocalSize, FLinearColor::Blue)); FSlateDrawElement::MakeGradient( OutDrawElements, LayerId, AllottedGeometry.ToPaintGeometry(), GradientStops, EOrientation::Orient_Horizontal );
03

Invalidation 시스템

Slate의 캐싱과 Invalidation으로 렌더링 최적화

Slate의 Invalidation 시스템은 변경되지 않은 위젯의 레이아웃과 Paint 결과를 캐싱하여 매 프레임 재계산을 방지합니다.

C++ - Invalidation 제어
// 위젯 무효화(Invalidation) 트리거 // 위젯 속성이 변경되었을 때 명시적으로 호출 Invalidate(EInvalidateWidgetReason::Paint); // 다시 그리기만 Invalidate(EInvalidateWidgetReason::Layout); // 레이아웃 재계산 Invalidate(EInvalidateWidgetReason::Visibility); // 가시성 변경 // Global Invalidation 활성화 (프로젝트 설정) // Slate.EnableGlobalInvalidation=1 // 모든 위젯에 대해 자동 Invalidation 추적 활성화 // TSlateAttribute: Invalidation과 통합된 속성 class SMyWidget : public SLeafWidget { // TSlateAttribute는 값 변경 시 자동으로 위젯을 Invalidate TSlateAttribute<FLinearColor> ColorAttr; void SetColor(FLinearColor NewColor) { // 값이 다를 때만 Invalidate 발생 (자동 최적화) ColorAttr.Set(*this, NewColor); } };
TSlateAttribute vs TAttribute

TSlateAttribute는 UE5에서 추가된 Invalidation 연동 속성으로, 값 변경 시 자동으로 해당 위젯만 Invalidate합니다. 기존 TAttribute는 매 프레임 폴링하므로 변경 감지가 비효율적입니다. 새로운 Slate 위젯 코드에서는 TSlateAttribute 사용을 권장합니다.

04

Slate Renderer 아키텍처

Draw Element에서 화면 출력까지의 렌더링 흐름

OnPaint()
Draw Elements 수집
Element Batcher
텍스처/셰이더별 배칭
Slate RHI Renderer
GPU 버텍스 버퍼 생성
화면 출력

Slate Renderer는 수집된 Draw Element들을 같은 텍스처/셰이더를 사용하는 것끼리 배칭하여 Draw Call을 최소화합니다. 이것이 Slate가 수천 개의 위젯을 효율적으로 렌더링할 수 있는 이유입니다.

배칭 깨짐 주의

서로 다른 텍스처를 사용하는 위젯이 Z-Order로 교차 배치되면 배칭이 깨져 Draw Call이 증가합니다. 같은 텍스처 아틀라스를 사용하는 요소끼리 그룹화하거나 Material 기반 렌더링으로 통합하면 배칭 효율을 높일 수 있습니다.

SUMMARY

핵심 요약

  • Slate 렌더링은 ComputeDesiredSize(바텀업) → ArrangeChildren(탑다운) → OnPaint(탑다운) → Batch/GPU 순서로 진행됩니다
  • FSlateDrawElementMakeBox, MakeLines, MakeText 등으로 커스텀 렌더링을 수행합니다
  • Invalidation 시스템은 변경되지 않은 위젯의 재계산을 방지하여 성능을 최적화합니다
  • TSlateAttribute는 값 변경 시 자동으로 Invalidation을 트리거하는 UE5의 최적화된 속성 타입입니다
  • Slate Renderer는 같은 텍스처/셰이더를 사용하는 Element를 배칭하여 Draw Call을 최소화합니다
PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: Invalidation Box 적용 실험

복잡한 위젯 트리(50개 이상의 자식)에 InvalidationBox를 적용하고, stat slate 명령어로 Paint 횟수 변화를 측정하세요. InvalidateWidget() 호출 시와 미호출 시의 성능 차이를 비교 분석합니다.

실습 2: Retainer Box 활용

자주 변경되지 않는 UI 영역(배경 장식, 프레임)에 RetainerBox를 적용하여 렌더 타겟에 캐시하세요. Phase Count를 조절하며 업데이트 주기에 따른 시각적 품질과 성능 트레이드오프를 확인합니다.

심화 과제

Unreal Insights의 Slate 채널을 활용하여 커스텀 위젯의 Paint 호출 비용을 프로파일링하세요. FSlateDrawElement 배칭이 깨지는 원인을 분석하고, 머티리얼/텍스처 아틀라스로 배치 수를 최적화합니다.