11.1 캐릭터 애니메이션의 종류

11.1.1 셀 애니메이션

셀 애니메이션을 전자적인 형태로 구현한 것이 스프라이트 애니메이션이다.

셀 애니메이션은 2D 게임 시대의 핵심 기법이었다.

 

11.1.2 계층적 강체 애니메이션

초기의 3D 캐릭터 애니메이션 기법은 캐릭터를 여러 조각의 강체로 모델링하는 계층적인 강체 애니메이션이었다.

캐릭터 애니메이션에 사용한다면 몸체가 관절에서 갈라지기 때문에 보기에 좋지 않다.

 

11.1.3 정점 애니메이션과 모프 타겟

정점 애니메이션 기법을 사용하면 애니메이터가 만든 메시의 정점들로부터 게임 엔진에서 실시간으로 움직일 정점 데이터를 추출할 수 있다. 하지만 이 방법을 사용하면 시간에 따라 변화하는 움직임 정보가 메시의 각 정점에 저장되어야 하기 때문에 데이터 양이 매우 커져 실시간 게임에는 잘 사용되지 않는다.

 

실시간 게임에 사용되는 기법에서는 모프 타겟 애니메이션 기법을 사용한다.

이 방식에서는 애니메이터가 메시의 정점들을 움직여 상대적으로 적은 개수의 고정된 핵심 포즈를 몇 개 만든다.

실행 시에는 이 고정된 핵심 포즈를 두개 혹은 그 이상을 섞어 애니메이션을 생성할 수 있다. 생성되는 애니메이션의 각 정점 위치는 핵심 포즈들의 정점 위치로부터 선형 보간 기법을 사용하여 계산할 수 있다.

 

모프 타겟 기법은 주로 표정 애니메이션에 사용된다. 사람 얼굴은 50개 이상의 근육으로 이루어진 굉장히 복잡한 조직이기 때문이다.

 

11.1.4 스킨 애니메이션

정점 애니메이션이나 모프 타겟 애니메이션과 같이 애니메이션되는 메시의 삼각형들을 변형할 수 있다는 장점이 있다.

그러면서도 효율적인 성능과 메모리 사용량을 갖는 계층적 강체 애니메이션의 이점도 함께 갖는다.

 

뼈대의 관절부분에 스킨이라 불리는 매끄럽고 연속적인 삼각형 메시가 붙는다.

스킨의 정점들은 관절의 움직임을 따라간다.

스킨 메시의 각 정점들은 다수 관절에 가중치를 갖고 결합될 수 있어 관절의 움직임에 따라 자연스럽게 스킨이 늘어날 수 있게 된다.

 

11.2 뼈대

뼈대는 관절이라고 하는 강체 조각들의 계층으로 이루어져 있다.

 

11.2.1 뼈대 계층 구조

뼈대의 관절들은 계층 구조나 트리 구조로 형성된다. 하나의 루트 관절이 있고 다른 모든 관절들은 자식이 되거나 자식의 자식이 되는 식으로 연결된다.

 

보통 각 관절에 0에서 N-1까지 번호를 붙인다. 각 관절마다 부모 관절의 번호를 저장하도록 하면 계층 구조 전체를 저장할 수 있다.

 

11.2.2 뼈대를 메모리에 저장

일반적인 뼈대의 자료구조

struct Joint
{
    Matrix4x3 m_invBindPose; // 관절의 바인드 포즈 역변환
    
    const char* m_name; // 관절의 이름
    
    U8 m_iParent; // 부모 관절의 인덱스 // 8비트로 최대 256개의 관절을 지원 // 루트라면 -1 (0xFF)을 저장
    
}

struct Skelton
{
    U32 m_jointCount; // 관절의 수
    
    Joint* m_aJoint; // 관절의 배열
}

 

11.3 포즈

11.3.1 바인드 포즈 (= 레퍼런스 포즈, 레스트 포즈, T 포즈)

3D 메시가 뼈대에 연결되기 전의 포즈이다.

뼈대가 연결되지 않은 삼각형만으로 이루어진 원래 상태의 메시 모습이다.

11.3.2 로컬 포즈

관절의 포즈는 대부분의 경우 부모 관절을 기준으로 지정한다.

관절의 포즈는 이동, 회전, 크기 변환의 합성행렬로 나타낼 수 있다.

전체 뼈대의 포즈는 모든 관절의 포즈의 집합이라고 할 수 있다.

 

11.3.2.1 관절 스케일

포즈나 애니메이션에서 스케일을 생략하거나 제한하면 몇 가지 이득이 있다.

관절 스케일(크기 변환)을 사용하지 않으면 저장 공간을 줄일 수 있다. (크기 행렬 파라미터를 받지 않아도 된다.)

비균일 스케일을 허용하면 관절의 경계 구가 타원체로 변화하지 않는다. 그렇기 때문에 절두체 검사나 충돌 검사를 관절 단위로 하는 엔진에서 필요한 연산을 대폭 줄일 수 있다.

 

