언리얼 런타임 SplineMeshComponent 동적 생성: 호출 순서·탄젠트 정규화·핫리로드 함정
기존 지형 위에 스플라인만 깔아 자율주행 경로로 쓰다 보니, 도로 메시가 없어 차량이 지형 굴곡을 타고 튀는 문제가 있었다.
스플라인을 따라 도로 메시를 코드로 생성하면서 마주친 세 가지 함정을 정리한다.
ASplineMeshActor 상속 대신 AActor 유지
처음에는 ASplineMeshActor를 상속하려 했다.
하지만 ASplineMeshActor는 USplineMeshComponent를 가진 액터라서, 이걸 상속하면 기존에 USplineComponent 기반으로 짜둔 자율주행 코드가 깨진다.
그 코드가 기대하는 함수와 구성이 사라지기 때문이다.
그래서 AActor 상속을 유지한 채 USplineComponent와 USplineMeshComponent들을 런타임에 동적 생성하는 방향을 택했다. 기존 코드의 전제를 깨지 않으려면 부모 클래스를 바꾸기보다 컴포넌트를 더하는 쪽이 안전하다고 판단했다.
함정 1: 호출 순서 — 설정을 끝낸 뒤에 부착·등록
메시가 스플라인과 어긋난 위치에 생성됐다.
원인은 SetupAttachment와 RegisterComponent를 너무 일찍 호출한 것이었다.
부착·등록을 먼저 하면 그 시점의 잘못된 상태로 메시가 등록된다.
USplineMeshComponent* SMC = NewObject<USplineMeshComponent>(...);
SMC->SetMobility(EComponentMobility::Movable);
SMC->AttachToComponent(SplineComponent, ...);
SMC->SetForwardAxis(ForwardAxis, false);
SMC->SetStaticMesh(RoadMesh);
SMC->SetStartAndEnd(StartPos, StartTan, EndPos, EndTan, true);
SMC->RegisterComponent();
이 프로젝트에서는 SetForwardAxis → SetStaticMesh → SetStartAndEnd 순으로 모든 설정을 끝낸 다음 마지막에 RegisterComponent를 호출하는 것으로 정리했다.
메시 적용 전에 ForwardAxis를 정하고, 등록은 가장 마지막이라는 순서가 핵심이었다.
함정 2: 탄젠트 길이를 세그먼트 실제 길이에 맞추기
위치는 맞췄는데 곡선 구간이 직선처럼 보였다.
스플라인에서 가져온 탄젠트의 길이가 세그먼트 실제 길이와 맞지 않으면 메시가 출렁이거나 직선이 된다.
StartTan = StartTan.GetSafeNormal() * ActualSegLen;
EndTan = EndTan.GetSafeNormal() * ActualSegLen;
SMC->SetStartAndEnd(StartPos, StartTan, EndPos, EndTan, true);
탄젠트를 정규화한 뒤 세그먼트 실제 길이를 곱해 길이를 맞추면 곡선이 자연스럽게 표현된다.
스플라인 메시의 곡률 표현은 탄젠트의 방향뿐 아니라 길이에도 의존한다는 점이 포인트다.
함정 3: 핫리로드 후에는 배열 추적이 믿을 수 없다
같은 위치에 메시가 여러 층으로 누적됐다. 기존 정리 코드는 추적용 배열을 순회하며 메시를 파괴했는데,
for (USplineMeshComponent* SMC : SplineMeshes)
{
SMC->DestroyComponent();
}
SplineMeshes.Reset();
핫리로드 후에는 SplineMeshes 배열은 초기화되지만 액터에 실제로 붙어 있는 메시 컴포넌트는 그대로 남는다.
그래서 배열을 돌아도 아무것도 안 지워지고 새 메시만 계속 쌓였다.
TArray<USplineMeshComponent*> ExistingMeshes;
GetComponents<USplineMeshComponent>(ExistingMeshes);
for (USplineMeshComponent* SMC : ExistingMeshes)
{
if (SMC) SMC->DestroyComponent();
}
SplineMeshes.Reset();
GetComponents는 액터에 실제로 붙어 있는 컴포넌트를 직접 가져오므로 핫리로드 후에도 안정적이었다.
자체 배열로 추적한 것만 정리하는 방식이 항상 안전하지는 않다는 걸 이 과정에서 확인했다.
'etc' 카테고리의 다른 글
| 언리얼 델리게이트로 트리거-반응 결합도 낮추기, 그리고 토글 상태의 베이스라인 패턴 (0) | 2026.05.16 |
|---|---|
| 언리얼 Chaos Vehicle이 멈추지 않고 후진할 때: bReverseAsBrake와 상태 머신 이해 (0) | 2026.05.16 |
| 언리얼 스플라인 경로 추종 차량이 도로 밖으로 튕길 때, 평면 조향과 이탈 페일세이프 분리 (0) | 2026.05.16 |
| 언리얼 자율주행 차량, 곡률 반경으로 안전 속도 계산하기 (V = √(μgR)) (0) | 2026.05.13 |
| 자율주행 차량 조향 가중치를 곡률에 따라 동적 조정하기 (Lerp 활용) (0) | 2026.05.13 |
