▲ 에픽게임즈 사와다 유타로 엔지니어

게임 속에 존재하는 물체들은 그냥 움직이지 않는다. 간단하게 숨을 들이쉬고, 흔들거리는 동작마저도 여러 장의 화면을 연속 촬영, 조작해 마치 화면 속 물체나 캐릭터가 움직이는 것처럼 보이게 하는 애니메이션 기법의 결과물이다. 이렇게 만들어진 것들을 데이터화한 뒤에 재생하거나 혹은 사전에 내재한 뒤 처리 과정을 통해 게임 속 캐릭터와 사물에 움직임을 부여하는 것이다.

이전에는 애니메이션을 위한 툴은 별도로 존재했지만, 기술이 발전하면서 상용 엔진에서도 캐릭터나 사물의 애니메이션을 처리할 수 있는 툴과 기능이 지원되기 시작했다. 언리얼 엔진4는 더 나아가, 코딩 없이도 캐릭터의 움직임의 조건을 처리하는 파라미터를 구현하고 애니메이션에 적용되는 수치를 조절할 수 있도록 했다. 프로그래밍을 몰라도, 캐릭터의 움직임을 만들어가고 그 동작 사이사이를 이어서 다양한 연출을 할 수 있게 한 것이다.

그럼에도 어떻게 언리얼 엔진4에서 애니메이션을 만들지?'라는 의문은 이어질 수밖에 없다. 코딩 없이 노드를 세팅하고, 파라미터를 조율할 수 있도록 블루 스크린이 만들어졌지만 그 외에도 애니메이션을 만들기 위해서는 여러 문제에 필연적으로 봉착하기 때문이다. 이번 CEDEC 2018 강연에서 에픽게임즈의 사와다 유타로 서포트 엔지니어는 언리얼 엔진으로 애니메이션을 만드는 방법과, 주의할 점을 소개했다.




3D 애니메이션의 기초는 폴리곤을 구성하고 있는 요소를 이동, 전이를 한 뒤 원하는 프레임에 키값을 부여하는 것이다. 이 과정에도 각 프레임에 입력된 키값이 연속으로 재생되면서 움직임이 구현된다는 기초적인 원리가 적용되기 때문이다. 그렇지만 일반적으로 이 방법은 게임에서 많이 사용되지 않는다. 물이나, 캐릭터 모델처럼 폴리곤이 많은 오브젝트를 폴리곤 단위로 x, y, z값이나 여타 값을 일일이 다 조정하기에는 번거롭고 시간도 오래 걸리기 때문이다.

▲ 제일 기초적인 애니메이션은 폴리곤 애니메이션이지만, 조금만 복잡해져도 사용하기 어렵다

이 방식은 단순히 번거롭거나 작업하는데 시간이 오래 걸리는 것을 넘어서, 생성되는 데이터의 양도 많아진다는 단점이 있다. 사람이 점 하나하나를 일일이 옮기는 것처럼 엔진 내에서도 오브젝트를 이루는 버텍스나 라인, 혹은 폴리곤들에 대한 명령 하나하나 일일이 받은 뒤, 이를 처리해나가기 때문이다.

그렇게 해서 만들어진 방식이 본 애니메이션 방식이다. 본 애니메이션은 여러 개의 폴리곤 안에 뼈대를 심고 연결해서 애니메이션을 만드는 방식이다. 이러한 방식을 사용하면 뼈대에 연결된 폴리곤은 뼈대가 움직이면서 같이 움직이게 되는데, 일일이 움직이는 것보다 엔진에서 처리하는 과정 자체가 간단해진다. 종속 관계와 연결 관계를 설정된 부분을 파악한 뒤, 그 부분을 함께 움직이면 되기 때문이다.

본 애니메이션을 구현할 때 유의할 점은, 움직임을 자연스럽게 구현하기 위해서는 웨이트 등을 고려해야 한다는 점이다. 버텍스 등에 걸리는 웨이트에 신경쓰지 않으면 관절이 구부러질 때 형태가 우그러지거나 하는 일도 있기 때문이다. 그러나 사람이 움직이는 원리와 비슷하고, 편하다는 장점 때문에 3D 애니메이션에서 가장 많이 쓰는 기법이며, 오늘 강연에서도 이 부분을 중심적으로 설명할 것이라고 밝혔다.

언리얼 엔진4에서 본 애니메이션 작업에는 에셋들이 사용된다. 기반이 되는 뼈대에 부드러운 애니메이션을 줄 수 있도록 하는 애니메이션 시퀀스와, 뼈대 위에 입혀진 폴리곤 세트인 스켈레탈 메시 등이다. 이것들이 합쳐질 때 비로소 본 애니메이션이 완성된다.