11.3.2.2. 관절 포즈를 메모리에 저장

관절 포즈는 대개 SQT 형태로 저장된다. 

struct JointPose
{
    Quaternion m_rot; // Q
    Vector3 m_trans; // T
    F32 m_scale; // S
}

struct SkeletonPose
{
    Skeleton* m_pSkeleton; // 뼈대 자료구조, 관절의 개수 정보
    JointPose* m_aLocalPose;  // 각 관절의 로컬 관절 포즈
}

 

11.3.2.3 기저 변환으로서의 관절 포즈

관절 j의 좌표 공간을 표현한 점 혹은 벡터에 관절 표준 변환(QTS로 만든 변환)을 적용한 결과는 부모 공간에서의 점이나 벡터가 된다.

 

11.3.3 글로벌 포즈 (= 모델 공간 포즈)

관절 j의 모델 공간 포즈를 얻으려면 그 관절에서 시작해 뼈대의 계층을 루트까지 거슬러 올라가면서 각 관절의 로컬 포즈를 곱해 나가면 된다.

 

11.3.3.1 글로벌 포즈 구현

매번 행렬의 곱셈을 계산하기보다는 SkeletonPose 구조체에 글로벌 포즈 변환 행렬을 멤버로 추가하는 방법을 사용한다.

 

11.4 클립

게임은 캐릭터가 어떻게 움직이고 행동할지 예측할 수 없기 때문에 게임 애니메이션은 길게 이어지는 프레임으로 제작하지 않는다.대신 게임 캐릭터의 움직임을 수 많은 세세한 동작 단위로 끊어서 만든다. 이 개별적인 움직임들을 애니메이션 클립 또는 그냥 애니메이션이라고 부른다.

 

각 클립에는 캐릭터가 수행하는 잘 정의되는 동작 한 개가 들어 있다.

어떤 클립은 걷거나 뛰기 사이클처럼 루핑되는 것도 있고 한 번씩만 재생되는 것도 있다.

 

애니메이션을 클립을 사용하지 않고 제작하는 경우는 플레이어와 캐릭터가 상호작용을 하지 않는 부분에 등장하는 IGC, NIS, FMV 장면을 만드는 경우이다.

 

인 게임 시네마틱(IGC, in-game cinematic), 비상호작용 장면(NIS, non-interactive sequence)는 일반적으로 게임 엔진에서 실시간으로 렌더링 하는 경우를 지칭한다.

 

풀 모션 비디오(FMV, full-motion video)는 어떤 장면을 미리 MP4나 WMV 또는 다른 형식의 동영상 파일로 만들어 놓은 다음 게임 엔진의 전체 화면 동영상 재생기로 실행 시 재생하는 경우를 말한다.

 

11.4.1 로컬 타임라인

모든 애니메이션 클립은 로컬 타임라인을 갖고 있다. 보통 독립된 변수 t로 표현하고,

 t의 값은 0 (클립의 시작점) ~ T(클립의 전체 재생시간) 범위의 값을 가진다.

 

11.4.1.1 포즈 보간과 연속 시간

애니메이터가 프레임 단위로 포즈를 잡을 필요는 없다.

애니메이터는 클립 내의 특정 시각에 키 포즈나 키 프레임이라 불리는 주요한 포즈를 만든다.

비어 있는 클립은 컴퓨터를 이용, 선형이나 곡면 보간 등의 방법을 사용하여 채운다.

포즈들 사이를 보간하는 엔진의 기능 덕분에 정수 프레임 뿐만 아니라 실수 프레임에서의 캐릭터 포즈도 추출할 수 있다.

시간 척도 변수를 사용하여 애니메이션을 원래보다 빠르게, 느리게, 거꾸로 재생할 수 있다. 실수 프레임에서의 포즈 추출이 이럴 때 필요하다.

 

11.4.1.3 프레임과 샘플

프레임이라는 용어는 1/30초 1/60초와 같이 시간 간격을 나타낼 때 쓰고

애니메이션의 특정 시각을 나타낼 때는 샘플이라는 용어를 쓰자.

 

11.4.1.4 프레임, 샘플, 루핑 클립

루핑 클립에서 첫 번째 포즈와 마지막 포즈는 똑같기 때문에 보통 게임 엔진은 루핑 클립의 마지막 샘플을 생략한다.

 

루핑 클립이 아닌 경우 N 프레임 애니메이션에는 N + 1 개의 고유한 샘플이 있다.

루핑 클립인 경우 마지막 샘플은 군더더기이므로 N 개의 고유한 샘플이 있다.

 

11.4.1.5 정규화된 시간(위상)

타임라인 변수의 범위를 0 ~ T에서 0 ~ 1로 정규화 하면 편리한 경우가 있다.

재생시간이 2초(60프레임)인 달리기 애니메이션을 3초(90프레임)인 걷기 애니메이션으로 부드럽게 크로스 페이드 하고 싶 은 경우

11.4.2 글로벌 타임라인

