Unreal Custom Import System을 만들어보자 — Interchange 입문
개요
언리얼로 텍스처를 임포트할 때마다 반복하는 작업이 있다.
_ORM이면 sRGB를 끄고, Compression Settings과 Texture Group을 프로젝트 권장 값으로 바꿔야 한다_BC(BaseColor)도 Compression Settings이나 Texture Group을 바꿔야 하는데, 가끔 파란색 BaseColor는 엔진이 노말맵으로 인식해서 sRGB까지 풀려버린다 — 수정할 옵션이 더 늘어남- 캐릭터 텍스처는
TEXTUREGROUP_Character에, 배경은TEXTUREGROUP_World에 넣어야 하는데 매번 수동
Interchange Framework에 커스텀 파이프라인을 하나 끼워넣으면 이 반복 작업을 자동화할 수 있다.
Interchange Framework 간단 소개
Interchange는 UE5에서 에셋 임포트/리임포트를 담당하는 프레임워크다. 기존의 FBX 임포터와 달리 모듈화된 파이프라인 구조를 가지고 있어서, 각 단계를 독립적으로 교체하거나 추가할 수 있다.
핵심 구조는 세 단계다:
Translator → Pipeline → Factory
(파일 읽기) (노드 가공) (에셋 생성)- Translator: 소스 파일을 읽어서 중간 노드(Interchange Node)로 변환
- Pipeline: 노드를 가공하여 Factory Node를 생성 — 여기에 커스텀 로직을 끼워넣는다
- Factory: Factory Node를 실제 UE 에셋(UTexture2D, UMaterialInstance 등)으로 변환
파이프라인은 스택 구조로, 여러 개를 순서대로 쌓을 수 있다. 기본 UInterchangeGenericTexturePipeline이 텍스처 Factory Node를 만든 뒤, 우리가 만든 파이프라인이 그 노드의 설정을 덮어쓰는 방식이다.
CustomTextureAutoSettingsPipeline
UInterchangePipelineBase를 상속받은 커스텀 파이프라인이다. 언리얼 기본 UInterchangeGenericTexturePipeline을 대체하는 구조로, Project Settings - Interchange 스택에는 이 커스텀 파이프라인만 등록한다.
기본 GenericTextureInterchangePipeline을 스택에 직접 두면 bDetectNormalMapTexture가 활성 상태라 파란색 BaseColor를 노말맵으로 오인하는 문제가 생긴다. 커스텀 파이프라인 내부에서 Generic 파이프라인을 생성하되 bDetectNormalMapTexture = false로 끄고 실행한 뒤, 접미사 _N이 붙은 텍스쳐만 노말맵으로 처리하는 방식으로 대체했다.
파란색 BaseColor 같은 텍스처를 노말맵으로 오인하는 문제를 원천 차단하기 위해서다. 대신 접미사 _N이 붙은 텍스처만 노말맵으로 처리한다.
접미사 규칙 (Suffix Rules)
텍스처 이름의 끝을 보고 압축/sRGB 설정을 결정한다. _N(노말맵) 같은 경우는 언리얼이 기본 제공하는 UInterchangeGenericTexturePipeline에서 이미 처리해준다. 여기서는 기본 파이프라인이 커버하지 않는 항목들을 다룬다.
| 접미사 | sRGB | Compression | Flip Green |
|---|---|---|---|
_BC | O | BC7 | X |
_N | X | BC5 (Normalmap) | X |
_ORM | X | BC7 | X |
매칭은 이름의 마지막 _ 세그먼트를 추출해서 규칙과 정확히 일치하는지 확인한다. T_CHAR_Body_BC라면 _BC를 꺼내서 규칙과 비교하는 방식이다.
const FMEANTTextureSuffixRule* FindSuffixRule(const FString& AssetName) const
{
int32 LastUnderscore;
if (!AssetName.FindLastChar(TEXT('_'), LastUnderscore))
{
return nullptr;
}
const FString LastSegment = AssetName.Mid(LastUnderscore); // "_BC"
for (const FMEANTTextureSuffixRule& Rule : SuffixRules)
{
if (LastSegment.Equals(Rule.Suffix, ESearchCase::IgnoreCase))
{
return &Rule;
}
}
return nullptr;
}키워드 규칙 (Prefix Rules)
텍스처 이름을 _로 분리한 세그먼트에서 키워드를 찾아 TextureGroup을 결정한다.
| 키워드 | TextureGroup |
|---|---|
CHAR | TEXTUREGROUP_Character |
WOR | TEXTUREGROUP_World |
예를 들어 T_CHAR_Body_BC를 _로 파싱하면 [T, CHAR, Body, BC]가 되고, 세그먼트 중 CHAR이 매칭되어 TEXTUREGROUP_Character가 적용된다.
TArray<FString> Segments;
AssetName.ParseIntoArray(Segments, TEXT("_"));
for (const FMEANTTexturePrefixRule& Rule : PrefixRules)
{
for (const FString& Segment : Segments)
{
if (Segment.Equals(Rule.Keyword, ESearchCase::IgnoreCase))
{
FactoryNode->SetCustomLODGroup(
static_cast<uint8>(Rule.TextureGroup));
break;
}
}
}파이프라인 스택 배치
스택에는 이 파이프라인만 등록한다. 단, 내부 구현에서 Generic 파이프라인을 반드시 생성·실행해야 한다 — 팩토리 노드
생성을 Generic이 담당하기 때문이다. Generic을 빼면 텍스처 임포트 자체가 안 된다.
Pipeline Stack:
1. MEANTTextureAutoSettingsPipeline
└─ 내부: GenericTexturePipeline (bDetectNormalMap = OFF)
└─ 접미사/키워드 규칙 적용네이밍 규칙 편집
모든 규칙은 UPROPERTY(EditAnywhere)로 노출되어 있어서, Pipeline Stack에서 규칙을 자유롭게 추가/수정/삭제할 수 있다. 코드를 수정하지 않아도 프로젝트 네이밍 컨벤션에 맞게 조정이 가능하다.
결과
임포트 시 수동으로 건드릴 것이 없다. 텍스처 파일을 드래그 앤 드롭하면:
_BC로 끝나는 텍스처는 sRGB ON, BC7_N은 sRGB OFF, BC5(Normalmap)_ORM은 sRGB OFF, BC7- 이름에
CHAR가 포함되면 Character TextureGroup - 이름에
WOR가 포함되면 World TextureGroup
파란색 BaseColor가 노말맵으로 분류되는 문제도, TextureGroup을 매번 수동으로 바꾸는 작업도 사라졌다.
규칙 자체가 UPROPERTY로 노출된 구조체 배열이기 때문에, 추후 DataTable로 빼서 관리하는 것도 가능하다. 프로젝트별로 네이밍 컨벤션이 다르더라도 코드 수정 없이 테이블만 교체하면 된다.
참고
- Unreal Engine - Interchange Framework
UInterchangePipelineBase— 커스텀 파이프라인의 베이스 클래스UInterchangeTextureFactoryNode— 텍스처 임포트 설정을 담는 Factory Node