24.05.08 - 24.05.22
프로토타입 구현 일지
에임 오프셋을 통해 상반신의 움직임이 에임을 따라가도록 설정하자.
어제 받았던 애니메이션 에셋이 너무 뭐가 없어서.. 라이라 프로젝트 샘플에서 에셋을 가져왔다. 우선 어제 만들었던 애니메이션들을 다 대체해주고, 에임 오프셋도 만들어주겠다!
흠..... Locomotion을 베이스 포즈로 설정하고 에임 오프셋을 섞어줬는데 포즈가 요염하게 나와버린다....
공식 문서를 찾아보니 모든 애니메이션 시퀀스의 베이스 포즈 타입을 설정해줘야 하는데, 귀찮아서 안했던게 문제였다.
Edit Selection in Property Matrix를 사용하면 한번에 수정 가능하다.
이렇게 옵션을 지정하고 저장해주면 된다.
이렇게 정상적으로 움직이는걸 확인할 수 있었다. 일단 문제는, 에임 오프셋이 Yaw 회전에 대해서만 작용한다는 것.
어떤게 문제인지 모르겠어서 우선은 공식 문서에 나와있는 블루프린트대로 코드를 구현해보았다.
// UPlayerAnimInstance::NativeUpdateAnimation
FRotator CurrentRotator(AimPitch, AimYaw, 0);
FRotator TargetRotator = UKismetMathLibrary::NormalizedDeltaRotator(Owner->GetControlRotation(), Owner->GetActorRotation());
FRotator Rotator = UKismetMathLibrary::RInterpTo(CurrentRotator, TargetRotator, GetDeltaSeconds(), 15);
AimPitch = UKismetMathLibrary::Clamp(Rotator.Pitch, -90, 90);
AimYaw = UKismetMathLibrary::Clamp(Rotator.Yaw, -180, 180);
이렇게 구현해도 문제는 똑같다. 이것저것 막 건들여봤더니 이번엔 Pitch 회전값만 들어가는데.. 아무래도 카메라와 컨트롤 관련 옵션을 함께 확인해봐야 할 것 같다.
에임 오프셋이 정상적으로 동작하도록 컨트롤 옵션을 바꿔보자.
우선, 내가 생각했을 때 Pawn은 Use Controller Rotation Yaw만 true 해야한다. 그리고 항상 캐릭터의 뒷모습을 봐야하므로, Spring Arm의 Use Pawn Control Rotation을 켜주고 Pitch와 Yaw를 상속시켰다.
지금 Pawn 자체는 Yaw 회전만 들어가고, Pitch 값은 들어가지 않는 상태다. Pawn의 컨트롤 옵션에서 Use Controller Rotation Yaw만 true로 해놨으니 당연한 결과이다.
근데 왜 AnimInstance에서 Log를 찍어봤을 땐 Pitch값만 들어가는걸까..? 액터에는 정상적인 Yaw 값이 들어가고 있고, AnimInstance쪽에는 정상적인 Pitch값이 들어간다.
Use Controller Rotation Yaw까지 false 해야 값이 제대로 들어간다. 도대체 이유가 뭘까?? 집가야하니까 다음에 이어서 알아보자..
실마리를 찾았다. 컨트롤 옵션에는 문제가 없고, 코드상에서 NormalizedDeltaRotator
함수 이후로 Pitch값만 제대로 출력되고, 나머지는 값이 출력되지 않는다는 것을 발견했다.
NormalizedDeltaRotator
는 벡터 A에서 B를 뺀 값을 정규화시킨 값을 리턴해주는데, 블루프린트에서 이 노드를 쓰는 이유가 중요하다.
언리얼에서 FRotator는 0~ 360 사이에서만 반복되는데, 이 값을 그대로 사용하게 되면 0에서 아래로 내리는 순간 360로 바뀌기 때문에, 총이 원하는 방향을 가리키지 않게 된다. 나는 0에서 -90방향으로 총이 서서히 회전하길 바라는 것이므로, 최단경로를 사용해야 한다.
FRotator를 Normalize시키면, 최단경로를 고려해 값을 반환해주기 때문에 음수가 정상적으로 나오게 된다. 원하는 값을 구하려면 컨트롤러의 회전자를 정규화시키면 되는데, 블루프린트에는 회전자를 정규화시켜주는 함수가 없다! 그래서 저 함수를 사용했던 것. 컨트롤러의 Pitch에서 액터의 Pitch(Yaw만 컨트롤러의 회전값을 반영하므로 Pitch값은 0이다)를 빼주면 언제나 컨트롤러의 Pitch값(최단거리를 고려한)이 나오게 된다. 왜 이 과정을 끝낸 후 Yaw값이 0이었냐 하면, 컨트롤러의 Yaw 회전값은 Pawn에 반영되고 있기 때문. 두 값이 같다면 결과는 0이 된다. 회전값이 0이기 때문에, Yaw 회전값은 변하지 않는다.
나는 어차피 C++을 사용해 코드를 짤 것이므로, 컨트롤 회전을 바로 정규화 시킨 값으로 바꿔주었다.
FRotator TargetRotator = Owner->GetControlRotation().GetNormalized();
FRotator Rotator = UKismetMathLibrary::RInterpTo(FRotator(AimPitch, AimYaw, 0), TargetRotator, GetDeltaSeconds(), 15);
AimPitch = UKismetMathLibrary::Clamp(Rotator.Pitch, -90, 90);
AimYaw = UKismetMathLibrary::Clamp(Rotator.Yaw, -180, 180);
이게 바로 내가 원했던 움직임이었는데..... 위 영상처럼 결과를 확인해보니 애초에 3인칭 시점에서 Yaw값을 에임 오프셋에 집어넣을 필요가 없었음.... 기획분께 말씀드리고 에임 오프셋은 Pitch값만 사용하기로 결정했다. 그래도 공부가 많이 됐으니까!!!!! 난 만족해!!!!
Aim Offset 1D로 바꿔주었다. 아직 디테일하게 만질 것들은 많지만, 우선은 마무리하고 카메라 회전을 구현하기로 했다.