Shipping 빌드에서만 메시가 사라졌다
에디터랑 PIE에서는 잘만 보이던 동료 NPC 메시가 Shipping 패키징에서만 스폰 직후부터 통째로 안 보였다. 스트리밍이랑 바운드, 텍스처 스트리밍까지 다 의심했는데 정작 범인은 엉뚱한 곳에 있었다. 가시성 플래그의 ‘자식 전파’ 인자다.
증상
- 에디터·PIE는 정상. Shipping 패키징 빌드에서만 메시가 안 보인다.
- 스폰 직후부터 안 보인다.
- 0.2초마다 가시성을 강제로 켜는 폴링을 넣으면 그 주기에만 잠깐 다시 보인다.
사실 마지막 항목이 결정적인 단서였다. BeginPlay에서 한 번 복구하는 걸로는 안 되고 0.2초 폴링만 먹혔다는 건, 누군가 계속 다시 끄고 있다는 뜻이다. 대증요법이 ‘언제’ 통하는지를 보면 원인의 위치가 좁혀진다.
원인 — Shipping 전용 디버그 숨김이 전파로 자식 메시까지 꺼버렸다
World Partition 스트리밍, 축소된 스켈레톤 바운드, r.TextureStreaming=0, 쿠킹 누락까지 가설은 많았지만 전부 가시성 플래그 ‘값’ 자체를 바꾸지 않으니 직접 원인이 아니었다. 진짜는 상호작용 컴포넌트의 Shipping 전용 디버그 숨김 코드였다. 소유 액터의 모든 UShapeComponent에 대해 이렇게 호출하고 있었다.
// 마지막 인자 true = 자식 컴포넌트로 전파
ShapeComponent->SetHiddenInGame(true, true);
ShapeComponent->SetVisibility(false, true);캐릭터 루트가 UCapsuleComponent(= UShapeComponent)이고 렌더링되는CharacterMesh0가 그 캡슐의 자식이다. 마지막 true(bPropagateToChildren)가 루트 캡슐을 숨기면서 그 밑의 메시까지 내려가, 메시의 bHiddenInGame과 bVisible을 동시에 꺼버렸다. 우회로 넣었던 코드가 두 플래그를 모두 되돌려야 했던 것도 이걸로 설명이 됐다.
해결 — 전파를 끄고 루트는 건너뛴다
if (UShapeComponent* ShapeComponent = Cast<UShapeComponent>(Component))
{
// 캐릭터 루트 Capsule은 건드리지 않는다. 루트에 전파(true)로 렌더링을 끄면
// 자식 CharacterMesh0의 bHiddenInGame/bVisible까지 같이 꺼져 메시가 사라진다.
if (ShapeComponent == OwnerActor->GetRootComponent())
{
continue;
}
ShapeComponent->SetHiddenInGame(true, false);
ShapeComponent->SetVisibility(false, false);
}전파 인자를 false로 바꾸고 루트 캡슐은 continue로 건너뛴다. 어차피 루프가 모든UShapeComponent를 개별로 방문하니까 전파가 없어도 디버그 존은 그대로 숨겨지고 충돌도 살아 있다. 근본 원인이 없어지니 폴링 타이머랑 강제 복구 함수, 그거 하나 때문에 있던 BeginPlay/EndPlay오버라이드까지 다 지웠다.
배운 점
전파 인자가 붙은 플래그는 대상 하나가 아니라 대상과 그 자식 전부를 바꾼다. SetHiddenInGame·SetVisibility의 마지막 인자를 습관적으로 true로 두면, 캡슐 하나 숨기려던 게 그 밑 메시까지 숨긴다. 루프가 이미 개별로 다 도는데 전파를 켤 이유는 없었다.
폴링 우회가 특정 주기에만 먹힌다면, 그건 원인이 계속 다시 설정되고 있다는 신호다. 1회 복구로 안 되고 주기적으로만 통한다는 사실 자체가 ‘누가 계속 끄고 있다’를 가리켰다.
에디터에서 아무리 해도 재현이 안 되면 빌드 구성별 코드 경로부터 의심한다. #if UE_BUILD_SHIPPING 블록은 PIE에서는 컴파일조차 안 되니, 그 안의 버그는 에디터에서 절대 안 나온다.