그 외에도 언리얼 엔진4에서는 내부적으로 애니메이션을 구현하기 위해 다양한 에셋과 기능을 지원한다. 스켈레탈 메시의 애니메이션을 제어하는 비주얼 스크립팅 에셋인 애니메이션 블루프린트가 그 중 하나다. 애니메이션 로직이 모여있는 에셋이기 때문에 처음에 언리얼 엔진4로 애니메이션 작업을 할 때 가장 많이 보게 되는 에셋이기도 하다. 다만 애니메이션 블루프린트를 활용하기 위해서는 뼈대가 먼저 갖춰져야 한다.

하나의 캐릭터에 적용된 물리 애니메이션을 다른 캐릭터에도 적용하기 위해서 다른 애니메이션 블루프린트에 대한 애니메이션을 레퍼런스를 생성하고 호출하는 구조인 서브 애니메이션 블루프린트가 있다. 그러나 이 역시도 동일한 뼈대를 지정해야 한다. 애니메이션 블루프린트에 이미 만들어진 결과를 조정하기 위한 에셋이 포스트 프로세스 애니메이션 블루프린트다. 포스트 프로세스 애니메이션 블루프린트는 스켈레탈 메시에 직접 할당할 수 있다. 따라서 애니메이션 블루프린트가 스켈레탈 메시 컴포넌트의 메인 애니메이션의 인스턴스로 할당된 이후에도 항상 실행되는 애니메이션 블루프린트를 스켈레탈 메시에 할당할 수 있다.

▲ 애니메이션 작업을 하면서 가장 많이 보게될 애니메이션 블루프린트

하나, 혹은 소수의 애니메이션에는 이와 같은 블루프린트만으로도 충분하지만 다수의 애니메이션을 작업할 때는 작업이 번거롭다. 이를 해소하기 위한 에셋이 애님 컴포짓이다. 애님 컴포짓은 다수의 애니메이션을 합쳐 하나의 단위로 취급할 수 있도록 하는 에셋으로, 블렌딩 기능이 아니라는 점은 유의해야 한다.

애니메이션 몽타주는 특정 트랙에서 애니메이션 시퀀스를 유지하면서 블렝딩 등을 진행하기 위해 마련된 에셋이다. 그룹이나 슬롯 단위로 복수의 애니메이션을 관리할 수 있는 것이 특징이다. 애니메이션 노티파이 에셋을 통해 애니메이션 시퀀스 도중의 특정 지점에 이벤트가 발생하도록 구성할 수 있으며, 여기에서 시작, 틱, 끝의 3단계 이벤트 지정을 할 수 있는 애니메이션 노티파이 스테이트를 통해서 그래프를 조절할 수 있다.

애니메이션 시퀀스에서는 커브 형태로 애니메이션의 정보가 기록이 되는데, 애니메이션 모디파이어를 통해서 커브의 정보나, 노티파이된 정보를 추가하거나 수정하는 것이 가능하다. 애니메이션 모디파이어는 다른 에셋에 의존하지 않고 독립적으로 작성 가능하지만, 스켈레톤에 애니메이션 모디파이어를 적용하면 해당 스켈레톤을 기반으로 한 모든 애니메이션 시퀀스에 모디파이어가 적용된다는 점에 유의해야 한다.

스테이트 머신은 스켈레탈 메시의 애니메이션을 일련의 스테이트로 분해하여 그래프로 표시해주는 에셋이다. 애니메이션 블루프린트 안에서 작성하며, 개별의 에셋화가 되지 않는다는 특징이 있다. 애니메이션에 있는 1프레임의 본의 상태를 보존한 상태에서 포즈 에셋이 사용 가능하다. 이 에셋을 모아서 새로운 애니메이션을 만들어내는 것이 가능하다. 예를 들어서 서있는 기본 자세를 설정한 뒤, 포즈 에셋을 모아서 앉아있는 자세의 애니메이션을 만들 수 있다. 그 외에도 무기나 손에 쥘 것이 아직 만들어지지 않았을 때에도, 마치 이것을 쥐고 있는 것처럼 뼈대를 움직이게 할 수 있는 버추얼 본 기능 등이 언리얼 엔진4 내에서 지원된다.

▲ 이밖에도 언리얼 엔진4에는 다양한 에셋과 기능이 있다

