Blender에서 Python으로 애니메이션 구현 & Unreal Engine 5에서 Pytorch 사용하기

aarchiiive·2023년 2월 15일
0

지난주에 이어 Blender로 애니메이션을 만드는 데에 계속 공을 들여봤다. 저번주는 값을 일일이 대입했다면 이번에는 간단한 Python 코드를 만들어 한번에 실행해봤다. MHFormer에서 나온 3D keypoints를 quaternion 값으로 변환한 후 이를 캐릭터의 뼈에 넣어보는 작업이다.

먼저 Mixamo에서 마음에 드는 무료 캐릭터를 하나 다운로드 받는다. Mixamo는 Adobe사에서 제공하는 무료 애니메이션, 캐릭터를 받을 수 있는 곳이다. 접속하면 아래와 같이 다양한 캐릭터와 애니메이션들이 있다. 여기서 아무거나 선택한 후 .fbx 파일로 다운로드하면 된다. 캐릭터만 다운로드 받으면 기본적으로 T-Pose이다.

다운로드 버튼을 누르면 아래와 같은 창이 뜨는데 아마 Blender 2.92에서는 FBX 7 이상은 호환이 안될 것이다. 따라서 FBX 6.x로 다운로드….

Blender에 fbx 파일을 import하면 Armature라는 이름의 object가 하나 생긴다. 여기서 mesh는 볼 필요 없기 때문에 Pose, Armature를 제외한 다른 것들은 보이지 않게 숨겨두었다.

여기까지 진행했을 때 공간 상에 아래와 같은 뼈대가 덩그러니 남겨진다.

코드 부분을 이야기하기 전에 bpy 모듈에 대한 내용은 아래 링크를 참고하면 된다.

Blender 3.4 Python API Documentation — Blender Python API

이제 애니메이션을 구현해야 한다. keypoints의 개수가 Mixamo에서 제공하는 bones의 개수보다 훨씬 적어 선별하는 작업을 해야했다. 궁금해서 모든 bone의 이름을 출력해봤고 일일이 골라냈다.

bones_list = ['mixamorig:Hips', 'mixamorig:Spine', 'mixamorig:Spine1', 'mixamorig:Spine2', 'mixamorig:Neck', 
              'mixamorig:Head', 'mixamorig:HeadTop_End', 'mixamorig:LeftShoulder', 'mixamorig:LeftArm', 
              'mixamorig:LeftForeArm', 'mixamorig:LeftHand', 'mixamorig:LeftHandThumb1', 'mixamorig:LeftHandThumb2',
              'mixamorig:LeftHandThumb3', 'mixamorig:LeftHandThumb4', 'mixamorig:LeftHandIndex1', 'mixamorig:LeftHandIndex2',
              'mixamorig:LeftHandIndex3', 'mixamorig:LeftHandIndex4', 'mixamorig:LeftHandMiddle1', 'mixamorig:LeftHandMiddle2', 
              'mixamorig:LeftHandMiddle3', 'mixamorig:LeftHandMiddle4', 'mixamorig:LeftHandRing1', 'mixamorig:LeftHandRing2',
              'mixamorig:LeftHandRing3', 'mixamorig:LeftHandRing4', 'mixamorig:LeftHandPinky1', 'mixamorig:LeftHandPinky2',
              'mixamorig:LeftHandPinky3', 'mixamorig:LeftHandPinky4', 'mixamorig:RightShoulder', 'mixamorig:RightArm',
              'mixamorig:RightForeArm', 'mixamorig:RightHand', 'mixamorig:RightHandThumb1', 'mixamorig:RightHandThumb2',
              'mixamorig:RightHandThumb3', 'mixamorig:RightHandThumb4', 'mixamorig:RightHandIndex1', 'mixamorig:RightHandIndex2',
              'mixamorig:RightHandIndex3', 'mixamorig:RightHandIndex4', 'mixamorig:RightHandMiddle1', 'mixamorig:RightHandMiddle2',
              'mixamorig:RightHandMiddle3', 'mixamorig:RightHandMiddle4', 'mixamorig:RightHandRing1', 'mixamorig:RightHandRing2', 
              'mixamorig:RightHandRing3', 'mixamorig:RightHandRing4', 'mixamorig:RightHandPinky1', 'mixamorig:RightHandPinky2', 
              'mixamorig:RightHandPinky3', 'mixamorig:RightHandPinky4', 'mixamorig:LeftUpLeg', 'mixamorig:LeftLeg', 'mixamorig:LeftFoot',
              'mixamorig:LeftToeBase', 'mixamorig:LeftToe_End', 'mixamorig:RightUpLeg', 'mixamorig:RightLeg', 'mixamorig:RightFoot', 
              'mixamorig:RightToeBase', 'mixamorig:RightToe_End']

