book/46-tech-material-lut-and-parameter-packing.md

N/A

46. 기술: Material LUT와 파라미터 패킹

부위별 NPR 파라미터를 LUT/마스크로 압축해 아트 파이프라인과 성능을 동시에 관리하는 방법

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 결과만 사용
  • [A/B] C# 계층:

    • 캐릭터 타입별 LUT 세트를 ScriptableObject로 바인딩
    • RendererFeature에서 캐릭터 그룹별 LUT 전환 가능
  • [B] 성능:

    • LUT는 R8G8B8A8 또는 R16G16B16A16로 제한
    • 모바일은 단일 LUT로 축소, 콘솔은 2장 분리 운영

실패 패턴/오해

  • [B] LUT 인덱스 반올림 규칙이 셰이더/툴에서 다르게 구현되어 경계 떨림이 생긴다.
  • [B] 채널 의미 문서화 없이 아트가 값을 덮어써 룩이 드리프트한다.
  • [C] LUT만 바꾸면 모든 문제가 해결된다고 오해해 광원/노멀 품질 문제를 방치한다.

실무 체크리스트

  • matId

Sources (섹션 단위 인용)

패턴 근거

운영 맥락