스켈레톤이 아니라 표면을 맞춰라
Cinevva CTO 겸 공동 창업자 Oleg Sidorkin
1부에서는 CC0 동물 12종을 대상으로 자동 리거 네 가지를 아티스트 리그와 비교했고, 모두에게 공통된 결함 하나를 발견했다. 어느 리거든 사족보행 동물의 다리를 거의 곧게 만든다는 점이다. 접힌 부분이 없는 다리는 리타기팅이 아무리 뛰어나도 아티스트가 만든 무릎 각도를 재현할 수 없기 때문에, 글은 리그를 보정하겠다는 계획으로 끝났다.
그런데 결과를 놓고 논의하던 중 더 단순한 질문이 떠올랐다. 애초에 왜 스켈레톤 사이에서 애니메이션을 옮기고 있는가?
스켈레톤은 표면을 변형하기 위한 기계다. 플레이어가 실제로 보는 것은 표면이며, 아티스트 클립에는 매 프레임마다 그 표면이 어디에 있어야 하는지 버텍스 단위로 정확히 담겨 있다. 그렇다면 스켈레톤 간 매핑을 완전히 건너뛰면 된다. 아티스트 클립을 한 번 재생해 변형된 메시를 기록한 다음, 자동 리깅된 스켈레톤 자체의 스키닝이 그 표면을 최대한 가깝게 재현하도록 트랜스폼을 푼다. 그러면 새 리그의 공간에 네이티브로 존재하는 클립이 만들어진다. 본 이름이 bone_0이든 무엇이든 상관없다.

문헌상 새로운 아이디어는 아니다. 이는 스키닝 분해 중 트랜스폼에 해당하는 절반이며, 2012년 Le와 Deng이 제시한 SSDR이기도 하고, 모션 캡처 솔버가 임의의 리그를 조밀한 마커에 맞추는 방식이기도 하다. 우리 상황은 쉬운 경우다. 리거가 이미 스켈레톤과 웨이트를 제공했으므로, 미지수는 프레임별 본 트랜스폼뿐이다.
방법, 그리고 결과의 신뢰성을 지키는 대조군
각 프레임에서 리그의 스키닝된 표면과 목표 표면 사이의 거리를 최소화하는 본별 트랜스폼을 찾는다. 웨이트가 고정되어 있으면 각 본의 최적 트랜스폼에는 닫힌 형식의 해가 존재한다. 바로 Horn의 쿼터니언 방법을 이용한 가중 강체 피팅이다. 선형 블렌드 스키닝에서는 공유 버텍스를 통해 본들이 서로 결합되므로, 잔차가 더 이상 변하지 않을 때까지 각 본을 차례로 훑으며 솔브한다. 이때 각 솔브는 다른 모든 본이 현재 기여하는 값을 반영한다. 각 프레임은 이전 프레임의 결과를 초기값으로 사용한다.
모든 계산은 바인드 공간에서 실행한다. 파일이 어떤 규약으로 내보내졌든 이 공간에서는 스키닝 항등식이 정확히 성립한다. 아티스트 메시와 리거가 다시 용접하거나 세분화한 메시 사이의 대응 관계는 정렬된 레스트 포즈에서의 최근접 이웃으로 구한다. 둘 다 같은 동물이므로 여기서는 정확하다.
가장 중요했던 설계 원칙은 반드시 0이 나와야 하는 대조군 실행이었다. 완벽한 답이 구조적으로 존재하는 조건, 즉 아티스트 리그를 자체 클립에 맞춰 솔브한다. 솔버가 그 답을 찾지 못한다면 다른 어떤 결과도 의미가 없다. 대조군은 모델 대각선 길이의 0.008%에 도달했고, 단일 최악 버텍스조차 0.08%였다. 이후의 모든 측정은 이 바닥값을 기준으로 한다.
신뢰할 수 있는 0에 도달하기까지 세 번의 시도가 필요했다
첫 대조군 실행은 3%에서 멈췄고, 반복 횟수를 30배 늘려도 움직이지 않았다. 각 원인은 겉으로는 보이지 않았으므로 기록해 둘 가치가 있다.
가장 큰 원인은 API 함정이었다. 최신 three.js에서는 boneTransform의 이름을 applyBoneTransform으로 바꾸면서 동작도 조용히 변경했다. 새 함수는 전달받은 벡터에서 입력 위치를 가져오며 지오메트리는 전혀 읽지 않는다. 재사용되는 임시 벡터를 넘기면 각 버텍스를 이전 버텍스의 출력으로부터 계산하게 된다. 그 결과 부드럽고 그럴듯해 보이는 쓰레기 목표값이 생성됐다. 민망하게도 한 시간 동안 우리는 이 수치에 너무나 아름답게 들어맞지만 완전한 허구였던 아마추어 스케일 이론을 정교하게 세웠다. 올바른 진입점은 getVertexPosition이다. 대조군이 이 문제를 잡아냈고, 그것이 바로 대조군이 필요한 이유다.
나머지 두 가지 문제는 더 작았다. Horn 행렬에서의 거듭제곱 반복은 약 1,000분의 1도에서 정체된다. 수렴을 가능하게 하는 스펙트럼 시프트가 동시에 수렴 방향의 간격도 짓누르기 때문이다. 그래서 4x4 행렬에서 정확한 야코비 회전으로 전환했다. 또 상대적 진척도를 기준으로 한 초기 종료 테스트가 스윕이 여전히 오차를 줄이고 있는데도 멈춰 버렸기 때문에, 이제 종료 조건은 모델 스케일에 대한 절대적 진척도를 측정한다.
각 리거가 실제로 담아낼 수 있는 것
솔버를 검증한 뒤, 모든 리거가 지원하는 동물 여섯 종에 대해 Walk와 Gallop이라는 두 아티스트 클립을 각 리그에 맞춰 솔브했다. 점수는 리그가 재현한 모션 표면 변위의 비율이다. 이제 우리는 이 수치를 전송 품질이라고 부른다.

