Tick 함수 안에서 현재 PC의 Control 회전값을 TargetRotation 으로 회전하는 코드
PlayerController->SetControlRotation(FMath::QInterpConstantTo(
PlayerController->GetControlRotation().Quaternion(),
TargetRotation.Quaternion(),
GetWorld()->DeltaTimeSeconds,
RotateSpeed
).Rotator());
의도 (Pitch 값을 현재에서 40 만큼 증가)
TargetRatator : P=-51.462800 Y=-47.524287 R=0.000000
시작ControlRotator : P=-11.462800 Y=-47.524287 R=-0.000000
회전끝ControlRotator : P=-51.462800 Y=-47.524287 R=0.000000
때때로는 위의 의도처럼 잘 될 때가 있지만 문제는 Rotator -> Quat -> Rotator 로 변환하였더니 Roll이 0에서 180 으로 되는 현상이 있다.
TargetRatator : P=-87.518949 Y=115.043328 R=180.000000
시작ControlRotator : P=-52.481051 Y=-64.956672 R=0.000000
회전끝ControlRotator : P=-87.325985 Y=114.555076 R=89.900002
Pitch값을 40 만큼 증가시키려하였는데 40도 아니고 심지어 다른 회전값도 변해버림
언리얼에는 PlayerCameraManager 이라는 클래스가 있는데 말 그대로 카메라의 최소 최대 Control Rotation 값을 정의한다.
여기엔 기본적으로 Pitch 와 Roll 값이 -89~89 사이로 막아져있다.
(Pitch의 90을 막은 이유는 짐벌락 현상 때문 -> Yaw 와 Roll 축이 겹침)
그래서 Roll 값이 0 -> 180 으로 증가하다가 뷰 롤 최대 값 (89.9..) 에서 막아져서 위와 같은 현상이 벌어졌던 것
FRotator 특성 상, 0도, 180도 또는 -180도 Rotator과 쿼터니언 사이의 변환에서 같은값으로 판별하기 때문에 생기는 원인
일반적으로 카메라에선 Roll 값을 잘 안사용하기 때문에 0을 강제로 설정해주면 위와같은 문제는 발생하진 않는다.
TargetRotation.Roll = 0.f;
PlayerController->SetControlRotation(FMath::QInterpConstantTo(
PlayerController->GetControlRotation().Quaternion(),
TargetRotation.Quaternion(),
GetWorld()->DeltaTimeSeconds,
RotateSpeed
).Rotator());
혹은 SpringArmComponent를 사용하고 있다면 bInheritRoll 옵션을 비활성화 할 수도 있다.
FRotator
Pitch (y축 회전 right axis)
Yaw (z축 회전 up axis)
Roll (x축 회전 forward axis)
C++ 에선 FRotator { Pitch , Yaw , Roll }
블루프린트에선 회전 축으로 Roll , Pitch , Yaw 순으로 사용
일반적으로 각도를 직관적으로 표현하기 위해 0~360 범위를 조절할 수 있는데 일반적으로 계산을 위해 -180 ~ 180 방식을 사용 (회전의 방향성을 단일값으로 표현 / 회전의 연속성)
Yaw = 270도는 FRotator에서 Yaw = -90도랑 같다.
Yaw = 360도는 FRotator에서 Yaw = 0도랑 같다.
그래서 Rotator에는
Normailzed -> -180 ~ 180 사이로 변환
Denormalized -> 0 ~ 360 사이로 변환해주는 함수가 있다.
0도, 180도 또는 -180도 Rotator과 쿼터니언 사이의 변환에서 생기는 문제도 쿼터니언을 Rotator로 변환할 때, 값이 이 범위로 매핑되기 때문
Rotator 를 비교할 때 둘 다 Nomailzed 하여서 비교
PC->GetControlRotation().GetNormalized().Pitch == TargetRotator.GetNormalized().Pitch
TargetRotator = PC->GetControlRotation() + AdditionalRotator;
// BasePos * AddRotate
TargetQuat = PC->GetControlRotation().Quaternion()* AdditionalQuat;
'언리얼 > 언리얼 기능' 카테고리의 다른 글
쿼터니언 정규화 (0) | 2024.11.14 |
---|---|
채널 프리셋 (1) | 2024.09.23 |
언리얼 보간 (Interpolation) (1) | 2023.10.19 |
UStruct static_cast (0) | 2023.09.04 |
Delegate 관리 (0) | 2023.07.23 |