듀얼 쿼터니언 스키닝 — 캔디 래퍼가 사라지는 자리

듀얼 쿼터니언 스키닝 — 캔디 래퍼가 사라지는 자리
팔꿈치를 180도 비틀면 팔뚝이 종잇장처럼 납작해진다. 어깨를 돌리면 겨드랑이가 사탕 포장지처럼 배배 꼬여 부피가 사라진다. 리깅을 하다 보면 반드시 만나는 이 현상을 캔디 래퍼(candy wrapper)라고 부른다. 원인은 스킨 웨이트를 잘못 칠해서가 아니다. 원인은 행렬을 섞는 방식 그 자체에 있다.
이 글은 그 원인을 수식으로 짚고, 듀얼 쿼터니언이 어떻게 그 원인을 제거하는지 단계별로 따라간다.
먼저, 기존 방식이 왜 무너지는가
표준적인 스키닝은 선형 블렌드 스키닝(Linear Blend Skinning, LBS)이다. 정점 하나의 최종 위치는 이렇게 계산된다.
기호를 하나씩 풀면 이렇다. 는 바인드 포즈에서의 정점 위치, 는 변형 후 위치다. 는 번째 본이 만드는 4×4 변환 행렬이고, 는 그 본이 이 정점에 미치는 영향력, 즉 스킨 웨이트다. 웨이트는 정규화되어 있어서 이고 이다. 은 이 정점에 물린 본의 개수다.
수식을 보면 괄호 안이 먼저 계산된다. 즉 행렬들을 성분별로 가중 평균한 뒤, 그 결과를 정점에 곱한다. 여기가 문제의 발원지다.
구체적으로 보자. 본 두 개가 각각 로 물려 있고, 하나는 회전이 없는 항등 행렬 , 다른 하나는 z축 기준 180도 회전 이라고 하자. 회전 부분만 떼어 2×2로 축약하면
이 둘을 성분별로 평균하면
영행렬이다. 이 행렬을 정점에 곱하면 모든 정점이 원점 한 점으로 빨려 들어간다. 부피가 완전히 사라진다. 이것이 캔디 래퍼의 극단적 형태이고, 90도나 120도처럼 덜 극단적인 각도에서도 같은 일이 정도만 약하게 일어난다. 예를 들어 90도라면
이 행렬의 행렬식은 다. 회전 행렬이라면 행렬식이 1이어야 하는데 0.5로 줄었다. 넓이가 절반으로 쪼그라들었다는 뜻이다.
핵심은 이것이다. 회전 행렬들의 집합은 덧셈에 대해 닫혀 있지 않다. 회전 두 개를 더하면 회전이 아닌 무언가가 나온다. LBS는 이 닫히지 않은 연산을 매 프레임 수행하고 있다. 웨이트를 아무리 정교하게 칠해도 이 대수적 사실은 바뀌지 않는다.
해법의 방향: 더하지 말고, 궤도 위에서 섞기
문제가 "회전을 직선으로 섞어서"라면, 해법은 "회전을 회전답게 섞기"다. 두 값 사이를 채우는 선형 보간(lerp)은 직선 위를 지나가는데, 회전은 직선 위가 아니라 구면 위에 살기 때문이다.
회전만 놓고 보면 이 문제는 이미 풀려 있다. 쿼터니언과 구면 선형 보간(slerp)이 그것이다. 단위 쿼터니언 는
여기서 는 실수부, 는 허수부 계수이고 는 을 만족하는 허수 단위다. 노름이 항상 1이라는 조건 때문에 단위 쿼터니언은 4차원 공간의 구면 위에 놓인다. 섞은 뒤 다시 노름 1로 정규화하면 언제나 온전한 회전으로 되돌아온다.
그런데 스키닝은 회전만으로 끝나지 않는다. 본은 회전하는 동시에 이동한다. 쿼터니언은 회전은 다루지만 이동(translation)은 담지 못한다. 회전은 slerp로 섞고 이동은 따로 lerp로 섞는 임시방편도 있지만, 그러면 회전 중심이 어긋나면서 관절이 미끄러진다.
회전과 이동을 하나의 대수 안에서 함께 다루는 것 — 이것이 듀얼 쿼터니언이 존재하는 이유다.
듀얼 수: 이라는 이상한 약속
듀얼 쿼터니언을 이해하려면 먼저 듀얼 수를 봐야 한다. 듀얼 수는 이렇게 생겼다.
는 실수고, 은 듀얼 단위다. 복소수의 가 을 만족하듯, 은 다음을 만족한다.
0이 아닌데 제곱하면 0이 되는 수. 실수 체계에서는 있을 수 없지만, 대수 구조로는 완벽하게 정의된다. 그리고 이 성질이 놀랄 만큼 유용하다. 듀얼 수 두 개를 곱해 보자.
마지막 항의 이 0이므로 통째로 사라진다. 남는 것은
즉 이 붙은 부분은 절대 실수부로 스며들지 않는다. 두 정보가 서로 오염되지 않고 한 객체 안에 공존한다. 회전을 실수부에, 이동을 듀얼부에 담을 수 있는 근거가 여기 있다.
듀얼 쿼터니언의 정의
이제 듀얼 수의 계수 자리에 실수 대신 쿼터니언을 넣는다. 그것이 듀얼 쿼터니언이다.
와 는 각각 보통의 쿼터니언이고, 은 여전히 을 만족하며 대수의 모든 원소와 교환된다(즉 ). 쿼터니언 하나가 4차원이니 듀얼 쿼터니언은 8차원 실수 대수다. 형식적으로는 쿼터니언 대수 와 듀얼 수 대수 의 텐서곱과 동형이다.
여기서 유의할 점 하나. 쿼터니언은 0이 아닌 모든 원소가 역원을 갖는 나눗셈 대수지만, 듀얼 쿼터니언은 나눗셈 대수가 아니다. 인데 이라는 것은 곧 영인자(zero divisor)가 존재한다는 뜻이고, 영인자가 있으면 나눗셈 대수가 될 수 없다. 은 역원이 없다. 다행히 스키닝에서 쓰는 것은 단위 듀얼 쿼터니언이라는 특별한 부분집합이고, 그 안에서는 역원이 잘 정의된다.
강체 변환을 담는 방법
본 하나의 움직임은 회전 + 이동, 즉 강체 변환이다. 이것을 듀얼 쿼터니언으로 옮기는 규칙은 다음과 같다.
기호를 풀면 은 본의 회전을 나타내는 단위 쿼터니언이고, 는 이동 벡터 를 실수부가 0인 순허수 쿼터니언 로 올린 것이다. 이 붙는 이유는 쿼터니언 회전이 처럼 양쪽에서 두 번 작용하기 때문이다. 이동도 같은 샌드위치 구조를 따르게 하려면 절반으로 넣어야 한다.
이렇게 만든 는 단위 듀얼 쿼터니언 조건을 만족한다.
앞 조건은 실수부가 온전한 회전이라는 뜻이고, 뒤 조건은 실수부와 듀얼부가 4차원 내적으로 직교한다는 뜻이다. 이 두 조건을 지키는 8차원 벡터들만이 강체 변환에 대응한다.
섞는 순간: DLB
이제 본론이다. 여러 본을 섞을 때 듀얼 쿼터니언 선형 블렌딩(Dual quaternion Linear Blending, DLB)은 이렇게 한다.
겉보기에는 LBS와 똑같이 "가중합"이다. 결정적 차이는 분모의 정규화다. 8차원 벡터들을 더하면 단위 조건을 벗어나 구면 안쪽으로 들어가지만, 노름으로 나누는 순간 다시 구면 위로 튕겨 올라온다. 구면 위로 되돌아온 값은 언제나 유효한 강체 변환이다. 회전이 뭉개지지 않고, 부피가 손실되지 않는다.
LBS와 나란히 놓으면 차이가 선명하다.
정규화 한 번이 만드는 차이다. 그리고 이 정규화가 가능한 이유가 바로 앞에서 본 대수 구조 — 회전과 이동이 하나의 노름을 공유하는 8차원 객체로 묶여 있기 때문이다. 회전은 slerp, 이동은 lerp로 따로 처리했다면 이런 통합된 정규화는 불가능하다.
계산 비용 면에서도 나쁘지 않다. 4×4 행렬은 16개 실수를 다루지만 듀얼 쿼터니언은 8개다. GPU 스키닝에서 유니폼 대역폭이 절반으로 줄어든다.
알면 좋아지는 점
이 구조를 알고 나면 리깅 작업의 감이 달라진다.
첫째, 웨이트를 탓하지 않게 된다. 팔뚝이 꼬일 때 며칠씩 웨이트를 다시 칠하는 대신, "이건 블렌딩 방식의 문제"라고 즉시 판정할 수 있다. 원인이 대수에 있으면 페인팅으로는 못 고친다.
둘째, DQS가 만드는 특유의 부풀음(bulging)을 예상할 수 있다. 구면 위에서 섞는다는 것은 최단 호를 따라간다는 뜻이고, 그래서 관절 안쪽이 볼록하게 부푼다. 이게 버그가 아니라 방식의 필연이라는 걸 알면, 트위스트 본을 추가하거나 보정 블렌드 셰이프를 붙이는 쪽으로 바로 넘어갈 수 있다.
셋째, 어디에 트위스트 본을 넣어야 하는지 계산할 수 있다. 캔디 래퍼는 두 본의 회전 차이가 커질수록 심해진다. 손목처럼 180도 가까이 비틀리는 곳에 중간 본을 하나 끼우면 각 구간의 회전 차가 절반으로 줄고, 문제도 그만큼 줄어든다. 감이 아니라 각도 차이라는 명확한 기준으로 판단하게 된다.
모르면 겪는 문제
반대로 이 구조를 모르면 반복해서 벽에 부딪힌다.
웨이트 페인팅으로 해결하려다 시간을 쏟는다. 앞서 봤듯 두 회전 차가 180도면 어떤 웨이트 조합으로도 붕괴를 막을 수 없다. 으로 바꿔도 결과 행렬의 행렬식은 여전히 1보다 작다. 조금 덜 무너질 뿐이다.
또 DQS로 전환했는데 관절이 부풀어 오르면 "설정을 잘못했다"고 판단해 다시 LBS로 돌아가기 쉽다. 부풀음은 구면 보간의 성질이지 설정 오류가 아니다. 원인을 모르면 두 방식 사이를 오가며 시간만 흘려보낸다.
영인자 문제도 있다. 듀얼 쿼터니언 두 개를 섞기 전에 부호를 맞추지 않으면(즉 일 때 한쪽 부호를 뒤집지 않으면) 먼 길로 돌아가는 보간이 나와 캐릭터가 순간적으로 뒤집힌다. 이건 방식의 결함이 아니라 구현에서 반드시 처리해야 하는 단계인데, 대수를 모르면 원인 불명의 팝핑으로만 보인다.
정리
정리하면 이렇다. LBS는 회전 행렬을 성분별로 더하는데, 회전은 덧셈에 대해 닫혀 있지 않아서 결과가 회전이 아닌 무언가가 된다. 그것이 캔디 래퍼다.
듀얼 쿼터니언은 이라는 성질로 회전과 이동을 서로 오염시키지 않고 8차원 객체 하나에 담는다. 이 객체는 단일한 노름을 갖기 때문에, 가중합 후 정규화 한 번으로 항상 유효한 강체 변환의 집합 위로 되돌아온다.
다시 강조하면, 핵심은 대단한 알고리즘이 아니라 올바른 공간에서 섞는 것이다. 직선 위에서 섞으면 무너지고, 구면 위에서 섞으면 유지된다. 도구를 바꾼 게 아니라 무대를 바꾼 것이다.
함께 읽기 — 이 글이 쓰는 기초 수학
출처
리깅 파이프라인 자동화 도구
반복 작업은 스크립트에게. 현업에서 쓰는 리깅 툴 모음.
리깅 도구 보기