멀티플레이 개발
네모난 캐릭터가 떼굴떼굴 구르는 이동 연출을 구현하기 위해 CapsuleComponent는 그냥 두고StaticMesh를 회전 시키고 있었다.
처음에 한 번 구를 때 Mesh를 360도 회전시켰다. 360도 회전은 마지막에 다시 원래 자세로 돌아오기 때문에 별다른 문제가 보이지 않았다.
하지만 회전 각도를 180도로 변경하자, Mesh의 현재 회전값이 예상과 다르게 반환되는 문제가 발생했다.
const FRotator CurrentRotation = VisualStaticMesh->GetRelativeRotation();
한 축으로만 회전시키고 있으므로 해당 축의 값이 0 -> 90 -> 180 같이 누적될 것이라고 예상했다. 그러나 실제로 180도 부근에서 값이 다시 0에 가까워지거나, 회전값이 다른 축으로 분산되어 나타났다.
화면에서는 Mesh가 정상적으로 뒤집혀 있지만, Pitch, Yaw, Roll값은 내가 예상한 방식으로 유지되지 않았다. 그래서 360도 회전은 가능했지만 180도로 회전했을때 기준으로 삼을 값이 존재하지않았다.
Frotator는 회전을 다음 세 개의 오일러 각도로 표현한다. Pitch, Yaw, Roll
문제는 하나의 3차원 회전 상태를 표현할 수 있는 오일러 각도의 조합이 하나만 존재하지 않는다는 점이다.
서로 다른 Pitch, Yaw, Roll, 조합이더라도 결과적으로 같은 방향을 나타낼 수 있다.
Unreal Engine은 내부적으로 관리하는 회전값을 FRotator로 반환할 때 각도를 정규화한다. 이 과정에서 특히 180도처럼 Mesh가 완전히 뒤집힌 상태에서는 회전값이 다른 축의 조합으로 표현 될 수 있다.
따라서 GetRelativeRotation()은 메쉬가 현재 어떤 자세인지 확인하는 데에는 사용할 수 있지만, 그 값을 한 축의 누적 회전량, 캐릭터가 바라보는 논리적인 방향, 다음 회전의 시작 각도, 지금까지 몇 도 회전했는지 계산하는 값과 같은 용도로 사용하는 것은 변하는 값의 기준점으로 사용하기에 안전하지 않다.
결국 RelativeRotation이 잘못된 값을 반환하는 것이 아니다.
같은 회전을 다른 오일러 각도 조합으로 표현한 값을 반환하는 것이며, 그 값을 내가 원하는 축의 누적 각도로 해석한 것이 문제였다.
const float DeltaAlpha = Alpha - PreviousAlpha;
PreviousAlpha = Alpha;
const float DeltaAngle =
DeltaAlpha * TargetAngle;
VisualStaticMesh->AddLocalRotation(
FRotator(DeltaAngle, 0.f, 0.f)
);
현재 회전값을 읽어서 새로운 회전을 계산하는 대신, 매 프레임 추가되어야 하는 회전량만 계산하도록 AddlocalRotation()을 사용했다.
여기서 Alpha는 현재 거리, 시간 기반 애니메이션 진행도이고, PreviousAlpha는 이전 프레임의 진행도를 캐싱한 것이다.
두 값의 차이를 사용하면 이번 프레임에 추가해야 하는 회전 비율을 계산할 수 있다.
AddLocalRotation()일까?단순히 SetRelativeRotation()대신 AddLocalRotation()을 사용한 곳에 있지 않다.
기존 방식은 현재 회전을 읽고 그 값을 다음 계산의 기준으로 사용했다.
GetRelativeRotation()
→ 축의 각도를 수정
→ SetRelativeRotation()
변경한 방식은 현재 회전값을 논리적인 각도로 해석하지 않고, 직접 계산한 각도 Delta값만 적용한다.
이번 문제는 RelativeRotation이 틀린 값을 반환해서 발생한 문제가 아니였다.
FRotator의 Pitch, Yaw, Roll 값을 내가 원하는 축의 연속적인 누적 각도로 사용한 것이 문제였다.
3차원에서는 하나의 회전을 여러 오일러 각도 조합으로 표현할 수 있다. Unreal Engine은 회전값을 FRotator로 변환하는 과정에서 각도를 정규화하기 때문에, 특히 180도 부근에서는 회전값이 다른 축으로 분산되어 보일 수 있다.
계속해서 특정 각도로 회전하는 값을 구해서 적용해야한다면, RelativeRotation은 부적절하다