Artoke

리깅: 동차 좌표 — 본의 로컬 공간과 월드 공간 계산

리깅: 동차 좌표 — 본의 로컬 공간과 월드 공간 계산 대표 이미지
출처: 동차 좌표 — 본의 로컬 공간과 월드 공간 계산

3D 툴에서 본(bone)을 하나 옮기면 그 아래 달린 자식 본들이 전부 따라 움직인다. 이 당연해 보이는 동작의 밑바닥에는 한 가지 계산이 있다. 각 본이 자기 부모의 좌표계 안에서만 자기 위치를 기억하고, 최종적으로 월드 좌표를 구할 때 부모의 변환을 차례로 곱해 올라가는 것이다. 그리고 그 "곱해 올라가는" 일을 깔끔하게 만들어 주는 것이 동차 좌표(homogeneous coordinates)다.

동차 좌표는 1827년 뫼비우스(August Ferdinand Möbius)가 Der barycentrische Calcul에서 도입한 사영기하학의 좌표계다. 유클리드 기하가 데카르트 좌표를 쓰는 것처럼, 사영기하는 동차 좌표를 쓴다. 이 좌표계의 장점은 무한원점까지 유한한 숫자로 표현할 수 있다는 것, 그리고 아핀 변환과 사영 변환을 전부 하나의 행렬 곱으로 통일할 수 있다는 것이다. 리깅에서 우리가 실제로 쓰는 건 후자다.

왜 3개 숫자로는 부족한가

점의 위치를 벡터 로 적고, 회전·스케일 같은 변환을 행렬 로 적으면, 변환된 점은 로 구해진다. 회전은 이 방식으로 잘 표현된다. 예를 들어 축 기준 회전은

여기서 는 회전각, 행렬의 각 열은 회전 후의 축이 어디로 가는지를 알려준다. 스케일도 마찬가지로 대각행렬 로 표현된다.

그런데 이동(translation)은 이 틀에 들어가지 않는다. 이동은 인데, 어떤 행렬 을 골라도 이다. 원점은 항상 원점으로 간다. 행렬 곱은 선형(linear)이라 원점을 옮길 수 없기 때문이다. 이동은 선형 변환이 아니라 아핀(affine) 변환이다.

이게 왜 문제냐면, 본 체인은 "회전하고, 옮기고, 또 회전하고, 또 옮기고"의 반복이기 때문이다. 이걸 행렬과 벡터 덧셈을 섞어서 쓰면

같은 중첩된 식이 나온다. 본이 20개 달린 손가락 체인이면 이 식은 20겹으로 쌓인다. 미리 합쳐서 하나로 만들어 둘 수도 없고, 역변환을 구하기도 지저분하다.

차원을 하나 올려서 이동을 선형으로 만들기

해법은 이상하리만치 단순하다. 좌표에 숫자를 하나 더 붙인다. 점 로 적고, 로 둔다. 그러면 행렬은 가 되고, 이동을 이렇게 쓸 수 있다.

기호를 풀면, 는 각 축 방향으로 얼마나 옮길지를 나타내는 이동량이다. 곱셈을 손으로 전개해 보면 첫 행은 가 된다. 마지막 성분의 를 "끌어와서" 더해주는 역할을 하는 것이다. 덧셈이 곱셈 안으로 숨어 들어갔다.

이제 회전·스케일·이동이 전부 같은 모양의 행렬이 된다. 일반형은

여기서 블록으로 회전과 스케일(그리고 셰어)을 담고, 오른쪽 열은 이동을, 맨 아래 행 은 이 변환이 아핀 변환임을 표시한다. 아까의 중첩된 식은 이제 단순한 행렬 곱의 연쇄가 된다.

행렬 곱은 결합법칙이 성립하므로 를 미리 하나로 합쳐 둘 수 있다. 본 100개짜리 리그에서도 각 본마다 최종 행렬 하나만 들고 있으면 된다.

w는 점과 방향을 구분한다

동차 좌표의 네 번째 성분 에는 또 하나의 역할이 있다. 이면 점(position), 이면 방향 벡터(direction)다.

왜 이렇게 되는지 위의 이동 행렬에 을 넣어 보면 바로 보인다.

이동 성분 과 곱해져 전부 사라진다. 즉 방향 벡터는 이동의 영향을 받지 않는다. 이건 수학적 우연이 아니라 정확히 우리가 원하는 동작이다. 본이 바라보는 방향, 노멀 벡터, 조인트의 축(axis) — 이런 것들은 본이 어디에 있든 상관없이 회전만 따라가야 한다. 반면 조인트의 피벗 위치는 이동을 그대로 받아야 한다.

실무에서 리그가 이상하게 어긋날 때 흔한 원인 중 하나가 이 를 잘못 넣는 것이다. 방향 벡터를 로 변환하면 방향이 본의 위치만큼 밀려 버린다.

본의 로컬 공간과 월드 공간

이제 본 체인을 보자. 각 본 는 부모 본의 좌표계 기준으로 자기 변환을 하나 들고 있다. 이걸 로컬 행렬 라고 하자. 로컬 행렬은 보통 이렇게 조립된다.

오른쪽부터 읽는다. 점에 먼저 스케일 가 적용되고, 그 결과에 회전 가, 마지막에 이동 가 적용된다. 순서가 중요하다. 행렬 곱은 교환법칙이 성립하지 않기 때문에(), 회전 후 이동과 이동 후 회전은 완전히 다른 결과를 낸다. 스케일을 회전보다 뒤에 적용하면 축이 비틀린 스케일이 되어 셰어가 생긴다.

월드 행렬 는 루트부터 자기까지의 로컬 행렬을 전부 곱한 것이다. 재귀적으로 쓰면

