[UE5] Animation Blueprint Linking - Lyra 스타일 애니메이션 시스템 구축 (프로젝트ASR - 개발일지7)
더 많은 종류의 적을 추가하고 플레이어 캐릭터에도 점프, 달리기, 앉기 등 다양한 애니메이션들을 추가로 세팅할 때가 되었다. 기능은 이전에 구현해 놓았으나 문제는 기존 애니메이션 블루프린트가 전혀 모듈화 되어있지 않다는 것이었다.
전투 시스템을 전부 리뉴얼하고 나서 테스트를 위해 아래처럼 간단한 애니메이션 블루프린트를 계속 사용하고 있었으며 공격과 관련된 애니메이션은 시점에 맞는 이벤트 수집을 위해 애니메이션 몽타주로 관리하고 있다.
프로젝트에서 애니메이션 시스템 전체를 다시 설계, 최적화하여 변경 사항이 매우 많지만 이번 포스팅에서는 Animation Blueprint Linking, Animation Layer Interface만 소개하려 합니다
https://www.youtube.com/watch?v=OjKul_DsJNs
(작업 중인 애니메이션 영상)
Animation Blueprint Linking
공격 애니메이션의 경우 부모 클래스에 정의된 Montage를 대체하고 Anim notify를 세팅하기만 하면 다형성에 의해 다양한 캐릭터에서 세팅한 애니메이션이 정상적으로 재생된다.
하지만 애니메이션 블루프린트도 애니메이션을 지정하는 부분과 State Machine의 로직을 분리하도록 하는 기능이 있을 것이라고 생각하였고 Lyra의 애니메이션 시스템을 참고하였고 Animation Blueprint Linking, Anim Layer Interface라는 것을 알게 되어 이를 적용하였다.
AnimGraph의 하위 섹션을 동적으로 전환할 수 있도록 해주는 기능으로 애니메이션 블루프린트가 사용하지 않는 애니메이션 에셋을 더 이상 로드하지 않아 메모리 절감에도 도움이 된다.
Animation Layer Interface를 사용하여 구현할 수 있다.
Animation Layer Interface
이름에서 알 수 있듯이 Interface이다. 애니메이션 블루프린트는 이를 상속하게 할 수 있으며 필수적으로 구현이 필요한 것들이 생긴다. C++ Interface에서는 함수의 구현이 필요하지만 Animation Layer Interface는 Layer(Pose)의 구현이 필요하다.
Content Drawer에서 우클릭하고 Animation Layer Interface를 만들자.
이후 Add 버튼을 누르면 Layer를 추가할 수 있다.
Interface를 사용할 모든 Animation Blueprint에서 공통적으로 사용할 Pose를 Layer로 만들자.
다시 애니메이션 블루프린트를 열고 Class Settings에서 Implemented Interfaces에 방금 만든 인터페이스를 추가하자.
그리고 State의 Pose에 Animation Layer Interface의 Layer를 연결한다. (지금 Pose를 연결한 애니메이션 블루프린트를 앞으로 ABP_Base라고 부름)
ABP_Base는 이제 State Machine에서 State 간의 Transition Rule과 IK, Blend, Warping 등 애니메이션 전반을 관리하는 로직을 담고 있으며 각 State의 애니메이션이 어떻게 구성되어 있는지는 신경 쓰지 않는다.
ABP_LocomotionLayersBase
이제 Animation의 Layer의 구현을 담당할 Animation Blueprint를 새로 만들자 (이하 ABP_LocomotionLayersBase)
아까와 같이 Anim Layer Interface를 추가한 뒤, Layer에 맞는 Pose를 만들고 노드를 연결한다.
Base란 이름이 붙인 이유는 부모 클래스로 사용할 애니메이션 블루프린트이기 때문이다.
한 번 더 상속 구조를 나눠 Interface Layer의 구현을 부모 클래스에 맡기고 애니메이션 시퀀스의 지정, 특수한 애니메이션 기능 구현은 파생 클래스에서 담당한다.
사용할 애니메이션을 Anim Sequence 자료형의 변수로 ABP_LocomotionLayersBase에 추가하고 아래와 같이 만든 애니메이션 변수를 노드에 연결한다.
Blending이 필요한 달리기, 걷기 애니메이션은 Sequence Evaluator의 OnUpdate 함수에 바인딩을 추가한 뒤 Set Sequence with Inertial Blending 노드를 사용하였다.
점프 시작과 같이 State에 진입하면 애니메이션이 확정되는 애니메이션은 Sequence Player 노드에서 애니메이션을 고정하였다.
Distance Matching이 필요하거나 State 진입 시점에서 조건에 따라 애니메이션이 선택되는 Layer에서는 Sequence Evaluator를 사용하였고 OnBecomRelevant 함수에 바인딩하고 Set Sequence를 사용하여 진입 시점에 애니메이션을 지정하였다.
Derived Animation Blueprint
모든 Layer의 Pose를 구현했다면 이제 파생 클래스를 만들자. Content Drawer에서 ABP_LocomotionLayersBase를 우클락하고 Create Child Anim Blueprint with Skeleton을 클릭하자.
만든 애니메이션 블루프린트를 열고 상단의 Class Defaults를 누르고 아래처럼 애니메이션 시퀀스를 지정해 주면 끝이다.
(만든 애니메이션 블루프린트는 검과 방패를 들고 있을 때 애니메이션 세트로 ABP_SwordAndShield라고 부르겠다)
캐릭터는 여전히 Interface의 구현이 빠져있는 ABP_Base를 애니메이션 블루프린트로 사용한다.
이제 Layer의 Pose 구현과 애니메이션들이 모두 존재하는 ABP_SwordAndShield를 ABP_Base에 Link 시켜주면 된다.
// SkeletalMeshComponent.cpp
void USkeletalMeshComponent::LinkAnimClassLayers(TSubclassOf<UAnimInstance> InClass)
{
if(AnimScriptInstance)
{
AnimScriptInstance->LinkAnimClassLayers(InClass);
}
}
SkeletalMeshComponent에서 함수 하나로 간단하게 Anim Layers를 연결할 수 있다.
이제 ABP_Base를 복사하고 내부에 있는 모든 State의 애니메이션을 교체하는 비효율 적인 작업 대신 무기가 검, 방패에서 대검으로 바뀌어도 간단하게 애니메이션 세트만 세팅한 ABP_GreatSword를 만들어 Link 하여 캐릭터 애니메이션을 변경할 수 있다.
무기 데이터가 정의된 DataTable에 ABP_GreatSword, ABP_SwordAndShield, ABP_Bow 등 무기에 따라 정의한 애니메이션 블루프린트 파생 클래스를 저장하고 무기 교체 함수에서 이를 처리하면 착용하고 있는 무기에 따라 유기적으로 애니메이션이 변경되는 시스템을 구축할 수 있다.
작업중에 작성했던 포스팅이라 연산 노드가 추가되어 빠른 경로가 해제되거나 ThreadSafe를 사용하지 않은 노드들이 캡쳐되어 있는데 멀티스레드 애니메이션 업데이트를 사용하는 것은 애니메이션 최적화에 매우 중요하기 때문에 아래 링크를 참고하여 세팅하는 것을 추천한다.
https://dev.epicgames.com/documentation/ko-kr/unreal-engine/animation-optimization-in-unreal-engine
https://www.youtube.com/watch?v=N_suMyUuork
Reference