게임의 모든 캐릭터에는 글로벌 타임라인(캐릭터가 처음 게임 월드에 생성된 시점, 특정 레벨이 시작되는 시점 또는 게임이 처음 시작할 때 시작되는 시계)이 있다.

 

애니메이션을 재생한다라는 것을 클립의 로컬 타임라인을 캐릭터의 글로벌 타임라인에 매핑한다고 생각할 수 있다.

 

애니메이션 클립을 글로벌 타임라인에 매핑하려면 다음과 같은 클립의 정보를 알고 있어야 한다.

ㄴ 글로벌 시작 시간

ㄴ 재생 비율 R 

ㄴ 총 재생 시간 T

ㄴ 반복 재생해야 할 횟수 N

11.4.3 로컬 클록과 글로벌 클록 비교

애니메이션 시스템은 현재 재생중인 모든 애니메이션의 시간 인덱스를 관리하고 있어야 한다.

여기에는 두 가지 방법이 있다.

 

로컬 클록

ㄴ 각 클립은 고유한 로컬 클록을 갖고 있다. (초 단위, 프레임 단위, 또는 정규화된 시간 단위)

 

글로벌 클록

ㄴ 캐릭터는 대개 초로 측정되는 글로벌 클록을 갖고, 각 클립은 재생을 시작한 시점의 글로벌 시각을 저장하기만 하면 된다. 클립의 로컬 클록을 이 정보들을 이용하여 계산한다.

 

글로벌 클록 방식을 사용하면 한 캐릭터를 동기화하는 것뿐만 아니라 여러 캐릭터의 동기도 쉽게 맞출 수 있다.

예를 들어 캐릭터가 주먹으로 때리는 애니메이션과 NPC의 맞는 애니메이션을 동기화 하는 경우 로컬 클록의 방식에서는 두 애니메이션 사이에 프레임 지연이 발생할 가능성이 있다.

11.4.4 간단한 애니메이션 데이터 형식

struct AnimationSample
{
    JointPose* m_aJointPose; // 애니메이션의 샘플 한 개는 뼈대 내 각 관절들의 모든 포즈로 이루어진다.
};

struct AnimationClip
{
    Skeleton* m_pSkeleton; // 뼈대 자료구조
    F32 m_framesPerSecond; // 초당 프레임 수
    U32 m_frameCount; // T(총 재생 시간, 전체 샘플 수)
    AnimationSample* m_aSamples; // 샘플의 배열
    bool m_isLooping; // 루프 클립인지 아닌지
}

실제 게임 엔진에서는 애니메이션을 이러한 형식 그대로 저장하지는 않는다. 보통은 저장 공간을 줄이려고 여러 방식으로 애니메이션 데이터를 압축한다.

 

11.4.4.1 애니메이션 리타겟팅

애니메이션은 한 가지 뼈대에만 적합하지만, 비슷한 구조로 이루어진 뼈대들의 경우에는 예외다. 예를 들어 기본 계층구조에 영향을 미치지 않는 부가적인 말단 관절만 다르고 전체 뼈대의 구조는 동일한 경우에는 애니메이션을 공유할 수 있다.

이렇게 하려면 현재 애니메이션 되는 뼈대에는 없는 관절인데 이것의 채널 데이터가 있다면 그냥 무시하도록 엔진을 만들어야 한다.

 

11.4.5 연속 채널 함수

애니메이션 클립의 샘플은 시간에 대한 연속함수로 정의할 수 있다.

대다수 게임 엔진은 샘플을 선형적으로 보간하는데, 이 경우 사용되는 함수는 원래의 연속함수를 구분적 선형근사(piece-wise linear approximation)한 것이다.

 

11.4.6 메타 채널

많은 게임에서는 애니메이션에 필요한 부가적인 데이터를 사용할 수 있도록 메타 채널을 허용한다.

메타 채널에는 뼈대의 포즈를 잡는 일에는 직접 영향을 미치지는 않지만 애니메이션과 동기화해야 하는 게임에 특화된 정보를 담을 수 있다.

흔히 다양한 시간 인덱스(샘플)에서의 이벤트 트리거를 저장하는 특별한 채널을 정의한다.

애니메이션의 로컬 시간 값이 트리거를 지날 때 마다 이벤트를 게임 엔진으로 보내 필요한 처리를 할 수 있도록 한다.

예를 들어 애니메이션 특정 시점에서의 소리나 파티클 효과를 재생하는데 사용한다.

 

11.5 스키닝과 행렬 팔레트 생성

스키닝 : 3D 메시의 정점들을 포즈를 잡은 뼈대에 연결 하는 과정

 

11.5.1 정점별 스키닝 정보

skinned mesh는 정점에 의하여 뼈대에 연결된다. 각 정점은 관절 한 개이상의 관절에 묶일 수 있다.

관절 한 개에만 묶인 정점은 관절의 움직임과 똑같이 움직인다. (붙어있다.)

두 개 이상의 관절에 묶인 정점은  각 관절을 따라 따로 움직인 경우의 위치를 구한 후, 각 위치를 가중치에 따라 가중 평균하여 최종 위치를 결정한다.

 

