본문 바로가기

프로시저럴 애니메이션 구현

IK와 물리 기반 애니메이션으로 지형·충돌에 실시간 반응하는 포즈를 만들고 적용 범위와 한계를 이해합니다.

지금까지는 애니메이션 시퀀스, 블렌드 스페이스, 애님 몽타주처럼 미리 만들어 둔 에셋으로 캐릭터를 움직였습니다. 그런데 평평한 바닥에서 만든 걷기 애니메이션을 경사로나 계단에서 재생하면, 한쪽 발은 허공에 뜨고 다른 발은 바닥을 파고듭니다. 바닥의 높이는 게임이 실행되는 순간에야 알 수 있으므로, 미리 만든 애니메이션만으로는 이 차이를 메울 수 없습니다.

이처럼 지형, 충돌, 물리 반응 같은 실행 중의 상황에 맞춰 포즈를 바로 바꿔야 할 때 쓰는 방법이 프로시저럴 애니메이션(procedural animation)입니다. 이 글에서는 프로시저럴 애니메이션이 무엇인지 살펴본 뒤, 언리얼 엔진에서 가장 많이 쓰는 두 기법인 IK와 물리 기반 애니메이션을 하나씩 연결해 봅니다. 그리고 미리 만든 애니메이션과 어떻게 나누어 쓰는지 정리합니다.


실행 중에 계산하는 애니메이션

프로시저럴 애니메이션은 미리 만든 애니메이션을 보완하거나 대신해서, 게임이 실행되는 동안 알고리즘이나 수학적 계산으로 만들어 내는 애니메이션입니다. 캐릭터의 뼈(bone)를 직접 제어하거나 물리 시뮬레이션을 적용해 동작을 만듭니다.

이 방법을 쓰면 경사에 맞춰 발의 각도를 바꾸거나, 무언가에 부딪혔을 때 팔다리가 자연스럽게 밀려나는 것처럼 미리 예상하기 어려운 상황에 바로 반응할 수 있습니다. 같은 걷기 애니메이션에 작은 흔들림을 더해 매번 조금씩 다른 움직임을 만들 수도 있고, 모든 세부 동작을 애니메이터가 손으로 만들지 않아도 되므로 제작 비용도 줄어듭니다. 발이 바닥에 정확히 붙는 것처럼 물리 법칙에 맞는 움직임은 캐릭터를 더 실감 나게 보이게 합니다.

언리얼 엔진의 애님 그래프는 이런 일을 하는 노드를 여럿 제공하며, 그중 대표적인 것이 IK와 물리 기반 시뮬레이션입니다.


IK: 목표에서 거꾸로 관절을 계산하기

일반적인 애니메이션은 정운동학(Forward Kinematics, FK) 방식으로 포즈를 만듭니다. 골반을 돌리고, 그 결과에 이어 허벅지를, 다시 그 결과에 이어 정강이를 돌리는 식으로 부모 뼈에서 자식 뼈 순서로 회전을 쌓아 갑니다. 그래서 발이 어디에 놓일지는 모든 회전을 쌓은 뒤에야 정해집니다.

역운동학(Inverse Kinematics, IK)은 순서를 거꾸로 뒤집습니다. 발이나 손 같은 끝 뼈의 목표 위치를 먼저 정하면, 시스템이 그 목표에 닿도록 부모 뼈들의 회전을 역으로 계산합니다. "발을 여기 놓아라"라고 지정하면 무릎과 허벅지가 알아서 맞춰지는 셈이라, 실행 중에 바닥의 높이가 바뀌는 상황에 잘 맞습니다.

IK는 여러 곳에 씁니다. 발 IK(Foot IK)는 경사진 지형을 걷거나 계단을 오를 때 발이 바닥에 붙도록 조절합니다. 손 IK는 캐릭터의 손이 문손잡이나 벽의 스위치 같은 물체에 정확히 닿게 하고, 조준 IK는 총을 든 캐릭터의 손과 팔 자세를 조준 방향에 맞춰 바꿉니다.

