스키닝
고친 사람 github-actions[bot]
스키닝은 뼈대가 움직일 때 그 뼈대를 감싼 3차원 모형의 겉면을 함께 휘게 합니다. 겉면의 꼭짓점마다 어느 뼈를 얼마나 따라갈지 적어 둡니다. 뼈가 움직이면 그 비율대로 꼭짓점을 옮깁니다. 팔을 굽히면 팔꿈치 둘레의 살갗이 따라 접히는 것이 이 계산의 결과입니다.
쉽고 빠른 이해
스키닝은 뼈대의 움직임을 겉면의 꼭짓점들에 나눠 옮겨 주는 계산입니다. 사람 모형이 팔을 들면 어깨와 팔을 덮은 꼭짓점 수천 개가 뼈를 따라 함께 올라갑니다.
이게 없으면 움직이는 장면마다 모든 꼭짓점의 위치를 따로 저장해야 합니다. 걷는 동작 하나에도 모형 한 벌이 장면 수만큼 쌓입니다. 스키닝을 쓰면 뼈 수십 개의 자세만 저장하고 꼭짓점 위치는 그릴 때마다 계산합니다.
어떻게 도나:
- 모형을 만들 때 꼭짓점마다 따라갈 뼈 몇 개와 그 가중치를 적어 둡니다
- 장면마다 뼈 하나하나가 처음 자세에서 얼마나 움직였는지 구합니다
- 꼭짓점마다 자기 뼈들의 움직임을 가중치대로 섞어 새 위치를 냅니다
대가는 섞는 방식이 단순한 만큼 모양이 틀어질 때가 있다는 것입니다. 팔꿈치를 크게 굽히면 그 둘레가 쪼그라듭니다. 손목을 크게 비틀면 사탕 포장지 끝처럼 가늘게 꼬입니다.
뼈대로 나타내기 어려운 움직임에는 스키닝을 쓰지 않습니다. 얼굴 표정처럼 뼈 몇 개로 잡히지 않는 변형은 겉면 모양을 여러 벌 만들어 두고 섞습니다. 바람에 펄럭이는 옷자락처럼 뼈대 없이 흔들리는 것은 물리 계산으로 꼭짓점을 직접 옮깁니다.
상세
스키닝은 입력 셋을 받아 꼭짓점의 새 위치를 내놓는 계산입니다. 넣는 것은 처음 자세의 꼭짓점 위치, 꼭짓점마다 적어 둔 뼈와 가중치, 그리고 지금 장면의 뼈대 자세입니다. 나오는 것은 그 자세에 맞게 휜 꼭짓점 위치입니다.
이 절은 먼저 뼈대와 겉면이 무엇인지를 옷소매 하나로 그려 봅니다. 그다음 꼭짓점에 무엇을 적어 두는지와 섞는 계산이 어떻게 생겼는지를 팔꿈치 둘레 꼭짓점 하나의 숫자로 따라갑니다. 끝으로 세 가지를 봅니다. 이 계산이 그래픽 카드의 어느 단계에서 도는지, 비용이 어떻게 붙는지, 어디서 모양이 틀어지는지입니다.
뼈대와 겉면
긴소매 옷을 입고 팔을 굽히는 장면을 떠올려 보면 됩니다. 위팔을 덮은 천은 위팔을 따라갑니다. 아래팔을 덮은 천은 아래팔을 따라갑니다. 팔꿈치 둘레의 천은 양쪽에 다 끌려서 그 중간쯤으로 접힙니다.
3차원 캐릭터도 두 겹으로 만듭니다. 바깥 겹은 눈에 보이는 겉면입니다. 안쪽 겹은 화면에 안 그려지는 뼈대입니다. 움직임을 만드는 쪽은 뼈대만 움직입니다. 겉면은 스키닝이 뼈대에 맞춰 옮깁니다.
겉면은 작은 삼각형 수천에서 수만 개를 이어 붙여 만듭니다. 이 삼각형 묶음을 메시라고 부릅니다. 삼각형의 모서리가 만나는 점은 꼭짓점이라고 부릅니다. 그래픽스에서는 같은 점을 정점이라고도 부릅니다. 겉면을 휘게 한다는 말은 꼭짓점을 옮긴다는 말입니다.
뼈대는 뼈 여러 개가 부모와 자식으로 이어진 나무 모양입니다. 어깨 뼈 아래에 위팔 뼈가, 그 아래에 아래팔 뼈가 매달립니다. 부모가 돌면 자식도 따라 돌기 때문에 어깨만 돌려도 팔 전체가 움직입니다. 뼈는 본(bone)이나 조인트(joint)라고도 부릅니다.
장면마다 뼈대의 자세를 정하는 일은 스켈레탈 애니메이션이 맡습니다. 스키닝은 그렇게 정해진 자세를 받아 겉면에 옮기는 뒤쪽 절반입니다.
꼭짓점을 장면마다 저장하지 않는 까닭
스키닝 없이 캐릭터를 움직이는 가장 곧은 방법은 장면마다 모든 꼭짓점 위치를 적어 두는 것입니다. 꼭짓점이 만 개인 모형이 걷는 동작을 서른 장면으로 보여 주면 위치 삼십만 개가 필요합니다. 동작이 하나 늘 때마다 이만큼씩 더 쌓입니다.
뼈대는 훨씬 작습니다. 사람 모형의 뼈는 대개 수십 개라서 장면마다 뼈 수십 개의 자세만 적어 두면 됩니다. 꼭짓점 위치는 그릴 때 이 자세에서 계산해 냅니다.
꼭짓점마다 적어 두는 뼈와 가중치
꼭짓점 하나에는 두 가지가 붙습니다. 어느 뼈를 따라갈지와 얼마나 따라갈지입니다. 따라갈 뼈는 번호로 적습니다. 얼마나 따라갈지는 0 과 1 사이의 수로 적습니다. 이 수를 가중치라고 부릅니다.
한 꼭짓점의 가중치를 다 더하면 1 이 되도록 맞춥니다. 위팔 한가운데 꼭짓점은 위팔 뼈 하나에서 1 을 받습니다. 팔꿈치 둘레 꼭짓점은 위팔 뼈와 아래팔 뼈에서 0.5 씩 나눠 받습니다. 합이 1 이어야 뼈대가 가만히 있을 때 꼭짓점도 제 위치에 머뭅니다.
한 꼭짓점이 따라갈 뼈의 수는 몇 개까지로 묶어 둡니다. 실시간으로 그리는 쪽에서는 넷까지로 묶는 경우가 많습니다. 개수가 정해져 있어야 모든 꼭짓점이 같은 크기의 칸에 번호와 가중치를 담을 수 있습니다.
꼭짓점마다 붙는 이런 값을 정점 속성이라고 부릅니다. 뼈 번호와 가중치는 위치나 색과 같은 방식으로 꼭짓점 목록에 함께 담깁니다.
가중치는 사람이 정합니다. 모델링 도구에서 뼈마다 영향 범위를 붓으로 칠하듯 그려 넣습니다. 이 작업을 웨이트 페인팅이라고 부릅니다. 뼈대에 겉면을 붙이는 이 앞 단계까지 묶어 스키닝이라고 부르기도 합니다. 이 항목은 그렇게 정한 값을 써서 꼭짓점을 옮기는 계산을 다룹니다.
처음 자세에서 얼마나 움직였나
뼈 하나가 꼭짓점을 옮기려면 먼저 기준이 되는 자세가 있어야 합니다. 꼭짓점 위치는 모형을 만들 때 한 번 적힙니다. 그때 뼈대는 팔을 옆으로 벌린 T 자 자세처럼 정해진 자세로 서 있습니다. 뼈대에 겉면을 붙이던 때의 이 자세를 바인드 포즈라고 부릅니다.
스키닝이 뼈마다 알아야 하는 것은 바인드 포즈에서 지금까지 얼마나 움직였느냐입니다. 지금 자세만 알아서는 부족합니다. 꼭짓점 위치가 바인드 포즈를 기준으로 적혀 있기 때문입니다.
뼈의 자세와 움직임은 변환 행렬로 적습니다. 변환 행렬은 옮기기·돌리기·키우기를 숫자 한 덩이에 담은 것입니다. 점에 곱하면 그 변환이 한 번에 적용됩니다.
뼈 하나의 자세 행렬은 그 뼈가 그 자세에서 어디에 어느 방향으로 놓였는지를 담습니다. 그래서 뼈마다 바인드 포즈의 행렬과 지금 자세의 행렬을 하나씩 갖습니다.
계산은 두 단계입니다. 먼저 바인드 포즈의 변환을 되돌려 꼭짓점을 그 뼈 기준의 좌표로 바꿉니다. 뼈 기준의 좌표는 그 뼈가 원점이고 그 뼈의 방향이 축인 좌표입니다. 그다음 지금 자세의 행렬을 곱하면 뼈를 따라 옮겨진 위치가 나옵니다.
어떤 행렬이 하는 변환을 거꾸로 되돌리는 행렬을 그 행렬의 역행렬이라고 부릅니다. 첫 단계에 쓰는 것이 바인드 포즈 행렬의 역행렬입니다. 이 역행렬은 뼈대가 움직여도 바뀌지 않아서 모형을 불러올 때 한 번만 구해 둡니다.
두 행렬은 꼭짓점과 상관없이 뼈마다 하나씩 정해집니다. 그래서 장면마다 뼈 하나에 한 번씩 둘을 곱해 행렬 하나로 합쳐 둡니다. 꼭짓점 쪽에서는 곱셈이 한 번으로 줄어듭니다.
이 합친 행렬을 스키닝 행렬이라고 부릅니다. 스키닝 행렬이 곧 그 뼈가 바인드 포즈에서 지금까지 움직인 양입니다.
가중치대로 섞는 계산
뼈 여럿을 따라가는 꼭짓점은 여러 위치를 하나로 모아야 합니다. 뼈마다 스키닝 행렬로 옮겨 본 위치가 하나씩 나옵니다. 이 위치들을 가중치만큼씩 더하면 최종 위치가 됩니다. 가중치 0.5 인 뼈 둘이라면 두 위치의 한가운데입니다.
이 방식을 선형 블렌드 스키닝이라고 부릅니다. 위치를 곧은 선 위에서 비율대로 섞는다는 뜻입니다. 가장 단순한 방식이라 그냥 스키닝이라고 하면 대개 이 방식을 가리킵니다.
아래는 팔꿈치 둘레 꼭짓점 하나를 손으로 계산한 예입니다. 팔꿈치는 원점에 둡니다. 꼭짓점은 팔꿈치에서 1 만큼 떨어진 (1, 0) 에 있습니다. 위팔 뼈는 가만히 있고 아래팔 뼈는 팔꿈치를 축으로 90 도 굽었습니다. 가중치는 두 뼈에 0.5 씩입니다.
v = (1, 0)
pa = turn(v, 0) # (1, 0)
pb = turn(v, 90) # (0, 1)
p = mix(pa, pb, 0.5) # (0.5, 0.5)
dist(p) # 0.71
turn 은 팔꿈치를 축으로 점을 돌리는 계산입니다. mix 는 두 점을 비율대로 섞습니다. dist 는
팔꿈치에서 떨어진 거리를 잽니다. 위팔 뼈를 따르면 (1, 0) 에 머뭅니다. 아래팔 뼈를 따르면
(0, 1) 로 갑니다. 둘을 반씩 섞은 (0.5, 0.5) 가 이 꼭짓점의 새 위치입니다.
마지막 줄을 보면 거리가 달라졌습니다. 처음 거리는 1 이었습니다. 섞은 뒤에는 0.71 로 줄었습니다. 이 줄어듦은 아래 「모양이 틀어지는 경우」에서 다시 봅니다.
꼭짓점에는 위치 말고도 표면이 향한 방향이 붙습니다. 이 방향을 법선이라고 부릅니다. 법선은 빛이 어떻게 비칠지 계산할 때 씁니다. 겉면이 휘면 방향도 바뀌므로 법선도 같은 뼈와 가중치로 함께 돌려 줍니다.
정점 셰이더에서 도는 계산
이 소절은 스키닝이 그래픽 카드의 어느 단계에서 도는지와 필요한 값이 어느 길로 들어오는지를 봅니다. 스키닝은 꼭짓점마다 따로 돕니다. 한 꼭짓점을 옮길 때 옆 꼭짓점의 결과를 볼 필요가 없습니다. 이렇게 서로 기다리지 않는 계산은 GPU(Graphics Processing Unit, 그래픽 처리 장치)가 수천 개를 한꺼번에 처리할 수 있습니다.
그래서 스키닝은 대개 정점 셰이더에서 돕니다. 정점 셰이더는 그래픽 카드가 꼭짓점 하나마다 한 번씩 부르는 작은 프로그램입니다. 꼭짓점의 새 위치를 계산해 내놓는 것이 이 프로그램의 일입니다.
값이 들어오는 길은 둘로 갈립니다. 뼈 번호와 가중치는 위치와 함께 꼭짓점 목록에 담겨 꼭짓점마다 하나씩 들어옵니다. 스키닝 행렬은 뼈 수만큼 배열로 묶어 넘깁니다. 그리기 한 번 동안 모든 꼭짓점이 똑같이 읽는 이런 값을 유니폼이라고 부릅니다.
아래 그림은 무엇이 언제 준비되는지를 보입니다. 꼭짓점 목록과 바인드 포즈의 역행렬은 모형을 불러올 때 한 번 준비합니다. 장면마다 바뀌는 것은 뼈 수만큼의 행렬뿐입니다.
flowchart TD
subgraph S1["모형을 불러올 때 한 번"]
A["꼭짓점 목록 · 위치 · 뼈 번호 · 가중치"]
B["뼈마다 바인드 포즈의 역행렬"]
end
subgraph S2["장면마다"]
C["뼈마다 지금 자세의 행렬"]
D["뼈마다 스키닝 행렬"]
end
B --> D
C --> D
A --> E["정점 셰이더 · 꼭짓점마다 가중치대로 섞는다"]
D --> E
E --> F["휜 꼭짓점 위치"]
섞는 순서는 바꿔도 결과가 같습니다. 뼈마다 꼭짓점을 옮긴 뒤 섞어도 됩니다. 스키닝 행렬들을 가중치대로 먼저 섞은 뒤 꼭짓점에 한 번 곱해도 됩니다.
두 길의 값이 같은 까닭은 곱셈의 분배 법칙입니다. 행렬마다 점에 곱한 뒤 가중치대로 더한 값은 행렬들을 가중치대로 더한 뒤 점에 한 번 곱한 값과 같습니다. 뒤쪽으로 하면 섞은 행렬 하나로 위치와 법선을 함께 옮길 수 있습니다.
정점 셰이더 대신 컴퓨트 셰이더에서 스키닝을 먼저 돌려 결과를 저장해 두기도 합니다. 컴퓨트 셰이더는 그리기와 상관없는 계산을 그래픽 카드에 맡기는 프로그램입니다. 같은 모형을 한 장면에서 여러 번 그려야 할 때 스키닝을 한 번만 하려는 것입니다.
계산량
이 소절은 장면 하나를 그릴 때 스키닝에 드는 비용을 뼈 수와 꼭짓점 수로 셉니다. 뼈 수를 B, 꼭짓점 수를 V, 꼭짓점 하나가 따라가는 뼈 수를 k 라고 두겠습니다.
| 몫 | 비례하는 값 | 언제 드나 |
|---|---|---|
| 스키닝 행렬 만들기 | B | 장면마다 |
| 꼭짓점 섞기 | V × k | 장면마다, 그 모형을 그릴 때마다 |
| 추가 저장 공간 | V × k 개의 번호와 가중치 | 모형을 불러올 때 한 번 |
표를 합치면 장면 하나의 시간은 O(B + V·k) 입니다. k 는 넷 안팎으로 묶어 두므로 상수로 봐도 됩니다. 꼭짓점 수가 뼈 수보다 훨씬 많아서 비용은 거의 꼭짓점 수가 정합니다.
화면 크기는 이 비용과 상관이 없습니다. 같은 모형을 작은 창에 그리든 큰 화면에 그리든 꼭짓점 수는 같기 때문입니다. 멀리 있는 캐릭터를 꼭짓점과 뼈가 적은 모형으로 바꿔 그리면 비용이 줄어듭니다. 이 방식이 레벨 오브 디테일입니다.
모양이 틀어지는 경우
이 소절은 앞의 숫자 예에서 거리가 줄어든 까닭과, 그것이 겉면에서 어떤 모양으로 나타나는지를 봅니다. 두 위치는 팔꿈치를 중심으로 한 원 위에 있었습니다. 원 위의 두 점을 곧은 선으로 섞으면 그 한가운데는 원의 안쪽에 떨어집니다. 그래서 꼭짓점이 팔꿈치 쪽으로 끌려 들어갔습니다.
굽힘이 클수록 더 깊이 들어갑니다. 팔꿈치나 무릎을 많이 굽히면 그 둘레가 쪼그라들어 보입니다. 겉면이 감싼 부피가 줄어든 것처럼 보여서 이 증상을 부피 손실이라고 부릅니다.
비틀 때는 더 심합니다. 손목 뼈가 팔 방향을 축으로 반 바퀴 돌았다고 해 봅시다. 팔을 가로로 자른 단면을 보면서 팔의 중심선을 원점에 둡니다.
(1, 0) 에 있던 꼭짓점이 가만히 있는 아래팔 뼈를 따르면 (1, 0) 에 머뭅니다. 손목 뼈를 따르면 (-1, 0) 으로 갑니다. 두 뼈에서 가중치를 반씩 받았다면 두 위치의 한가운데인 원점, 곧 팔의 중심선으로 몰립니다. 그 둘레가 사탕 포장지 끝처럼 가늘게 꼬여서 이 증상을 캔디 래퍼 현상이라고 부릅니다.
틀어짐을 줄이는 방법은 여럿입니다. 흔한 셋은 다음과 같습니다.
| 방법 | 어떻게 줄이나 | 대가 |
|---|---|---|
| 회전끼리 섞기 · 듀얼 쿼터니언 스키닝 | 뼈의 움직임을 회전과 옮김으로 나눠 적고, 회전은 회전끼리 섞는다. 섞은 결과가 원 위에 남는다 | 계산이 선형 블렌드 스키닝보다 무겁다 |
| 비틀림을 나눠 받는 보조 뼈 | 손목 비틀림을 팔을 따라 놓인 뼈 여럿에 조금씩 나눠 준다. 뼈 하나가 도는 각도가 작아진다 | 뼈 수와 가중치 작업이 늘어난다 |
| 굽힌 모양을 따로 만들어 두기 · 모프 타깃 | 많이 굽힌 자세의 겉면 모양을 사람이 미리 다듬어 저장한다. 그 자세에 가까워지면 그 모양을 섞어 넣는다 | 자세마다 모양을 만들어야 하고 저장량이 는다 |
세 방법은 함께 쓸 수 있습니다. 앞의 둘은 섞는 계산이나 뼈대를 바꿉니다. 셋째는 섞은 결과 위에 사람이 다듬은 모양을 덧입힙니다.
뼈대로 나타내기 어려운 움직임에는 스키닝 대신 다른 방식을 씁니다. 얼굴 표정처럼 뼈 몇 개로 잡히지 않는 변형은 모프 타깃으로 겉면 모양을 섞기도 합니다. 바람에 펄럭이는 옷자락은 옷감 시뮬레이션이 물리 계산으로 꼭짓점을 직접 옮깁니다.
관련 항목
스키닝이 속하는 상위 분류
그래픽스 · 3D 그래픽스 · 컴퓨터 애니메이션 · 캐릭터 애니메이션 · 실시간 렌더링
스키닝 앞에서 뼈대 자세를 만드는 처리
스켈레탈 애니메이션 · 키프레임 · 애니메이션 블렌딩 · 순운동학 · 역운동학 · 모션 캡처 · 리깅
스키닝 계산에 들어가는 데이터
메시 · 정점 · 스켈레톤 · 조인트 · 바인드 포즈 · 역바인드 행렬 · 스키닝 가중치 · 정점 속성 · 법선
뼈의 움직임을 적고 섞는 수학 도구
변환 행렬 · 행렬 곱 · 역행렬 · 동차 좌표 · 쿼터니언 · 듀얼 쿼터니언 · 선형 보간 · 보간
스키닝의 하위 종류
선형 블렌드 스키닝 · 듀얼 쿼터니언 스키닝 · 구면 블렌드 스키닝
스키닝에서 나는 변형 결함과 그 보정 기법
부피 손실 · 캔디 래퍼 현상 · 트위스트 본 · 헬퍼 본 · 보정 셰이프 · 웨이트 페인팅
스키닝이 도는 처리 단계와 장치
정점 셰이더 · 컴퓨트 셰이더 · 유니폼 · 정점 버퍼 · 그래픽스 파이프라인 · GPU
스키닝 대신 모형을 움직이는 다른 방식
모프 타깃 · 정점 애니메이션 텍스처 · 옷감 시뮬레이션 · 래그돌
스키닝 비용을 줄이는 기법
레벨 오브 디테일 · GPU 스키닝 · 인스턴싱 · 컬링
스키닝 데이터를 담아 나르는 파일 포맷
glTF · FBX · COLLADA · USD
스키닝을 만들고 돌리는 도구와 엔진
Blender · Maya · Unity · Unreal Engine · 스키닝 메시 렌더러
다른 이름: skinning · Skinning · 메시 스키닝 · 정점 스키닝