3D 아티스트가 메시의 각 정점에 다음과 같은 정보를 지정해야 한다.

ㄴ 정점이 묶일 관절의 인덱스

ㄴ 정점과 묶인 관절들의 가중치

 

보통 하나의 정점에 묶일 수 있는 관절의 수는 4개를 최대로 잡는다. 관절 인덱스 표현을 8비트씩 4개로 32비트 워드 하나에 들어가도록 하면 좋기 때문에

 

가중치 4개의 합은 1이기 때문에 정점에는 3개의 가중치만 저장한다.

 

11.5.2 스키닝 수학

메시의 정점을 바인드 포즈에 맞는 위치에서 현재 뼈대의 포즈에 맞는 위치로 변환해 줄 행렬이 필요한데 이를 스키닝 행렬이라고 부른다.

 

스킨드 메시의 정점도 모델 공간에서 정의된다.

 

모든 관절마다 스키닝 행렬을 계산해야 한다. (= 스키닝 행렬의 배열 = 행렬 팔레트)

 

애니메이션 엔진이 각 관절의 스키닝 행렬을 계산하는 순서

1. 각 관절의 로컬 포즈를 계산

2. 로컬 포즈를 글로벌 포즈로 바꾸기

3. 캐시된 관절의 바인드 포즈의 역행렬과 곱하기

 

11.5.2.3 모델-월드 변환 통합

모든 정점은 언젠가는 모델 공간에서 월드 공간으로 변환되어야 한다. 따라서 어떤 게임 엔진은 스키닝 행렬 팔레트에 물체의 모델 월드 변환을 먼저 곱해 놓는다.

 

한 애니메이션을 동시에 여러 캐릭터에 적용해야 한다면 모델-월드 변환을 통합하면 안된다.

 

11.5.2.4 다관절에 묶인 정점의 스키닝

정점에 스키닝 행렬을 곱하고 가중치를 곱한 값들의 합을 새로운 정점으로 사용한다.

 

11.6 애니메이션 블렌딩

특정한 시각에서 두 개 이상의 포즈를 합쳐 같은 시각에서의 출력(하나의 포즈)을 만든다.

짧은 시간에 걸쳐 소스 애니메이션에서 목적 애니메이션으로 부드럽게 전환하는데 일시적으로 블렌딩을 사용할 수 있다.

11.6.1 LERP 블렌딩

LERP 연산을 SQT의 각 성분에 개별적으로 적용한다.

 

T는 벡터 LERP

Q는 사원수 LERP나 SLERP

S는 벡터 LERP

 

두 뼈대 포즈를 선형 보간할 때 가장 자연스로운 중간 포즈는 관절의 부모 공간(로컬 공간)에서 각 관절 포즈를 독립적으로 보간할 때 나온다. 포즈 블렌딩은 로컬 공간에서 하기 때문에 각 관절 포즈의 선형 보간은 뼈대의 다른 관절들에 완전히 독립적이다. 즉 포즈를 선형 보간하는 일은 멀티프로세서 구조에서 완전히 병렬로 수행할 수 있다는 뜻이다.

 

11.6.2 LERP 블렌딩 적용

11.6.2.1 시간 블렌딩

샘플된 포즈들 사이의 중간 포즈를 구할 때 사용한다.

t = 2, t = 3에서의 샘플된 포즈만 알고 있을 때, 만약 t= 2.18에서의 샘플을 얻고 싶다면 t = 2와 t = 3 에서의 포즈를 가중치 비율 0.18로 보간하면 된다.

 

11.6.2.2 움직임 연속성, 크로스 페이딩

클립 전환 중에도 캐릭터 신체 각 부분이 완벽하게 부드럽게 움직이도록 하는 것이 목표이다. (정점들의 위치가 연속적으로 바뀌어야 한다. = C0 연속성)

1차 도함수 또한 연속적이어야 한다.(C1 연속성)

 

LERP 기반 애니메이션 블렌딩을 사용할 경우 보기 좋은 C0 연속성을 구현할 수 있고 C1 연속성에 근접한 효과를 낼 수도 있다.

 

클립 사이의 전환에 LERP 블렌딩을 활용하는 것을 크로스 페이딩이라고 부르기도 한다.

 

크로스 페이딩의 종류

부드러운 전환

ㄴ 동기화가 잘 되어 있어야 한다.

ㄴ 블렌딩 계수를 0부터 1까지 증가시키며 두 클립을 동시에 재생한다.

 

동결 전환

ㄴ 이전 클립의 로컬 클록은 이후 클립이 재생을 시작하는 순간 멈춘다.

ㄴ 두 클립이 별로 연관성이 없고 시간을 동기화할 수 없는 경우에도 잘 동작한다.

 

블렌딩 계수를 일차원 베지어와 같은 시간의 3차 함수로 만들면 더 부드럽게 전환하게 만들 수도 있다.

 

11.6.2.3 방향 이동