애니메이션을 만드는 데 사용하는 에셋이나 시스템을 알았다면, 애니메이션이 어떤 식으로 처리되는 지도 알 필요가 있다. 사와다 엔지니어는 스레드, 즉 프로세스가 실행되는 흐름에 대해서 짚고 넘어갔다. CPU 스레드는 크게 다섯 가지의 스레드로 구분된다. 게임의 메인을 처리하는 게임스레드, 게임스레드를 보조처리하는 태스크스레드, 쉐이더 컴파일이나 UDP 통신 등을 처리하는 풀스레드, 렌더링에 관련된 처리를 담당하는 렌더스레드, GPU에 명령을 전달하는 RHI 스레드가 그것이다.

애니메이션 과정에서는 주로 게임스레드와 태스크, 렌더스레드가 작업에 관여한다.일반적으로 게임 내에서는 게임스레드가 가장 많이 관여하고, 때로는 게임스레드에서만 처리해서 FDX가 떨어지는 일도 발생한다. 이를 막기 위해서는 스레드와 애니메이션 처리에 대한 기본적인 이해도 필요하다고 사와다 엔지니어는 덧붙였다.

언리얼 엔진4에서 애니메이션을 만들게 되면, 크게 세 가지 단계를 거친다. 이벤트가 시작되고 정보가 호출되는 이벤트 업데이트를 거쳐서 애니메이션 그래프가 업데이트되는 그래프 업데이트, 이를 연산하고 수행하는 그래프 이벨류에이트 단계를 거친다. 스레드 상으로 볼 때 이벤트 스레드는 게임 스레드에서 처리되고, 그래프 부분은 태스크, 게임 스레드에서 처리된다.


뼈대 위에 덧씌워지는 스키닝 처리는 렌더스레드에서 진행되며, GPU스키닝과 CPU스키닝으로 구분된다. 혹은 스키닝없이 처리가 되기도 한다.GPU스키닝은 베이스패스의 버텍스셰이더부터 실제의 처리 과정을 확인할 수 있으며, 내부적으로 4개에서 8개까지의 본, 혹은 옵션을 통해서 2개까지의 본에만 영향을 받도록 모드를 설정할 수 있다. 본의 제한은 ProjetSetting에 있는 Rendering 메뉴의 Optimzation창에서 설정할 수 있다.

CPU 스키닝은 렌더스레드를 통해서 렌더스키닝이 업데이트된 이후, 스키닝 끝에 베이스패스를 그려나가는 방식이다. CPU스키닝이 발생하는 조건은 청크가 최대 본의 수까지 구성되거나, 혹은 FeatureLevel에 지정된 개수를 넘을 때 발생한다. 혹은 인플루언스본의 최대치가 4 이상을 넘었을 때에도 발생하게 된다. GPU와 CPU스키닝 외에도, 스태틱 옵션이 설정되어있을 경우 스키닝 처리가 스킵되는 경우도 있다.

▲ 스키닝 처리 방식은 CPU, GPU 두 가지가 있으며, 때로는 스키닝 처리 없이 연산으로 넘어가기도 한다

사와다 엔지니어는 이런 이론적인 부분을 넘어서 실제로 애니메이션 작업에 들어가게 되면 가장 많이 듣는 말이 '압축'이라고 설명했다. 애니메이션 작업에서 중요한 것은 런타임메모리나 사이즈를 최소화하고, 가능한한 불필요한 것을 없애는 것이기 때문이다. 그렇게 해야 어떤 상황에도 애니메이션이 쾌적하게 이어진다. 하나의 오브젝트에만 애니메이션을 입혔을 때는 실감하기 어려운 부분이지만, 여러 오브젝트를 한 번에 애니메이션을 주게 되면 이를 절실히 느끼게 될 것이라고 사와다 엔지니어는 예고했다. 이러한 압축 작업을 위해서 존재하는 것이 애니메이션 컴프레스 기능이다. 자동으로 처리해주는 오토매틱에서부터 거의 손실 없이 진행하는 Least Destructive 등이 있으며, 이를 활용해서 작업을 압축하는 것이 가능하다고 설명했다.

그 외에 뼈대의 공통화 작업을 통해서 애니메이션의 처리량을 최소화하는 방법도 존재한다. 하나의 애니메이션을 다수의 캐릭터에게 적용하면, 애니메이션 데이터와 메모리가 최소화될 수 있기 때문이다. 이렇게 뼈대 애니메이션을 공유하기 위해서는 이름과 계층구조를 하나로 처리하도록 해야 한다. 이때 새로운 본을 끼워넣는 일은 불가능하지만, 끄트머리에 새로운 본을 추가하는 것은 가능하다.

▲ 뼈대를 타 오브젝트와 공유하면 뼈대 사이에 새 뼈를 만들 수는 없지만, 끝에 이어서 만드는 것은 가능하다