애님 그래프에 IK 노드 넣기

발 IK를 예로 들어 연결해 보겠습니다. 애님 블루프린트의 애님 그래프 탭으로 가서, 스테이트 머신이나 Slot 노드의 출력과 최종 Output Pose 사이에 Two Bone IK 노드를 넣습니다. 더 많은 뼈로 이루어진 사슬을 다뤄야 한다면 FABRIK 노드를 쓸 수도 있습니다.

Two Bone IK는 지정한 끝 뼈와 그 위의 부모 뼈 두 개, 즉 관절 세 개로 이루어진 사슬을 제어합니다. 이런 IK 노드는 컴포넌트 공간(component space)의 포즈를 다루므로, 스테이트 머신이 내놓는 로컬 공간(local space) 포즈를 Local to Component 변환을 거쳐 IK 노드에 넣고, IK를 적용한 결과를 Component to Local로 되돌려 Output Pose에 연결합니다.

노드의 주요 설정은 다음과 같습니다. IK Bone에는 IK를 적용할 끝 뼈를 지정하며, 발이라면 foot_l이나 foot_r 같은 이름입니다. Effector Location은 끝 뼈가 닿을 목표 위치 벡터이고, 공식 문서에 따르면 Effector Location Space에서 World Space, Component Space, Parent Bone Space, Bone Space 중 하나를 고를 수 있습니다. 이 예제는 목표 위치를 월드 좌표의 라인 트레이스로 구하므로 World Space를 고릅니다.

Joint Target Location은 가운데 관절인 무릎이 어느 방향으로 굽을지를 정하는 위치로, 무릎이 바깥쪽 앞으로 굽도록 유도하는 데 씁니다. 이 값도 Joint Target Location Space에서 고른 공간에 맞는 좌표를 넣어야 합니다. 마지막으로 Alpha는 IK의 영향력으로, 0.0이면 IK를 적용하지 않고 1.0이면 완전히 적용합니다. 보통 발이 바닥에 닿아 있을 때만 IK를 적용하므로 이 값은 실행 중에 바꿔 줘야 합니다.

이벤트 그래프에서 목표 위치 계산하기

이벤트 그래프의 Event Blueprint Update Animation에서 발이 닿아야 할 바닥의 위치를 계산합니다. 이 계산에는 주로 라인 트레이스(line trace)를 씁니다. 발 뼈의 위치 위쪽에서 아래로 선을 쏘아 바닥과 만나는 점을 찾는 방법이며, 트레이스는 환경 쿼리와 트레이싱 기본 활용에서 자세히 다룹니다. 발 뼈의 월드 위치는 Get Owning Component로 이 애님 블루프린트를 쓰는 스켈레탈 메시 컴포넌트를 얻은 뒤, 그 컴포넌트의 Get Socket Location에 foot_l 같은 뼈 이름을 넣어 구합니다. 이 위치보다 조금 위를 Start로, 조금 아래를 End로 Line Trace By Channel에 넣으면, 바닥에 맞았는지는 Return Value로, 맞은 지점은 Out Hit을 Break Hit Result로 나눠 꺼낸 Impact Point로 알 수 있습니다.

트레이스가 바닥에 맞으면 결과의 Impact Point 벡터 전체에 발바닥 두께만큼의 오프셋을 더해 목표 위치 변수(예: IK_Foot_L_Location)에 저장합니다. 이때 Z 값 하나만 꺼내 벡터 입력에 넣지 않도록 주의합니다. 목표는 X, Y, Z가 모두 있는 위치입니다.