타겟 이동 (targeted movement)

ㄴ 애니메이터가 전진 이동, 왼쪽 스트레이핑, 오른쪽 스트레이핑 세 종류의 루핑 애니메이션을 만들어야 한다.

ㄴ 이동 방향에 따라 인접한 클립을 섞는다. (전진, 왼쪽)을 섞거나 (전진, 오른쪽)을 섞는다. 이동 방향의 각도가 두 인접한 클립에 얼마나 가까운지에 따라 블랜드 비율을 정한다.

 

선회축 이동 (pivotal movement)

ㄴ 캐릭터의 수직축을 기준으로 캐릭터를 회전하면서 그냥 앞으로 이동하는 루프 애니메이션을 재생

11.6.3 복합 LERP 블렌딩

11.6.3.1 일반적인 1차원 LERP 블렌딩

1차원 범위 안에 다수의 애니메이션 클립과 블렌딩 계수를 새로 정의하여 블렌딩 계수와 인접한 두 클립을 블렌딩한다.

 

11.6.3.2 단순한 2차원 LERP 블렌딩

2차원 범위 에서 인접한 4개의 클립을 블렌딩한다.

 

11.6.3.3 삼각형 2차원 LERP 블렌딩

2차원 블렌딩 벡터 b가 주어지면 2차원 블렌딩 공간에서 세 클립으로 형성되는 삼각형의 무게중심 좌표를 계산함으로써 

3개의 블렌딩 가중치 값을 구할 수 있다. 3개의 클립을 블렌딩한다.

 

11.6.3.4 일반적인 2차원 LERP 블렌딩

2차원 블렌딩 공간에 임의로 배치도니 임의 갯수 애니메이션 클립에도 무게 중심을 구하는 방법을 확장할 수 있다.

들로네 삼각분할 기법을 이용해 임의의 점들로 이루어진 삼각형들을 구하는 방법이다.

 

11.6.4 부분-뼈대 블렌딩

사람은 신체 각 부분을 따로 움직일 수 있다. 예를 들면 걸으면서 오른손을 흔들고 왼손으로는 뭔가 가리킬 수 있다.

부분 뼈대 블렌딩 이라고 부르는 기법을 이용하면 게임에서 이와 같은 움직임을 구현할 수 있다.

 

각 관절마다 서로 다른 블렌드 비율을 쓸 수 있도록 하면 된다.

블렌드 마스크를 사용하여 특정한 관절의 블렌드 비율을 0으로 설정하여 특정 관절에 애니메이션이 적용되지 않게 할 수 있다.

 

부분-뼈대 블렌딩은 캐릭터 움직임이 부자연스러운 문제가 있다.

ㄴ 관절별 블렌드 인자가 급격하게 변하면 신체의 일부분이 나머지 부분과 따로 움직이는 것처럼 보인다.

ㄴ 사람의 신체는 절대 독립적으로 움직이지 않기 때문에 부자연스럽다.

11.6.5 가산 블렌딩

가산 블렌딩은 두 애니메이션 클립의 차이를 나타내는 차이 클립을 만든다.

한 번 차이 클립을 만들면 원래의 참조 클립 뿐만 아니라 전혀 상관없는 다른 클립들에도 더할 수 있다.

 

예를 들어 (지친 상태로 뛰는 애니메이션 - 평범하게 달리는 애니메이션)을 걷기 애니메이션에 더하면

지친상태로 걷는 애니메이션이 된다.

 

11.6.5.1 수학 공식

D = S(소스 클립) - R(참조 클립) 인데 관절 포즈는 자기 관절의 공간을 부모 관절의 공간으로 변환 하는 행렬이다.

행렬 연산에서 - 는 역행렬의 곱셈이므로 관절의 차이 포즈는

소스 포즈 행렬에 참조 포즈의 역행렬을 곱한 것이다.

 

입력 클립 S와 R의 재생시간이 같을 때만 차이 클립을 구할 수 있다.

 

11.6.5.3 가산 블렌딩의 한계

기존 애니메이션에 움직임을 더하는 방식을 쓰기 떄문에 뼈대의 관절을 과도하게 회전시키는 경향이 있다.

문제를 피하기 위한 팁

ㄴ 참조 클립의 엉덩이 관절 회전을 최소화한다.

ㄴ 참조 클립의 어깨와 팔꿈치 관절을 중립 위치에 두어 팔이 과도하게 돌아가는 것을 방지한다.

ㄴ 애니메이터는 각 코어 포즈마다 새로운 차이 클립을 만들어야 한다.

11.6.6 가산 블렌딩 활용

ㄴ 발 자세 변이

ㄴ 움직임 소음

ㄴ조준과 바라보기

ㄴ시간 축의 재해석

 

11.7 후처리

마야와 같은 애니메이션 도구를 이용해 export한 데이터를 이용한 것이 아니라 실행 시간에 생성하는 애니메이션을 절차적 애니메이션이라고 한다.

 