뼈대를 공유할 때 주의해야 할 점은, 갱신했을 때 스켈레톤의 참조한 모든 애니메이션 시퀀스가 갱신된다는 점이다. 현재로서 이에 대한 대응책은 가능한 한 필요한 본이 최초부터 포함될 수 있도록 설계하는 수밖에 없는 만큼, 주의를 기울일 필요가 있다고 사와다 엔지니어는 강조했다.

그 외에 애니메이션 처리가 증대화되는 문제를 푸는 방법으로 세부적인 최적화가 있다고 사와다 엔지니어는 설명했다. 본에서부터 디테일하게 LOD를 살펴보면, 본을 지정해서 스키닝에서 제외하는 것이 가능하다. 그렇게 해서 스키닝 처리가 불필요한 부분을 없애고 처리 속도를 높일 수 있다. 애니메이션 노티파이에서는 애니메이션 시퀀스에 설정해둔 애니메이션 노티파이의 메시 LOD 상태에 따라 호출의 불가 여부를 변경할 수 있다. 이를 활용해서 불필요한 부분의 호출을 막을 수 있다.

▲ 노출되지 않는 부분을 지정해서 스키닝 처리를 하지 않도록 예외로 둘 수 있다.

애니메이션 그래프에서는 블루프린트의 연산을 최소한으로 호출할수록 처리가 빨라진다. 연산을 최소한으로 호출하기 위한 기능 중에는 패스트패스가 있는데, 이는 연산을 실행하지 않고 참조하는 것으로 블루프린트를 호출하는 기능이다. 그렇지만 모든 것을 패스트패스에 적용하기에는 무리가 따른다. 패스트패스는 그래프 업데이트 단계에서 처리되는데, 모두 패스트패스로 처리하면 이벤트 그래프에 처리하기 때문에 분산 처리가 되지 않고 일원처리가 되서 더 느려질 수 있기 때문이다.

게임상에서 일반적으로 캐릭터나 사물은 하나 이상의 움직임이 구현되며, 상황에 따라서 다른 애니메이션으로 변화가 이어지기도 한다. 하나의 애니메이션이 다른 애니메이션으로 전환되는 과정을 애니메이션 블렌딩이라고 하는데, 이 과정을 매끄럽게 하는 것이 애니메이션을 잘 만들기 위한 필수 조건이라고 사와다 엔지니어는 강조했다. 극단적으로 두 애니메이션이 거의 동시에 블렌딩이 일어날 경우, 이도저도 아닌 어색한 동작이 튀어나와버리기 때문이다.

블렌딩을 매끄럽게 하기 위해서는 업데이트 처리 과정을 다시 지켜볼 필요가 있다. 애니메이션의 연산 처리는 그래프 이벨류에이트 단계에서 이루어진다. 그리고 지정된 시간의 포즈는 애니메이션 시퀀스의 GetBonePose함수에서 만들어진다. 연산 처리 과정에서는 스켈레탈 메시의 본, 스켈레톤 본, 애니메이션 시퀀스의 본 이동 데이터 세 가지를 연산을 하게 된다. 여기에서 시퀀스 데이터는 스켈레톤을 베이스로 한다. 즉 애니메이션 데이터는 스켈레톤 베이스라서, 실제의 메시에 본이 존재하는 것만 연산 처리를 진행한다.


애니메이션 블루프린트의 각 트랙에서 보완처리를 하는 방법도 있다. 시퀀스에 지정되지 않은 것들이나, 키와 키 사이의 그래프를 조절하는 것이다. 또한 애니메이션 시퀀스 노드에서 오버랩스되는 타임을 줄여서 자연스럽게 연결해나가는 방법도 있다.

사와다 엔지니어는 여태까지 설명한 것처럼, 애니메이션 작업이 과부하될 위험이 높은 작업이라고 강조했다. 즉 작업을 진행하면 할수록 필요하지 않은 부분까지 쌓이고, 그로 인해서 처리하기가 곤란한 경우가 많이 발생할 수 있다는 것이다. 이 부분에 대한 설명 자체가 어찌보면 처음 언리얼 엔진4를 접하려는 사람에게는 과부하가 걸릴 정도로 어려울 수도 있다. 그렇지만 실제로 실습해보고 앞서 말한 것들을 발견해가면서 차츰 실습하다보면 좀 더 쉽게 게임 내 애니메이션을 구축할 수 있을 것이라고 전망했다.


8월 22일 개최된 일본 개발자 컨퍼런스 CEDEC 2018의 강연 정보와 뉴스를 현지에 나가 있는 박광석, 윤서호 기자가 생생하게 전달해드립니다 ▶ 인벤 뉴스센터: https://goo.gl/ha5vNc