여기서 는 본 의 부모 인덱스다. 이 한 줄이 리깅 계층 구조의 전부다. 루트부터 트리를 깊이 우선으로 훑으면서 부모의 월드 행렬에 자기 로컬 행렬을 곱해 나가면, 모든 본의 월드 행렬이 한 번의 순회로 계산된다.

리깅: 동차 좌표 — 본의 로컬 공간과 월드 공간 계산 도식

부모를 회전시키면 자식의 로컬 행렬 는 전혀 바뀌지 않는다. 바뀌는 건 뿐이고, 곱셈 결과인 가 자동으로 따라 움직인다. 애니메이터가 어깨를 돌렸을 때 손가락까지 딸려 오는 이유가 이것이다.

반대 방향: 월드에서 로컬로

월드 좌표를 알고 있고 로컬 좌표를 구해야 하는 경우도 흔하다. IK 솔버가 발 컨트롤러의 월드 위치를 다리 본 계층의 로컬 값으로 되돌릴 때, 혹은 스키닝에서 바인드 포즈를 되돌릴 때가 그렇다. 이때 필요한 것이 역행렬이다.

의 효과를 정확히 되돌리는 행렬, 즉 (항등행렬)를 만족하는 행렬이다. 동차 좌표의 아핀 행렬은 역행렬이 아주 예쁘게 나온다. 가 회전과 스케일 블록, 가 이동일 때

말로 풀면 이렇다. 먼저 이동을 되돌리려면 만큼 옮겨야 하는데, 그 되돌린 이동량도 로 변환된 좌표계 기준으로 표현해야 하므로 가 된다. 특히 가 순수 회전 행렬이라면 (전치행렬)이므로 역행렬 계산이 거의 공짜다. 스케일이 없는 본 체인에서 월드→로컬 변환이 빠른 이유다.

스키닝의 바인드 행렬도 같은 원리다. 본 의 바인드 포즈 월드 행렬을 라 할 때, 정점 의 스킨된 위치는

여기서 는 본 의 스킨 웨이트(가중치, )다. 이 정점을 월드에서 본의 바인드 로컬 공간으로 끌어오고, 가 현재 포즈의 월드 공간으로 다시 내보낸다. 이 두 행렬은 미리 곱해서 하나로 캐싱해 두는 것이 표준이고, 이것이 스키닝 팔레트다.

w가 1이 아닐 때: 사영과 스케일 동치

지금까지는 를 1 아니면 0으로만 썼다. 하지만 동차 좌표의 원래 정의는 더 넓다. 0이 아닌 임의의 에 대해

즉 스칼라 배는 같은 점을 나타낸다. 은 동일한 점이다. 실제 데카르트 좌표로 되돌리려면 로 나눈다(원근 나눗셈, perspective divide).

여기서 의 극한을 생각하면, 나눗셈 결과가 무한히 멀어진다. 그래서 인 좌표는 무한원점(point at infinity)이다. 방향 벡터를 으로 두는 것은 사실 "그 방향으로 무한히 먼 곳의 점"이라는 사영기하학적 해석과 정확히 일치한다. 두 평행선이 만나는 그 점이다.

리깅에서 이 실제로 등장하는 곳은 카메라의 원근 투영 행렬이다. 투영 행렬은 맨 아래 행이 이 아니라 같은 꼴이라, 곱한 결과의 (깊이)가 들어간다. 그다음 로 나누면 멀리 있는 것이 작아지는 원근 효과가 나온다. 아핀 변환과 사영 변환이 완전히 같은 행렬 곱 하나로 처리되는 것 — 이것이 동차 좌표가 컴퓨터 그래픽스의 표준 좌표계가 된 결정적 이유다.

같은 원리가 곡선에도 쓰인다

동차 좌표의 이 "나중에 로 나눈다"는 아이디어는 변환 말고 다른 데에도 재활용된다. 유리 베지에(rational Bézier)와 NURBS가 대표적이다. 제어점을 동차 좌표 로 올려 두고, 그 위에서 평범한 다항식 곡선을 만든 다음, 마지막에 로 나눠 평면으로 내리면 다항식으로는 표현할 수 없는 곡선(정확한 원호 등)이 나온다.

한 차원 위에서는 단순한 다항식인데, 아래로 내리면 유리함수가 된다. 본 계층에서 "한 차원 올려서 이동을 선형으로 만든다"는 것과 정확히 같은 발상이다. 리깅에서 스플라인 IK나 커브 기반 컨트롤을 다룰 때 제어점에 붙은 가중치가 이 다. 가중치를 키우면 곡선이 그 제어점 쪽으로 끌려오는 이유는, 사영하기 전 공간에서 그 점이 더 "높이" 올라가 있기 때문이다.

정리하면

동차 좌표가 리깅에 주는 것은 세 가지다. 첫째, 차원을 하나 올려서 이동을 행렬 곱 안에 집어넣었다. 덕분에 본 체인의 변환이 순수한 곱셈의 연쇄가 되고, 결합법칙으로 미리 합쳐 캐싱할 수 있다. 둘째, 의 0과 1이 방향과 위치를 자연스럽게 구분해 준다. 노멀과 축은 이동을 무시하고 회전만 따라간다. 셋째, 아핀 변환과 사영 변환이 같은 형식이 되어, 본 계층 계산부터 카메라 투영까지 하나의 파이프라인으로 흐른다.

본을 하나 옮겼을 때 자식들이 따라오는 그 흔한 동작은, 결국 라는 한 줄과 라는 숫자 하나가 만들어 내는 것이다.

함께 읽기 — 이 글이 쓰는 기초 수학

출처

광고

리깅 파이프라인 자동화 도구

반복 작업은 스크립트에게. 현업에서 쓰는 리깅 툴 모음.

리깅 도구 보기