수작업으로 만든 애니메이션 클립에서 뼈대의 포즈를 먼저 잡고, 절차적 애니메이션으로 포즈를 수정하는 후처리 작업을 한다.

11.7.1 절차적 애니메이션

원래의 애니메이션의 포즈를 후처리하기 위해서 변화가 필요한 관절의 Q, S, T 채널을 변경시켜 최종 포즈를 결정하게 한다.

11.7.2 역운동학 (IK, inverse kinematics)

캐릭터가 물체를 집어 드는 애니메이션 클립에서 캐릭터가 물체를 잡도록 뼈대의 최종 포즈를 조정해 목표하는 물체와 일치시키고자 할 때 사용하는 기법

 

역운동학에서는 한 관절의 글로벌 포즈(end effector)가 원하는 위치로 움직일 수 있도록 다른 관절들의 로컬 포즈를 변경하는 것이 목표이다.

 

11.7.3 래그 돌

캐릭터가 죽었을 때 몸이 축 늘어진다. 이러한 상황에서는 몸이 주변 환경에 따라 물리적으로 현실감 있게 반응하여야 한다. 이런 목적으로 래그 돌을 사용한다.

 

11.8 압축 기법

한 개의 관절 포즈에 부동소수점 수 10개가 필요할 수 있다(평행이동 3개, 회전변환 4개, 스케일변환 3개)

뼈대 관절이 100개이고, 30프레임으로 샘플된 1초 길이의 클립이라면

10 * 4바이트 * 100 * 30 =  12000 바이트 

1초당 117KB의 메모리를 사용한다.

 

11.8.1 채널 생략

애니메이션 클립의 크기를 줄이는 가장 단순한 방법은 관계없는 채널을 생략하는 것이다.

 

대부분의 캐릭터는 불균등 스케일을 사용할 필요가 없기 때문에 스케일 채널을 3개에서 1개로 줄일 수 있다.

캐릭터의 뼈들은 일반적으로 늘어나지 않기 때문에 루트 관절이나 얼굴 관절, 떄로는 쇄골뼈의 관절을 제외하고는 평행이동도 생략할 수 있다. (3개 -> 0개)

사원수는 언제나 정규화되기 때문에 4개의 성분중 3개만 저장하고 마지막 성분은 실행 시에 계산할 수 있다. (4개 -> 3개)

 

전체 재생시간 동안 포즈가 변하지 않는 관절의 채널은 t=0에서만 기록하고 한 비트 값으로 남은 시간동안 변하지 않는다는 것을 표시하는 방법으로 채널을 생략할 수 있다.

 

11.8.2 양자화

각 채널의 크기를 32비트 부동소수가 아닌 16비트 정수로 바꿔 표현하는 방법

부동소수점 수 값을 정수로 바꾸는 과정을 인코딩

정수를 부동소수점 수 값으로 바꾸는 과정을 디코딩

 

11.8.3 샘플링 주기와 키 생략

애니메이션 데이터가 큰 이유

1. 각 관절에 10개의 부동소수점 수를 갖는 채널이 있어서

2. 뼈대에 관절이 많아서

3. 애니메이션 샘플링 빈도가 높아서 (30프레임)

 

1번 이유는 채널 생략으로 극복할 수 있다.

2번 이유는 고품질 캐릭터의 관절 갯수를 줄이기는 힘들기 때문에 해결하기 힘들고

3번 이유는

ㄴ 샘플링 빈도 낮추기 : 30프레임에서 15프레임으로 낮추면 애니메이션 데이터를 절반으로 줄일 수 있다.

 

ㄴ 샘플 생략하기 : 클립에서 일정 시간 동안 채널 데이터가 선형에 가까운 변화를 보인다면 이 기간 동안의 샘플은 양 끝점들을 제외하고 모두 생략할 수 있다. 샐행 시에 선형 보간을 하여 생략된 샘플들을 복원한다.

 

11.8.4 커브 기반 압축

애니메이션을 일정 시간 간격의 포즈 샘플이 아니라 각 관절의 S, Q, T 채널들의 시간에 따른 궤적을 n차원, 불균등, 비유리수 B-스플라인의 집합으로 기록하는 방법이다.

B-스플라인을 사용하면 많은 굴곡을 갖는 채널들을 몇 개의 데이터로 인코딩할 수 있다.

 

11.8.5 선택적 로딩과 스트리밍

애니메이션이 특정 레벨에서만 쓰인다면 그 레벨이 로딩될 때 같이 로드하고 레벨이 끝날 때 해제하도록 하면 메모리를 잘 관리할 수 있다.

 

11.9 애니메이션 시스템 아키텍처

대부분의 애니메이션 시스템들은 최대 세 개의 개별 레이어들로 구성된다.

 

애니메이션 파이프라인

ㄴ 게임에서 애니메이팅되는 캐릭터와 객체에 대하여 하나 이상의 애니메이션 클립들과 블렌드 적용 값을 입력으로 블렌딩하여 하나의 로컬 뼈대 포즈를 출력한다.

