본문으로 건너뛰기

Babylon.js 애니메이션 런타임 사용

Babylon.js의 애니메이션 시스템을 사용하여 MMD 애니메이션을 재생하면 다음과 같은 장점을 제공합니다:

  • Babylon.js Animation Curve Editor 지원
  • 애니메이션 블렌딩 지원
  • 보다 일반화된 애니메이션 관리

따라서 babylon-mmd는 Babylon.js의 애니메이션 시스템을 사용하여 MMD 애니메이션을 재생하는 방법을 제공합니다.

Babylon.js 애니메이션 시스템 아키텍처

먼저 Babylon.js 애니메이션 시스템 아키텍처의 기능을 이해하는 것이 필요합니다.

Babylon.js Animation

Babylon.js에서 애니메이션은 주로 Animation 객체를 사용하여 표현됩니다.

Animation 객체는 특정 속성에 대한 애니메이션 키프레임을 저장하는 컨테이너입니다.

애니메이션으로 제어할 수 있는 8가지 타입이 있습니다:

  • Float (숫자)
  • Vector3
  • Quaternion
  • Matrix
  • Color3
  • Color4
  • Vector2
  • Size

각 타입은 서로 다른 보간 방법을 사용합니다.

예를 들어, Float 타입은 선형 보간을 사용하고, Quaternion 타입은 **구면 선형 보간(SLERP)**을 사용합니다.

Animation 객체는 시간 t에 대해 값을 평가하는 _interpolate 메서드를 제공합니다.

하지만 바인딩 대상에 애니메이션을 적용하는 로직은 포함되지 않습니다.

Babylon.js Runtime Animation

RuntimeAnimationAnimation 객체를 실제로 평가하고 이를 대상에 바인딩하는 역할을 담당합니다.

애니메이션 평가 로직의 일부와 바인딩 경로 해결을 위한 로직이 RuntimeAnimation 객체에 구현되어 있습니다.

Babylon.js Animatable

Animatable여러 개의 RuntimeAnimation 객체를 관리하고 씬의 렌더링 루프와 동기화하여 애니메이션을 업데이트하는 역할을 담당합니다.

복잡한 애니메이션 블렌딩 로직도 여기서 처리됩니다. (Babylon.js는 애니메이션 블렌딩을 지원합니다.)

따라서 다음과 같이 Animatable 객체를 사용하여 여러 개의 RuntimeAnimation 객체를 동시에 재생하여 MMD 모델 애니메이션을 재생할 수 있습니다:

Animatable Diagram 이 다이어그램은 Animatable, RuntimeAnimation, Animation 객체와 바인딩 대상 간의 참조 관계를 보여줍니다.

babylon-mmd는 Animatable 객체 접근 방식을 직접 사용하지 않으므로, 실제 다이어그램은 다소 다릅니다.

Babylon.js Animation Group

AnimationGroupAnimation 객체와 바인딩 대상을 쌍으로 관리하는 컨테이너입니다.

Animation Group Diagram 이 다이어그램은 AnimationGroupAnimation 객체와 바인딩 대상을 쌍으로 관리하는 방법을 보여줍니다.

AnimationGroup은 애니메이션을 재생하기 위해 내부적으로 Animatable 객체를 사용합니다. 사용을 더 쉽게 하기 위해 더 높은 수준의 API를 제공합니다.

Animation Group With Animatable Diagram 이 다이어그램은 AnimationGroup이 애니메이션을 재생하기 위해 내부적으로 Animatable 객체를 사용하는 방법을 보여줍니다.

Babylon.js 애니메이션 시스템을 사용하여 MMD 애니메이션 재생하기

Babylon.js의 애니메이션 시스템을 사용하여 MMD 애니메이션을 재생하기 위해 제공되는 주요 방법은 두 가지입니다:

  1. Animation 객체의 _interpolate 메서드를 사용한 애니메이션 평가 후 직접 바인딩
  2. AnimationGroup 객체를 사용한 애니메이션 평가 및 바인딩

각 방법의 장단점은 다음과 같습니다:

방법장점단점
방법 1
(Animation 사용)
Babylon.js Animation Curve Editor 지원MmdAnimation에 비해 성능 저하메모리 사용량 증가
방법 2
(AnimationGroup 사용)
Babylon.js 애니메이션 시스템의 모든 기능 사용 가능방법 1에 비해 더 큰 성능 저하더 많은 메모리 사용량

이제 이 두 방법을 사용하여 MMD 애니메이션을 재생하는 방법을 살펴보겠습니다.

애니메이션 컨테이너 클래스

Animation 객체는 단일 속성에 대한 애니메이션 키프레임을 저장하는 컨테이너입니다.

하지만 우리가 다루는 MMD 애니메이션은 여러 속성에 대한 애니메이션 키프레임을 포함합니다.

따라서 babylon-mmd는 여러 개의 Animation 객체를 함께 관리하는 컨테이너 클래스 MmdCameraAnimationContainerMmdModelAnimationContainer를 제공합니다.

MmdCameraAnimationContainerMmdModelAnimationContainer는 각각 MmdCameraMmdModel에 적용되도록 설계된 Animation 객체의 컬렉션을 관리합니다.

이들은 다음과 같이 생성됩니다:

const modelBezierBuilder = new MmdModelAnimationContainerBezierBuilder();
const cameraBezierBuilder = new MmdCameraAnimationContainerBezierBuilder();

const mmdModelAnimationContainer = new MmdModelAnimationContainer(mmdAnimation, modelBezierBuilder);
const mmdCameraAnimationContainer = new MmdCameraAnimationContainer(mmdAnimation, cameraBezierBuilder);

애니메이션 컨테이너를 생성할 때 빌더가 함께 전달된다는 점주목하세요.

이는 Babylon.js의 애니메이션 시스템이 MMD 애니메이션의 보간 방법을 완전히 지원하지 않기 때문입니다.

Babylon.js는 키프레임 간의 베지어 보간을 지원하지 않으며, 기본적으로 제공되는 세 가지 주요 보간 방법은 다음과 같습니다:

  • Linear
  • Step
  • Hermite

Hermite 보간은 inTangent와 outTangent를 사용하여 Cubic Spline 보간을 구현하는데, 이는 베지어 보간보다 자유도가 낮습니다.

따라서 babylon-mmd는 베지어 보간을 지원하기 위해 세 가지 옵션을 제공합니다:

  • Mmd(Model/Camera)AnimationContainerHermiteBuilder: Hermite 보간을 사용하여 Mmd(Model/Camera)AnimationContainer를 생성합니다.
    • 이 방법은 베지어 보간 탄젠트를 Hermite 보간 탄젠트로 근사합니다. 이 방법은 정확도가 낮으며 특히 카메라 애니메이션에서 상당한 차이를 보일 수 있습니다.
  • Mmd(Model/Camera)AnimationContainerSampleBuilder: 베지어 보간을 선형 보간으로 근사합니다.
    • 이 방법은 베지어 곡선을 30프레임 간격으로 샘플링하고 선형 보간으로 근사합니다. 이 방법은 높은 정확도를 가지지만 메모리 사용량이 증가합니다. 또한 애니메이션이 편집 불가능하게 된다는 단점이 있습니다.
  • Mmd(Model/Camera)lAnimationContainerBezierBuilder: 베지어 보간을 정확하게 구현합니다.
    • 이 방법은 Animation 객체의 _interpolate 메서드를 오버라이드하여 베지어 보간을 정확하게 구현합니다. 이는 가장 정확한 방법이지만, Animation 객체의 _interpolate 메서드를 오버라이드하여 존재하지 않는 보간 방법을 강제로 추가하므로 Animation Curve Editor와 같은 도구가 제대로 작동하지 않을 수 있습니다.

생성된 MmdModelAnimationContainerMmdCameraAnimationContainer는 각각 MmdModelMmdCamera바인딩될 수 있습니다. 바인딩 방법에 따라 Animation 객체의 _interpolate 메서드만 사용할지, 아니면 AnimationGroup을 통해 RuntimeAnimationAnimatable 객체를 사용할지가 결정됩니다.

방법 1: Animation 객체 사용

babylon-mmd는 MmdModelAnimationContainerMmdCameraAnimationContainer직접 바인딩하는 런타임 구현을 제공합니다.

이는 "babylon-mmd/esm//Runtime/Animation/mmdRuntimeCameraAnimationContainer""babylon-mmd/esm/Runtime/Animation/mmdRuntimeModelAnimationContainer" 모듈을 가져옴으로써 사용할 수 있습니다.

import "babylon-mmd/esm/Runtime/Animation/mmdRuntimeCameraAnimationContainer";
import "babylon-mmd/esm/Runtime/Animation/mmdRuntimeModelAnimationContainer";

이를 통해 MmdAnimation을 바인딩하는 것과 동일한 방법으로 MmdCameraMmdModel 객체의 createRuntimeAnimation 메서드를 사용하여 Mmd(Camera/Model)AnimationContainer를 바인딩할 수 있습니다.

const camera: MmdCamera = ...;
const model: MmdModel = ...;

const cameraAnimationHandle = camera.createRuntimeAnimation(mmdCameraAnimationContainer);
const modelAnimationHandle = model.createRuntimeAnimation(mmdModelAnimationContainer);

방법 2: AnimationGroup 객체 사용

MmdModelAnimationContainerMmdCameraAnimationContainerAnimationGroup 객체를 생성하기 위한 createAnimationGroup 메서드를 제공합니다.

const modelAnimationGroup = mmdModelAnimationContainer.createAnimationGroup("modelAnimation", mmdModel);
const cameraAnimationGroup = mmdCameraAnimationContainer.createAnimationGroup("cameraAnimation", mmdCamera);

이제 AnimationGroup API를 사용하여 애니메이션을 재생할 수 있습니다.

modelAnimationGroup.play(true);
cameraAnimationGroup.play(true);

AnimationGroup 객체는 재생뿐만 아니라 여러 애니메이션의 블렌딩을 포함한 여러 기능을 제공합니다. 자세한 내용은 Babylon.js 공식 문서를 참조하세요.

정보

AnimationGroup 객체를 사용하여 애니메이션을 재생할 때는 MMD 런타임이 더 이상 애니메이션의 실행 주체가 아니므로, MMD 런타임에 오디오를 추가하더라도 오디오와 애니메이션이 동기화되지 않습니다.