| 리그 | Walk | Gallop |
|---|---|---|
| 아티스트(대조군) | 99.8% | 99.9% |
| Anything World | 94.4% | 91.9% |
| Tripo | 92.3% | 89.1% |
| SkinTokens, 아티스트 스켈레톤 제공 | 82.5% | 89.4% |
| SkinTokens | 80.9% | 88.0% |
| RigNet | 48.5% | 58.3% |
이제 이 결과를 1부와 비교해 보자. 순위가 뒤집힌다.
RigNet은 네 리거 중 다리 굽힘이 가장 좋았고, 동물 12종 모두에서 스켈레톤이 우리의 구동 가능성 기준을 통과한 유일한 리거였다. 하지만 여기서는 보행 모션의 절반을 잃는다. 최악의 버텍스는 표면이 있어야 할 위치에서 모델 크기의 20~31%만큼 벗어나며, 이 실패는 동물 여섯 종 모두에서 일관되게 나타난다. 모든 동물의 품질이 38~59%에 불과하다. 반면 우리가 측정한 리그 중 다리가 가장 곧았던 Tripo와 Anything World가 애니메이션을 가장 잘 담아낸다.
설명하고 나면 양립하는 이유는 간단하다. 솔브된 클립은 관절을 회전시킬 뿐 아니라 이동시킬 수도 있으며, 관절별 이동 트랙은 평범하고 유효한 애니메이션 데이터다. 이동을 사용할 수 있으면 곧은 체인도 접히는 표면을 추적할 수 있으므로, 굽힘은 더 이상 지배적인 제약이 아니다. 대신 메시를 얼마나 깔끔하게 본을 따라가는 조각들로 나누는지가 스키닝 웨이트에 의해 결정된다. 상용 리거의 웨이트는 좋다. 불규칙한 체인 전체에 퍼진 RigNet의 웨이트는 솔버가 본을 어디로 옮기든 표면을 추적하지 못한다.
따라서 두 측정은 서로 다른 질문에 답한다. 굽힘 비율은 회전 기반 런타임 리그가 어떤 포즈를 만들 수 있는지를 좌우하며, 이것이 1부의 영역이다. 전송 품질은 베이크된 솔브 클립이 무엇을 표현할 수 있는지를 좌우하며, 이것이 이번 글의 영역이다. 솔브 클립 파이프라인에서는 우리가 이미 제공 중인 리거가 꼴찌가 아니라 92% 리그다.
표 안에 숨어 있는 결과가 하나 더 있다. SkinTokens에 아티스트의 스켈레톤을 그대로 제공해도 점수는 거의 변하지 않는다. 한계를 정하는 것은 관절 배치가 아니라 웨이트다.
수치를 믿는 대신 직접 보기
수치가 먼저고, 그다음은 눈으로 확인할 차례다. 같은 솔버가 실시간 뷰어도 구동한다. 여기서는 각 리그의 전체 메시가 솔브된 트랜스폼으로 스키닝되고, 아티스트의 정답 표면을 어두운 실루엣으로 겹쳐 표시하며, 모든 버텍스를 순간 오차에 따라 색칠한다. 파란색은 0이다. 빨간색은 모델 대각선 길이의 3% 이상이다.
뷰어가 지표를 측정한 바로 그 함수로 렌더링하므로, 영상과 표의 결과가 서로 어긋날 수 없다. 다만 한 패널에는 설명이 필요하다. SkinTokens 사슴에는 히트맵이 표시되지 않는다. 메시가 181,000개 버텍스로 이루어져 있고, 60,000개를 넘으면 전체 메시 대응 관계 계산을 건너뛰기 때문에 이 패널은 실루엣만으로 결과를 보여준다.
이것이 우리에게 바꾸는 것
클립 하나를 리그 하나에 맞춰 솔브하는 데는 GPU 없이 브라우저 JavaScript에서 0.5초에서 몇 초가 걸린다. 리그가 생성되는 순간 사족보행 동물의 전체 클립 세트를 베이크하기에 충분히 저렴하다. 베이크된 클립은 런타임도 더 단순하게 만든다. 동물에는 스켈레톤 리타기팅이 전혀 필요 없고, 리그 고유 공간에서 클립을 재생한 뒤 지면 접촉을 위해 기존 풋 로킹을 덧붙이면 된다.
두 번째 승인 기준도 생긴다. 1부의 기하학적 검사는 리그를 구동할 수 있는지 알려준다. 전송 품질은 실제 애니메이션을 얼마나 보존하는지 알려준다. 어떤 리거는 첫 번째 기준을 통과하면서 두 번째 기준에는 실패할 수 있으며, RigNet이 정확히 그렇다.
한계를 솔직하게 말하면
점수는 각 리그의 상한선이지 보장이 아니다. 솔버는 관절을 이동시킬 수 있으므로 모션 도중 본 길이가 보존되지 않으며, 이동에 크게 의존하는 리그는 극단적인 자세에서 고무처럼 보일 수 있다. 좋은 리그에서도 순간적으로 9~20%에 이르는 Gallop의 최악 버텍스는 바로 그런 순간에 나타난다. 회전만 사용하는 솔브 변형이라면 그 비용을 정직하게 측정할 수 있다. 이것은 아직 우리가 내놓아야 할 수치다. 이동을 사용할 수 없을 때 1부에서 확인한 곧은 다리의 불이익이 얼마나 남는지 보여줄 것이다.
프로덕션 단계와의 격차는 대응 관계다. 이 벤치마크에서는 리거가 아티스트가 애니메이션한 것과 동일한 메시를 리깅했으므로 버텍스 매칭이 간단하다. 사용자가 업로드한 동물은 다른 메시이며, 먼저 아티스트의 표면 모션을 그 메시로 옮기는 일 자체가 별개의 문제다. 알려진 방법들은 있지만 아직 측정하지 않았다.
그리고 표본의 한계도 있다. 동물 여섯 종, 클립 두 개, 클립당 24프레임이며, 가장 조밀한 메시는 제약 조건을 5,000개 버텍스로 서브샘플링했다. 리거의 순위를 자신 있게 매기기에는 충분하지만 소수점 둘째 자리까지 인용하기에는 부족하다.
동물은 Quaternius의 CC0 애셋이고, 방법은 40년 된 닫힌 형식 피팅에 인내심을 더한 것이며, 이 실험을 재현하려는 누구에게든 가장 먼저 만들라고 권하고 싶은 부분은 대조군 실행이다. 이전에 애니메이션을 리그에 맞춰 솔브하면서 우리와 같거나 다른 함정을 겪었다면, Discord에서 경험을 비교해 보고 싶다.