ㄴ 각 관절의 스키닝 행렬, 글로벌 뼈대 포즈를 계산하여 출력한다.

 

액션 상태 머신

ㄴ 게임 캐릭터의 동작들은 유한 상태 머신으로 모델링하는 것이 제일 좋은 방법이다.

ㄴ 동시에 여러 동작을 할 때, 캐릭터 몸체의 각 부위들이 독립적으로 동시에 움직일 수 있도록 해준다.

 

애니메이션 컨트롤러들

ㄴ 특정 상황에 처한 캐릭터의 행동을 관리하는 시스템

 

11.10 애니메이션 파이프라인

1. 클립 압축 해제와 포즈 추출

ㄴ 각 입력 클립에 대한 로컬 뼈대 포즈를 출력한다.

ㄴ 이 포즈가 가지는 정보는 뼈대에 있는 모든 관절에 대한 정보이거나, 관절의 일부분에 대한 정보이거나, 첨가 블렌딩에서 사용되는 차이 포즈가 될 수 있다.

 

2. 포즈 블렌딩

ㄴ 하나 이상의 애니메이션 클립을 블렌딩할 때만 실행되는 단계, 뼈대에 있는 모든 관절들에 대한 하나의 로컬 포즈를 출력한다.

 

3. 글로벌 포즈 생성

ㄴ 뼈대에 대한 계층구조를 따라서 지역 관절들을 조합하여 뼈대에 대한 글로벌 포즈를 생성한다.

 

4. 후처리

ㄴ 포즈를 마무리 하기 전에 뼈대의 로컬/글로벌 포즈를 수정한다.

ㄴ 후처리 단계에는 IK, ragdoll physics 기법을 적용할 수 있다.

 

5. 글로벌 포즈가 최종적으로 만들어지고 난 후 각 관절들의 글로벌 포즈 행렬을 그것과 일치하는 바인드 포즈 역행렬과 곱하여 렌더링 엔진 입력에 알맞는 스키닝 행렬 팔레트(배열)을 출력으로 생성한다.

 

11.10.1 자료 구조

11.10.1.1 공유 자원 데이터

모든 게임 엔진 시스템들은 공유 자원 데이터와 인스턴스별 상태 정보를 명확하게 구별해야 한다.

 

일반적으로 같은 유형의 캐릭터나 객체들은 하나의 자원 데이터를 공유하여 사용한다.

ㄴ 뼈대 - 뼈대는 관절과 관절 계층 구조를 묶어서 만든 포즈를 나타낸다.

ㄴ 스킨 메시 - 하나의 뼈대에는 여러 개의 스킨 메시들이 붙을 수 있다.

ㄴ 애니메이션 클립 - 한 캐릭터의 뼈대에 많은 애니메이션 클립이 적용될 수 있다.

 

게임에서 사용하는 고유한 뼈대들의 수를 최소한으로 줄이는 것이 도움이 된다.

 

11.10.1.2 인스턴스별 데이터

특정 캐릭터 형태에 대한 인스턴스 정보

1. 클립 상태

ㄴ 로컬 클록, 재생 비율

 

2. 블렌드 명세

ㄴ 블렌드 노드 트리 방식 : 블렌드 트리를 공유 자원으로 처리한다.

ㄴ 가중 평균 방식 : 블렌드 가중치를 인스턴스 별 상태 정보의 일부분으로 저장한다.

 

3. 부분 뼈대 관절 가중치

ㄴ 부분 뼈대를 블렌딩하게 되면 각 관절이 마지막 포즈에 미치는 영향 정도를 관절 가중치로 지정한다.

 

4. 로컬 포즈, 글로벌 포즈, 매트릭스 팔레트

 

11.10.2 균일 가중 평균 블렌딩 표현

모든 활성 애니메이션 클립(가중치가 0이 아닌 클립)들은 리스트로 관리된다.

N개의 활성 애니메이션들에서 평행 이동벡터들, 회전 사원수, 스케일 값들을 추출하여 가중평균을 계산한다. 이렇게 해서 뼈대의 마지막 포즈를 만든다.

 

11.10.3 블렌드 트리 (일반적으로 많이 씀)

애니메이션 블렌드 트리의 내부 노드들은 연산자이고 말단 노드들은 연산자에 제공되는 입력을 나타낸다.

ㄴ 11.6.3 복합 Lerp 블렌딩에서 다룬 내용들이다.

 

11.10.4 크로스-페이딩 아키텍처

크로스 페이드는 에니메이션 엔진이 균일 가중 평균을 사용하는지 또는 수식 트리 구조(블렌드 트리)를  사용하는지에 따라 두 가지로 구현될 수 있다.

 

11.10.4.1 균일 가중 평균 방식을 이용한 크로스-페이드

클립들의 가중치들을 조정하여 크로스-페이드를 구현한다.

복합 블렌드에서 다른 복합 블렌드로 전환하는 것을 크로스 페이딩으로 처리하는 것이 약간 까다롭다.