함께 IK_Foot_L_Alpha 같은 Float 변수를 두고, 트레이스가 바닥에 맞았는지에 따라 0.0에서 1.0 사이로 갱신해 Two Bone IK의 Alpha 핀에 연결합니다. 트레이스가 실패했거나 캐릭터가 공중에 있으면 Alpha를 낮춰, 발이 마지막으로 성공한 지점에 고정된 채 남지 않게 합니다. 연결을 마쳤으면 컴파일하고 저장합니다.

목표 좌표를 손으로 계산해 보기

평평한 바닥에서 트레이스의 월드 Impact Point가 (100, 200, 12) cm이고, 이 예제의 발바닥 오프셋을 월드 위쪽으로 (0, 0, 3) cm로 정했다고 해 봅시다. 저장할 목표 벡터는 두 값을 더한 (100, 200, 15) cm이며, 이 벡터를 공간이 World Space인 Effector Location에 넣습니다.

같은 숫자라도 넣는 방법이 다르면 결과가 달라집니다. 목표의 Z 값 15만 넣는 것이나, Effector Location Space를 Component Space로 둔 채 같은 월드 좌표를 넣는 것은 이 설정과 같지 않습니다. 컴포넌트 공간은 스켈레탈 메시 컴포넌트를 기준으로 한 좌표이므로, 월드 좌표를 그대로 넣으면 엉뚱한 곳을 목표로 삼게 됩니다. 또 경사진 바닥이라면 오프셋의 방향과 발의 회전, 무릎 목표, 다리가 닿을 수 있는 범위, 골반 높이 보정까지 함께 다뤄야 하므로, 이 덧셈 한 번으로 발 IK가 완성되지는 않습니다.

이 발 IK는 기준 포즈 위에 필요한 만큼의 보정만 섞는 방식입니다. 그래서 관절이 닿을 수 있는 범위와 보정 거리, Alpha에 상한을 두고, 트레이스가 실패하거나 멀리 있어 LOD가 낮아진 경우에는 IK를 끄는 경로를 함께 만들어 둡니다.


물리 기반 애니메이션

물리 기반 애니메이션은 캐릭터의 뼈에 물리 시뮬레이션을 적용해 움직임을 만드는 방법입니다. 이때 쓰는 것이 피직스 에셋(Physics Asset)으로, 공식 문서는 이를 래그돌(ragdoll)을 이루는 강체(rigid body)와 컨스트레인트(constraint)의 묶음이라고 설명합니다. 피직스 에셋이 있으면 캐릭터가 외부 충격에 쓰러지거나, 팔다리가 중력에 따라 늘어지는 효과를 만들 수 있습니다.

대표적인 쓰임은 세 가지입니다. 래그돌 효과는 캐릭터가 죽거나 큰 충격을 받았을 때 애니메이션을 멈추고 물리 시뮬레이션으로 넘겨 자연스럽게 쓰러지게 합니다. 부분 물리 시뮬레이션은 옷자락, 머리카락, 작은 장신구에만 물리를 적용해 작은 흔들림을 만드는데, 5.8에서는 옷감용 Chaos Cloth, 애님 그래프의 보조 물리 노드, 줄이나 케이블을 위한 Cable Component처럼 도구가 용도별로 나뉘어 있으니 목적에 맞게 고릅니다. 마지막으로 조준할 때 어깨나 팔에 작은 관성을 더하는 것처럼, IK와 물리를 섞어 쓰는 경우도 있습니다.

래그돌로 전환하기

먼저 피직스 에셋을 준비합니다. 콘텐츠 브라우저에서 캐릭터의 스켈레탈 메시를 우클릭해 Create 메뉴의 Physics Asset 항목으로 만들 수 있고, 메시를 임포트할 때 Create Physics Asset 옵션을 켜 두어도 만들어집니다. 피직스 에셋 에디터에서는 뼈마다 충돌 형태와 관절의 회전 제한을 설정할 수 있습니다.