여기서 또 rotation_mode를 Quaternion, XYZ, ZXY로 하느냐 등등 여러 갈림길과 어려움이 있었지만…. 최종적으로 진행했던 코드이다. 이 과정에서 선형대수학이나 Character rigging 등 다른 분야의 지식이 중요하다는 것을 여실히 느끼게 되었다. 어느 축은 Z가 위를 향해있고 어느 축은 Y가 위를 향해있고 등등 생각했던 것보다 복잡한 구조였다. 3D keypoints의 좌표들을 어떻게 quaternion 값들로 변환할지 등 다양한 문제가 있었다. 이야기하자면 글을 하나 새로 다시 써야 하지만 나름 다양한 방법들을 시도해봤고 결국 실패했다.

import bpy
import os
import numpy as np
targets = ["mixamorig:LeftUpLeg", "mixamorig:LeftLeg", "mixamorig:RightUpLeg", "mixamorig:RightLeg",
           "mixamorig:LeftArm", "mixamorig:LeftForeArm", "mixamorig:RightArm", "mixamorig:RightForeArm", 
           "mixamorig:Hips", "mixamorig:Spine2", "mixamorig:Neck", "mixamorig:Head"]

keypoints = np.load("quaternion.npy")
bones = bpy.data.objects["Armature"].pose.bones
for i in range(len(keypoints)):
    for k, t in zip(keypoints[i], targets): 
        bones[t].rotation_mode = "QUATERNION"
        bones[t].rotation_quaternion = k
        bones[t].keyframe_insert(data_path="rotation_quaternion", frame=(i+1)*2)

영상은 처음에 Euler angle로 시도했을 때의 화면이다. 다른 사진을 다시 첨부하지 않은 이유는 덜 기괴하거나 더 기괴하거나… 였기 때문이다. 결과는 비슷했다.

이제 구현 기간이 얼마 남지 않았다고 생각하기 때문에 애니메이션을 연동하는 것을 내려둘 지는 미지수이다..

다른 이야기로 넘어가자면 프로젝트를 진행하던 중 결국 게임엔진을 사용해야겠다고 생각했다. 아직 게임엔진에 대한 이해도가 높지 않으므로 복잡한 로직을 구현할 것 같지는 않다. 백엔드처럼 Anaconda 터미널에서 Python 코드(모델, 연산 등)가 하나 돌고, 프론트 역할을 해주는 게임엔진을 실행시키면 서로 통신을 하기로 했다. 그런데 Unreal에서 Python scripting을 지원한다는 것을 보고 외부 라이브러리도 설치할 수 있을까라는 생각을 했다.

앞서서 이 글은 버전 5.0.3을 기준으로 작성되었다. 먼저 Unreal Engine을 실행한다.

왼쪽 상단에서 Edit>Editor Preferences를 클릭하고 검색창에 python을 검색한 후 develover mode를 켜준다.

왼쪽 상단에서 Edit>Plugins를 클릭하고 검색창에 python을 검색한다.

작성자의 환경에는 모두 설치해 두었기 때문에 체크표시가 있지만, Python Editor Script Plugin을 설치하면 된다. 그런데 Pytorch를 설치하려고 해봤던 건데 이미 플러그인이 있다….?

Python Foundation Packages를 보니 numpy와 pytorch를 설치해주는 플러그인이라고 설명되어있다. 바로 설치해봤고 터미널에 import해봤다.

버전을 확인해보니 1.9.0 버전으로 설치되었고 의외로 다른 삽질은 필요가 없었다. 첨언하자면 Unreal에서 Python을 사용하는 것이 불가능한 것은 아니다… 가능하지만 안하는게 좋겠다는 생각이 들었다. Blueprint 대신 C++을 사용하려고 Visual studio를 사용해봤는데 Intellisense가 너무 느리다. 과장해서 2~30초 정도 기다려야 하는 것 같다. 이렇게 방대한 프로젝트에는 다양한 헤더 파일과 cpp 파일들이 있을 텐데… 작성자와 같은 게임엔진 초보자는 더더욱 사용하기 힘들다는 생각을 했다. 그래서 VSCode에서 개발을 하기로 했고 그래도 Visual studio보다 훨씬 나았다. 설정 방법은 아래를 참고하면 된다.

언리얼 엔진용 VS Code 구성

C++도 이 정도로 느린데 Python은 아예 자동완성이 안된다. 먼저 자동완성 기능을 사용하려면 interpreter부터 인식을 해야한다. VScode에서는 Python excutable path만 지정해주면 interpreter가 알아서 설정되어야 하는데 그렇지도 않다. 참고로 C:\Program Files\Epic Games\UE_5.0\Engine\Binaries\ThirdParty\Python3\Win64 경로로 설정해주면 된다.(해봤는데 안된다) 이번주는 여기까지….

profile
Post Anything

1개의 댓글

comment-user-thumbnail
2023년 6월 27일

안녕하세요 제가 이거에 관해서 여쭤보고싶은데 가능하실까요?

답글 달기