ㄴ 클립 그룹의 가중치의 합이 항상 1이도록 유지해야한다. 복합 블렌드를 전환하는 경우 가중치의 값이 0과 1 사이일 때 각 그룹의 가중치들을 더해도 1이 되지 않을 수 있기 때문에 그룹이 어떻게 묶여 있는지를 저장하는 메타 데이터가 더 필요하게 된다.

 

11.10.4.2 수식 트리를 이용한 크로스-페이드

 

복합 블렌드에서 다른 블렌드로 전환하든지 클립에서 클립으로 전환하든지 동일한 방식을 사용한다.(직관적이다.)

 

11.10.5 애니메이션 파이프라인 최적화

하드웨어에 따라 고유한 최적화 문제가 있다.

캐시 미스와 로드-적중-저장 연산을 피해야 한다.

부동소수점 연산을 피해야한다.

 

11.11 액션 상태 머신

액션 상태 머신은 애니메이션 파이프라인 위에 위치하며, 게임에서 캐릭터의 액션들을 상태 기반으로 직접 조정할 수 있도록 해준다.

11.11.1 애니메이션 상태

액션 상태 머신에서 각 상태는 동시에 처리되는 애니메이션 클립들에 대한 임의의 복합 블렌드에 해당된다. 

 

특정 애니메이션 상태에 해당하는 블렌드 트리는 단순하거나 복잡할 수 있다 예를 들어 대기 상태는 몸 전체 애니메이션 하나에 적용될 수 있고, 달리기 상태는 왼쪽 스트레이핑, 전방달리기, 오른쪽 스트레이핑을 각각 -90도 0도 90도로 섞는 반원형 블렌드에 해당된다.

11.11.2 상태 전환

 

11.11.2.1 상태 전환의 종류

소스 상태의 마지막 포즈와 목적 상태의 첫 번째 포즈가 정확하게 일치하다면, 한 상태에서 다른 상태로 바로 전환시킬 수 있다. 그렇지 않으면 크로스 - 페이드 방식으로 전환해야 한다.

크로스-페이드 방식이 부자연스러운 경우 한 상태에서 다른 상태로 변할 때만 사용할 전환 상태라는 특수한 상태를 상태 머신에 구현한다.

 

11.11.2.2 상태 전환 파라미터들

2가지 상태들 사이의 특정 전환을 표현할 때 조정할 수 있는 파라미터

ㄴ 소스와 목적지 상태들

ㄴ 전환 타입 (바로 전환인지, 크로스-페이드 인지, 전환 상태를 통해 실행 하는지)

ㄴ 기간 (크로스 페이드가 얼마 동안 일어나야 하는지)

ㄴ ease-in / ease-out 곡선 타입

 

11.11.2.3 상태 전환 행렬

n개의 상태를 가지는 상태 머신에서 가질 수 있는 전환의 개수는 최대 n의 제곱개 이다.

2차원 정방행렬을 사용하여 세로 축에 있는 상태에서 가로 축에 있는 다른 상태로 전환 가능한 모든 경우를 나타낼 수 있다.

 

11.11.3 상태 레이어들

상태 머신은 한 순간에 하나의 상태만 가질 수 있기 때문에 몸에서 

상태 계층을 사용하여 문제를 해결 할 수 있다.

n개의 각 계층에서 블렌드 트리를 계산하고 n개의 골격 포즈를 생성하고 블렌딩함으로써 뼈대의 최종 포즈를 계산한다.

11.11.4 컨트롤 파라미터들

블렌드 가중치, 재생 비율, 컨트롤 파라타미터를 조정하는 것은 쉬운 일이 아니다.

블렌드 가중치는 블렌딩에서 서로 다른 효과를 낸다. 어떤 가중치는 움직임 방향을 조정할 수 있고, 어떤 가중치는 캐릭터의 움직임 속도를 조정할 수도 있다. 따라서 상위 코드에서 블랜드 가중치들에 접근하는 방법이 있어야 한다.

 

노드 검색

ㄴ 상위 레벨의 코드에서 트리에 있는 블렌드 노드를 찾는 방법을 제공한다.

 

이름을 가진 변수

ㄴ 각 컨트롤 파라미터에 이름을 부여하고, 코드는 컨트롤 파라미터를 이름으로 찾아서 원하는 값으로 조정할 수 있다.

 

컨트롤 구조체

ㄴ 부동 소수점이나 구조체의 배열같은 간단한 자료 구조로 전체 캐릭터에 대한 컨트롤 파라미터들을 모두 저장하여 관리하고 블렌드 트리의 노드는 배열의 인덱스를 통해 찾는다.

'읽은 책 > 게임 엔진 아키텍처' 카테고리의 다른 글

14. 게임플레이 시스템의 소개  (0) 2022.08.17
12. 충돌과 강체 역학  (0) 2022.08.17
10. 렌더링 엔진  (0) 2022.08.12
9. 디버깅과 개발 도구  (0) 2022.08.10
8. 휴먼 인터페이스 장치 (HID)  (0) 2022.08.09

+ Recent posts