-
[UE5 | FPS] 1인칭 카메라의 애니메이션을 위한 구조 설계언리얼엔진/FPS 프로젝트 2024. 5. 4. 17:50
1인칭 게임인 FPS는 몰입감을 위해서 특정 행동을 하는 애니메이션에는 카메라 애니메이션이 포함되어있다.
카메라 애니메이션 덕분에 자신이 조종하는 캐릭터가 어떠한 행동을 하는 동안 머리가 흔들리는 느낌을 시각적으로 표현할 수 있다.
거기에 더 나아가 카메라가 흔들리는 동안 크로스헤어는 카메라가 아닌 캐릭터에 고정되게 해서 모니터의 중앙에서 벗어나게되고, 그 덕분에 흔들림을 직접적으로 비교할 수 있는 대상이 있으므로 더 효과적으로 체감되게 해준다.
예시로 에이펙스 레전드의 카메라 에니메이션을 가져왔다.
달리기 무기 교체 1 무기 교체 2 무기 교체 3 이런 카메라 애니메이션은 에이펙스 레전드 뿐만 아니라 콜 오브 듀티 등 다양한 게임에서 볼 수 있다.
언리얼 엔진에서 FPS를 만들때 이런 느낌의 카메라 애니메이션을 구현하려면 어떻게 해야할지 오랫동안 고민한적이 있었고, 그렇게 찾은 방법이 의도대로 잘 작동해서 한번 정리해보려고 한다.
최종 결과물은 이렇다.
먼저 카메라 애니메이션은 자연스러움을 위해 플레이어 캐릭터의 팔 애니메이션에 맞게 제작되어야한다.
애니메이션을 제작할 때에도 카메라의 애니메이션을 보면서 작업해야한다.
그렇다면 편의를 위해서 팔 애니메이션에 카메라 애니메이션을 포함하는 방법을 생각할 수 있고, 애니메이션 에셋도 하나씩만 존재하므로 관리하기도 편하다.
따라서 팔 스켈레톤에 카메라 본을 만들어서 거기에 카메라 애니메이션을 넣고, 언리얼 엔진에서는 카메라를 이 본에 어태치하는 방식을 쓴다.
언리얼 엔진에서 카메라를 본에 어태치 할때, 카메라의 로컬 로테이션을 변경하지 않아도 앞을 보게하기 위해 카메라 본의 +x축을 앞을 향하게 제작했다.
하지만 블렌더와 언리얼 엔진의 좌표계 차이 때문에 문제가 발생할 가능성이 있을듯 하다.
현재까진 큰 문제는 없는듯 하지만, 다음부터는 -y축에 맞춰서 제작할 예정이다.
언리얼 엔진에서는 캐릭터의 컴포넌트 계층 구조를 이렇게 설정한다.
카메라는 팔 메시에 어태치 되어있고, 팔 메시는 스프링 암에 어태치한다.
여기에서 폰 제어는 카메라가 아닌 스프링 암에서 하게된다.
cpp코드에서 캐릭터의 생성자에서는 아래와같이 설정했다.
// PlayerCharacter 생성자 코드 SpringArmComponent = CreateDefaultSubobject<USpringArmComponent>(FName("SpringArm")); SpringArmComponent->TargetArmLength = 0.f; SpringArmComponent->bUsePawnControlRotation = true; SpringArmComponent->bInheritPitch = true; SpringArmComponent->bInheritYaw = true; SpringArmComponent->bInheritRoll = false; SpringArmComponent->bDoCollisionTest = false; SpringArmComponent->SetupAttachment(GetRootComponent()); ArmMesh = CreateDefaultSubobject<UNLViewSkeletalMeshComponent>(FName("ArmMesh")); ArmMesh->bOnlyOwnerSee = true; ArmMesh->CastShadow = 0; ArmMesh->SetupAttachment(SpringArmComponent); ViewWeaponMesh = CreateDefaultSubobject<UNLViewSkeletalMeshComponent>(FName("ViewWeaponMesh")); ViewWeaponMesh->bOnlyOwnerSee = true; ViewWeaponMesh->CastShadow = 0; ViewWeaponMesh->SetupAttachment(ArmMesh, FName("weapon")); CameraComponent = CreateDefaultSubobject<UNLPlayerCameraComponent>(FName("Camera")); CameraComponent->SetupAttachment(ArmMesh, FName("camera")); CameraComponent->FieldOfView = 110.f;
이렇게 하면 폰의 제어는 스프링 암에서 담당하고 카메라는 스프링 암과 팔 메시에 붙어서 따라다니므로 1인칭 카메라의 조작에도 문제가 없고 애니메이션도 적용된다.
다음으로 크로스헤어를 고정한다.
참고로 스프링 암을 캡슐 높이의 중앙쯤에 두고, 소켓 오프셋과 타겟 오프셋을 이용해서 높이를 조정하면 위 아래를 볼때 허리를 숙이는 느낌이 들게 할 수 있다.
타깃 오프셋이 중심 위치라고 생각하면 된다.
소켓 오프셋은 중심에서 부터의 오프셋이다.
회전을 하면 중심을 기준으로 회전하게 되므로, 소켓 오프셋이 멀어질수록 회전 반경이 커지게 된다.
카메라 높이에서 회전 허리 높이에서 회전 아주 작은 차이지만, 이런 디테일이 모이면 몰입감에 많은 영향을 준다.
크로스헤어의 위치는 카메라의 중심이 아니라 플레이어가 제어하고 있는 방향을 가리켜야한다.
플레이어 컨트롤러에는
GetPlayerViewPoint
라는 함수가 있는데 이 함수는 카메라의 중심 위치와 회전값을 리턴한다.대신에 플레이어 컨트롤러의
GetControlRotation
함수는 캐릭터의 컨트롤 로테이션을 리턴하므로 플레이어가 제어중인 방향을 구할 수 있다.컨트롤 로테이션은 카메라가 바라보는 방향에 영향받지 않는다.
카메라의 위치와 컨트롤 로테이션을 통해 캐릭터가 바라보는 방향을 알 수 있으니 크로스헤어를 여기에 그리면 된다.
HUD 클래스에는 월드 좌표를 화면 좌표로 투영하는
Project
함수가 있으므로 이걸 활용하면 된다.그리고 HUD 클래스는 화면 좌표값을 이용해서 사용자 위젯의 위치를 설정하는
SetPositionInViewport
함수도 존재하므로 이런 상황에 사용하기에 좋다.HUD 블루프린트 HUD 블루프린트 크로스헤어로 사용할 위젯을 만든 다음 이런 방식으로 화면에서의 위치를 설정해주면 된다.
참고로 FPS에는 탄 퍼짐이 있어서 크로스헤어 중심으로 일정 각도 내에서 탄이 퍼져서 발사되기도 하는데 컨트롤 로테이션을 퍼짐 각도만큼 회전한 다음
Project
하면 탄 퍼짐이 얼마나 있는지를 정확하게 보여줄 수도 있다.
마지막으로 카메라 애니메이션이 포함된 팔 애니메이션을 만들고 적용하면 된다.
이렇게 하면 카메라에 애니메이션이나 카메라 쉐이크가 있어도 크로스헤어는 영향을 받지 않게된다.
이렇게 구현된 크로스헤어를 기준으로 총알이 발사되도록 한 경우에 캐릭터 제어를 조금 바꾸면 아래처럼 독특한 조작도 가능하다.
주제와는 관련없지만 재밌어서 올려본다.
'언리얼엔진 > FPS 프로젝트' 카테고리의 다른 글
[UE5 | FPS] 히트 박스를 관리하기 위한 에디터 유틸리티 (1) 2024.06.02 [UE5 | FPS] 수평 FOV와 수직 FOV, 그리고 뷰모델 (0) 2024.05.08 [UE5 | FPS] 애니메이션 블루프린트 링크 (1) 2024.05.07 [UE5 | FPS] 반동을 담하는 ControlShake와 반동 패턴 (0) 2024.05.06 [UE5] 발사체의 탄성 구현 (0) 2023.12.27