SWidget 렌더링
Slate의 렌더링 파이프라인, 레이아웃 패스, Paint 시스템, 그리고 Invalidation 메커니즘을 심층 분석합니다.
Slate 렌더링 파이프라인
프레임당 Slate가 수행하는 단계별 프로세스
ComputeDesiredSize
(Bottom-Up)
ArrangeChildren
(Top-Down)
OnPaint
(Top-Down)
Element 배칭
& GPU 전송
// 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는 위젯의 위치, 크기, 스케일, 회전 정보를 캡슐화합니다. GetLocalSize()로 로컬 크기를, AbsoluteToLocal()로 화면 좌표를 위젯 로컬 좌표로 변환할 수 있습니다. Paint/Layout 패스에서 핵심적으로 사용됩니다.
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 |
// 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
);
Invalidation 시스템
Slate의 캐싱과 Invalidation으로 렌더링 최적화
Slate의 Invalidation 시스템은 변경되지 않은 위젯의 레이아웃과 Paint 결과를 캐싱하여 매 프레임 재계산을 방지합니다.
// 위젯 무효화(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는 UE5에서 추가된 Invalidation 연동 속성으로, 값 변경 시 자동으로 해당 위젯만 Invalidate합니다. 기존 TAttribute는 매 프레임 폴링하므로 변경 감지가 비효율적입니다. 새로운 Slate 위젯 코드에서는 TSlateAttribute 사용을 권장합니다.
Slate Renderer 아키텍처
Draw Element에서 화면 출력까지의 렌더링 흐름
Draw Elements 수집
텍스처/셰이더별 배칭
GPU 버텍스 버퍼 생성
Slate Renderer는 수집된 Draw Element들을 같은 텍스처/셰이더를 사용하는 것끼리 배칭하여 Draw Call을 최소화합니다. 이것이 Slate가 수천 개의 위젯을 효율적으로 렌더링할 수 있는 이유입니다.
서로 다른 텍스처를 사용하는 위젯이 Z-Order로 교차 배치되면 배칭이 깨져 Draw Call이 증가합니다. 같은 텍스처 아틀라스를 사용하는 요소끼리 그룹화하거나 Material 기반 렌더링으로 통합하면 배칭 효율을 높일 수 있습니다.
핵심 요약
- Slate 렌더링은 ComputeDesiredSize(바텀업) → ArrangeChildren(탑다운) → OnPaint(탑다운) → Batch/GPU 순서로 진행됩니다
FSlateDrawElement의MakeBox,MakeLines,MakeText등으로 커스텀 렌더링을 수행합니다- Invalidation 시스템은 변경되지 않은 위젯의 재계산을 방지하여 성능을 최적화합니다
TSlateAttribute는 값 변경 시 자동으로 Invalidation을 트리거하는 UE5의 최적화된 속성 타입입니다- Slate Renderer는 같은 텍스처/셰이더를 사용하는 Element를 배칭하여 Draw Call을 최소화합니다
도전 과제
배운 내용을 직접 실습해보세요
복잡한 위젯 트리(50개 이상의 자식)에 InvalidationBox를 적용하고, stat slate 명령어로 Paint 횟수 변화를 측정하세요. InvalidateWidget() 호출 시와 미호출 시의 성능 차이를 비교 분석합니다.
자주 변경되지 않는 UI 영역(배경 장식, 프레임)에 RetainerBox를 적용하여 렌더 타겟에 캐시하세요. Phase Count를 조절하며 업데이트 주기에 따른 시각적 품질과 성능 트레이드오프를 확인합니다.
Unreal Insights의 Slate 채널을 활용하여 커스텀 위젯의 Paint 호출 비용을 프로파일링하세요. FSlateDrawElement 배칭이 깨지는 원인을 분석하고, 머티리얼/텍스처 아틀라스로 배치 수를 최적화합니다.