46. 기술: Material LUT와 파라미터 패킹
[B] 서브컬쳐 캐릭터는 “재질 종류”가 많고(피부/천/가죽/금속/보석/퍼), 각 재질이 요구하는 파라미터도 많습니다. 이를 머티리얼 인스턴스/키워드로만 관리하면 운영이 폭발하므로, Material ID -> LUT -> 파라미터 디코드로 문제를 데이터화하는 접근이 자주 쓰입니다.
목적
- [B] 캐릭터 부위별 파라미터를 텍스처 기반으로 압축해 변형 폭을 제어한다.
- [A/B] URP 셰이더에서 안정적으로 샘플 가능한 LUT 계약을 정의한다.
증거 등급 요약(A/B/C)
- [A] 공식 발표에서 멀티플랫폼 품질 일관성과 파라미터 관리 중요성이 반복된다.
- [B] 역분석 문서에서 LightMap A/ID 기반 부위 분류 + LUT 샘플 패턴이 반복된다.
- [C] 정확한 LUT 레이아웃(행/열 의미)은 프로젝트별 아트 파이프라인에 종속된다.
핵심 개념
이론 배경
- [B] LUT 패킹은 머티리얼 인스턴스 증식을 막고 파라미터 변경을 데이터 교체 문제로 환원한다.
- [B] 핵심은 채널 의미와 인덱싱 규칙을 고정해 툴-엔진 간 동일 디코드를 보장하는 것이다.
- [C] 정밀도 부족은 밴딩/경계 튐으로 바로 나타나므로 포맷 선택이 품질 결정요소다.
코드 해설
- [B]
floor(matId * (N-epsilon))패턴은 경계 샘플이 다음 슬롯으로 넘어가는 오프바이원 문제를 줄인다. - [B/C] LUT를 분리할수록 유연성은 증가하지만 바인딩 실수 가능성도 커져 자동 검증이 필요하다.
Material ID -> LUT index -> 셰이딩 파라미터 흐름을 고정하면 머티리얼 인스턴스 폭증을 억제할 수 있다. [B]
HLSL
struct PackedParams
{
float3 specColor;
float rimWidth;
float rimBoost;
float shadowLift;
};
PackedParams SamplePacked(float matId)
{
// 16x1 LUT 예시 (matId: 0..1)
float x = (floor(saturate(matId) * 15.999) + 0.5) / 16.0;
float4 a = SAMPLE_TEXTURE2D(_MatLutA, sampler_MatLutA, float2(x, 0.5));
float4 b = SAMPLE_TEXTURE2D(_MatLutB, sampler_MatLutB, float2(x, 0.5));
PackedParams p;
p.specColor = a.rgb;
p.rimWidth = a.a;
p.rimBoost = b.r;
p.shadowLift = b.g;
return p;
}
HLSL
float matId = SAMPLE_TEXTURE2D(_LightMap, sampler_LightMap, uv).a;
PackedParams p = SamplePacked(matId);
- [B]
matId는 텍스처 채널 의미를 팀 규약으로 고정해야 유지된다. - [C] LUT 채널 재정의 시 아트 리소스 전체 재익스포트 비용이 발생한다.
결론: LUT는 “표현 기법”이 아니라 “운영 장치”다
- [B] LUT를 도입하면 셰이딩의 핵심이 “수식”에서 “데이터 계약(채널/인덱싱/정밀도)”으로 이동한다.
- [B] 그래서 decode를 공통 include로 단일화하고, 변경 시 자동 검증(스냅샷/회귀)을 함께 설계해야 한다.
URP 매핑 포인트
설계 해석
-
[B] 공통 include에서 decode를 단일화하면 재질별 수식 드리프트를 방지할 수 있다.
-
[A/B] C# 바인딩은 캐릭터 타입 단위
ScriptableObject로 관리해 라이브 튜닝과 회귀 추적을 동시에 확보한다. -
[B] 셰이더 계층:
- 공통 include(
SubculturePackedParams.hlsl)에서 LUT decode - 각 재질(face/hair/body)에서는 decode 결과만 사용
- 공통 include(
-
[A/B] C# 계층:
- 캐릭터 타입별 LUT 세트를
ScriptableObject로 바인딩 - RendererFeature에서 캐릭터 그룹별 LUT 전환 가능
- 캐릭터 타입별 LUT 세트를
-
[B] 성능:
- LUT는
R8G8B8A8또는R16G16B16A16로 제한 - 모바일은 단일 LUT로 축소, 콘솔은 2장 분리 운영
- LUT는
실패 패턴/오해
- [B] LUT 인덱스 반올림 규칙이 셰이더/툴에서 다르게 구현되어 경계 떨림이 생긴다.
- [B] 채널 의미 문서화 없이 아트가 값을 덮어써 룩이 드리프트한다.
- [C] LUT만 바꾸면 모든 문제가 해결된다고 오해해 광원/노멀 품질 문제를 방치한다.
실무 체크리스트
-
matId