다음으로 캐릭터의 Mesh 컴포넌트에 이 피직스 에셋을 지정하고, 시뮬레이션에 맞는 충돌 프로파일(예: Ragdoll)을 설정합니다. 전신 래그돌은 애님 그래프의 RigidBody 노드로 하는 보조 시뮬레이션과는 다른 방법입니다. RigidBody 노드에 불리언 핀을 연결해 전신 래그돌을 켜는 것이 아니라, 컴포넌트 자체의 물리 시뮬레이션을 켜는 것입니다.

캐릭터의 이벤트 그래프에서 사망 조건이 충족되면 이동을 멈추고, Mesh를 대상으로 Set Simulate Physics를 true로 호출합니다. 캡슐 콜리전도 게임의 사망 처리 방식에 맞게 끄거나 바꿉니다. 래그돌에서 다시 애니메이션으로 돌아오는 일은 시뮬레이션을 끄는 것만으로 끝나지 않습니다. 쓰러진 메시와 캡슐의 위치를 맞추고, 일어나는 동작을 따로 만들어야 합니다.

전신이 아니라 장신구 같은 보조 구조의 흔들림만 원한다면, 애님 그래프에서 RigidBody 노드를 컴포넌트 공간에서 쓰고 Override Physics Asset과 Alpha 같은 설정을 조정합니다. 설정을 마쳤으면 컴파일하고 저장합니다.


미리 만든 애니메이션과 나누어 쓰기

프로시저럴 애니메이션은 게임 상황에 따라 실시간으로 바뀌는 동작을 만들 수 있고, 특정 종류의 애니메이션을 손으로 만들 일을 줄여 주며, 물리에 맞는 움직임으로 사실감을 높여 줍니다.

반면 한계도 분명합니다. 벡터와 좌표 공간, 물리 시뮬레이션을 이해해야 하므로 구현이 까다롭습니다. 물리 시뮬레이션은 때때로 의도하지 않은 결과를 내서 세밀하게 제어하기 어렵고, 복잡한 시뮬레이션이나 매 프레임의 트레이스는 실행 성능에 부담을 줄 수 있습니다.

그래서 프로시저럴 애니메이션은 키프레임 애니메이션을 완전히 대신하기보다, 키프레임 애니메이션이 채우지 못하는 부분을 보완하거나 특별한 효과를 내는 데 씁니다. 기본 걷기 애니메이션은 그대로 두고 발 IK로 지형에 발을 맞추는 것이 전형적인 예입니다. 미리 만든 동작이 큰 움직임을 맡고, 프로시저럴 보정이 실행 중의 작은 차이를 메우도록 섞어 쓰는 것이 효과적입니다.


정리

  • 프로시저럴 애니메이션은 실행 중에 계산으로 포즈를 만들거나 보정하는 방법이며, 대표적인 기법은 IK와 물리 기반 애니메이션입니다.
  • FK는 부모 뼈에서 자식 뼈로 회전을 쌓고, IK는 끝 뼈의 목표 위치에서 부모 뼈의 회전을 거꾸로 계산합니다.
  • Two Bone IK는 끝 뼈와 부모 뼈 두 개를 제어하며, Effector Location의 값은 Effector Location Space에서 고른 공간의 좌표여야 합니다.
  • 발 IK의 목표는 트레이스의 Impact Point 전체에 오프셋을 더한 벡터이고, 트레이스가 실패하면 Alpha를 낮춰 보정을 줄입니다.
  • 전신 래그돌은 Mesh의 Set Simulate Physics로, 보조 구조의 흔들림은 애님 그래프의 RigidBody 노드로 처리하며, 래그돌에서 돌아오는 동작은 따로 만들어야 합니다.

연습 문제

1. 다음 프레임의 목표와 실패 조건

같은 평평한 바닥과 3cm 오프셋에서 다음 Impact Point가 (150, 250, 20) cm라면 목표 벡터는 무엇일까요? 그다음 프레임에는 트레이스가 실패했고, 이 연습의 실패 처리 방식은 Alpha를 0으로 두는 것입니다. 이전에 성공한 좌표가 변수에 남아 있다면 IK 보정이 계속 적용될까요?

