PT / GI 팩

pt_surface.hlsl: 패스 트레이싱과 오프라인 GI 렌더러에서 팩을 적용하는 방법. PackEvaluate, PtPackIn / PtPackOut, 텍스처, 디노이저, 제한.

PT / GI 팩이란

표면 팩(surface.hlsl)은 PackShade로 래스터와 레이 트레이싱 카메라 뷰를 셰이딩합니다. 패스 트레이서(--render pt, PT 영상 렌더러)와 오프라인 GI 렌더러(GI 스틸·영상)는 모든 광선을 하나의 컴퓨트 셰이더 안에서 추적하기 때문에 PackShade를 거기서 실행할 수 없습니다. 팩은 두 번째 파일 pt_surface.hlsl로 참여할 수 있고, 이 파일은 히트 지점의 재질을 기술합니다. 태양 그림자, 간접광, 방사 조도 캐시, 디노이저 같은 빛 수송은 렌더러가 계속 맡습니다.

MMDX12 1.5.0 이상이 필요합니다. 이 파일이 없는 팩은 PT와 GI에서 기본 셰이딩을 쓰고, 이전 버전은 이 파일을 무시합니다.

파일

my_pack/
  pack.json        매니페스트 (변경 없음)
  surface.hlsl     래스터 / 실시간 RT       (PackShade)
  pt_surface.hlsl  패스 트레이싱 / 오프라인 GI (PackEvaluate)
  shared.hlsli     선택: 두 파일이 함께 쓰는 수학

두 파일 모두 팩 폴더의 #include "shared.hlsli"를 쓸 수 있어서 룩을 한 번만 작성하면 됩니다. 온라인 갤러리 팩 nimble_toon이 이렇게 만들어졌습니다.

PackEvaluate

PtPackOut PackEvaluate(PtPackIn i);

PtPackIn

필드의미
pos, normal, V, uv월드 위치, 셰이딩 법선, 카메라 방향, 텍스처 좌표
L, sunVis태양 방향, 추적한 그림자 광선의 태양 가시성 0..1 (확산 바운스에서는 0)
baseColor선형 텍스처 색 × 재질 색, 조명 없음
materialClassclasses 규칙에서 정한 PACK_BODY / SKIN / FACE / EYE / HAIR / WEAPON
params[16]pack.json 순서의 슬라이더 값
headPos, headScale, headRight, headUp, headForward, headValidPackSurface와 같은 머리 본 프레임

PtPackOut (모든 필드를 대입하세요. 대입하지 않은 필드가 있으면 pack_check가 경고합니다)

필드의미
albedo선형 표면 색. 확산 바운스와 디노이저가 보는 값
shadowTint그림자 쪽에 곱하는 선형 배율
shadowBiasN.L 단위로 경계를 이동 (부드럽게 한 얼굴 법선: dot(Nsmooth, L) - dot(normal, L))
terminator경계 smoothstep의 N.L 끝점 (lo, hi). (0, 0)이면 엔진 기본값
specular더해지는 선형 광휘(림, 광택, 매트캡). sunVis가 곱해집니다
flatFace엔진의 평면 얼굴 처리 사용 (이 표면에 간접광 그라디언트 없음)

렌더러가 쓰는 방식

  • 카메라 광선과 거울·유리 체인: lerp(albedo * shadowTint, albedo, term * sunVis) * sunIntensity + specular * sunVis, 여기서 term = smoothstep(lo, hi, N.L + shadowBias).
  • 확산 바운스(다른 표면이 모으는 빛): albedo만 사용합니다. 툰 항은 수집 광선에서 실행되지 않습니다.
  • 환경광(ambient) 항을 더하지 마세요. 패스 트레이서가 실제 간접광을 추적합니다.
  • 하프 램버트 램프 threshold ± softness는 terminator = (2 * (threshold - softness) - 1, 2 * (threshold + softness) - 1)로 옮길 수 있습니다.

텍스처

pack.json에 선언한 텍스처를 쓸 수 있습니다 (명시적 LOD만, 암시적 미분 없음):

float4 PtPackSampleTex(uint i, float2 uv);                 // 레벨 0
float4 PtPackSampleTexLevel(uint i, float2 uv, float lod);
uint   PtPackTexCount();
float2 PtPackTexSize(uint i);

범위를 벗어난 인덱스나 없는 파일은 PackSampleTex처럼 흰색입니다. sRGB 텍스처는 선형 값으로 샘플됩니다.

제한

  • 캐릭터만 해당합니다. 무대와 소품에는 팩이 적용되지 않습니다.
  • 한 장면에 서로 다른 PT 팩이 여럿이면 첫 번째 팩을 씁니다 (경고가 로그에 남습니다).
  • 오프라인 GI 렌더러는 앱 기본 외곽선을 그립니다 (PackEdge는 래스터와 RT에 적용).
  • 디노이저는 팩의 직접광을 기본 툰 조명과 똑같이 처리합니다. 정지 테스트에서는 딱딱한 step() 하이라이트 경계가 선명하게 남았지만, 빠른 움직임은 확인하지 않았습니다.
  • PackEvaluate에서 끝이 정해지지 않은 루프는 피하세요. GPU가 멈추면 앱이 종료됩니다.
  • pack_check <폴더> --compile로 확인하세요. 래스터, 오프라인 GI, 패스 트레이서 변형을 모두 컴파일합니다.