해설 보기

목표는 (150, 250, 20)에 (0, 0, 3)을 더한 (150, 250, 23) cm입니다. Z만이 아니라 X와 Y도 함께 갱신된다는 점을 놓치지 않습니다.

트레이스가 실패해 Alpha가 0이 되면, 이전 목표 벡터가 변수에 남아 있어도 그 IK 노드의 보정 영향은 0입니다. 목표 좌표가 있다는 것과 그 보정이 실제로 적용되는지는 서로 다른 조건입니다. Alpha를 한 번에 0으로 바꾸지 않고 서서히 낮추는 방식도 있지만, 그것은 따로 정하는 게임의 처리 방식이므로 이 문제의 즉시 0 조건과 섞지 않습니다.

2. Z 값만 넣은 목표

동료가 Impact Point에서 Z 값만 꺼내 3을 더한 뒤, 그 숫자를 Effector Location 벡터의 Z에만 넣고 X와 Y는 0으로 두었습니다. 공간은 World Space이고, Impact Point는 본문의 예처럼 (100, 200, 12) cm입니다. 발은 어디로 가려고 할까요?

해설 보기

발은 월드 좌표 (0, 0, 15) 쪽으로 뻗으려고 합니다. World Space에서 X와 Y를 0으로 두면 월드 원점 위를 목표로 삼는 것이므로, 캐릭터가 서 있는 곳과 전혀 다른 방향으로 다리를 끌어당기게 됩니다.

목표 벡터는 Impact Point의 X, Y, Z를 모두 쓰고 오프셋을 더해 만들어야 합니다. 또 Effector Location Space를 바꾸면 같은 숫자의 뜻이 달라지므로, 좌표를 계산한 공간과 노드에서 고른 공간이 같은지 함께 확인합니다.

3. 전신 래그돌과 장신구 흔들림

사망한 캐릭터를 쓰러뜨리는 효과와, 살아 있는 캐릭터의 허리에 달린 주머니가 걸을 때 흔들리는 효과를 만들려고 합니다. 두 효과에 각각 어떤 방법이 알맞을까요?

해설 보기

사망한 캐릭터는 전신 래그돌이 알맞습니다. 이동을 멈추고 Mesh 컴포넌트에서 Set Simulate Physics를 true로 호출해, 애니메이션 대신 물리 시뮬레이션이 몸 전체를 움직이게 합니다. 캡슐 콜리전도 사망 처리 방식에 맞게 정리합니다.

주머니의 흔들림은 애님 그래프의 RigidBody 노드가 알맞습니다. 캐릭터는 계속 걷기 애니메이션을 재생하고, 주머니에 해당하는 뼈에만 보조 물리를 더하면 됩니다. 이 경우에 전신 래그돌을 켜면 캐릭터 전체가 쓰러져 버리므로 두 방법을 섞지 않습니다.

Two Bone IK 노드의 설정과 좌표 공간은 언리얼 엔진 공식 문서의 Two Bone IK에서, 피직스 에셋은 피직스 에셋 에디터 문서에서 확인할 수 있습니다.

이것으로 7장을 마칩니다. 7장에서는 애님 블루프린트의 이벤트 그래프와 애님 그래프를 나누는 데서 시작해, 스테이트 머신으로 상태를 전환하고, 블렌드 스페이스로 속도에 따라 동작을 섞고, 몽타주와 노티파이로 한 번 재생하는 공격을 연결한 뒤, IK와 물리로 실행 중에 포즈를 보정하는 방법까지 살펴봤습니다. 다음 장의 비헤이비어 트리의 기본 이해부터는 비헤이비어 트리와 블랙보드, EQS, 내비게이션, 감지 시스템으로 스스로 판단하고 움직이는 AI를 만듭니다.