컷아웃 캐릭터 애니메이션하기
파츠 리그로 제작된 캐릭터를 위한 레시피: 몸통, 머리, 두 조각의 팔, 그리고 머리 캔버스 위에 그려진 페이스 오버레이(입 모양과 깜빡임)로 구성됩니다. 이 레시피들은 montagent의 루프 중 빌드 단계에 들어갑니다. 아직 montagent를 로드하지 않았다면 먼저 로드하세요. 캐릭터가 대사를 말하는 쇼트 영상의 경우, 계획을 세우기 전에 캐릭터 쇼트 구조를 여세요.
리그가 제공해야 하는 것
무엇보다 먼저 리그의 설명을 읽으세요. 각 파츠에 대해 다음이 필요합니다: 이미지, 크기, 피벗(파츠가 회전하는 관절 지점, 원본 그림에서의 점), 부모, 그리고 파츠가 그려지는 순서(뒤에서 앞으로). 또한 음성의 비즈메 ID를 입 모양에 매핑하는 테이블이 필요합니다. 각 파츠의 이미지는 피벗이 캔버스의 정확한 중심이 되도록 패딩되어야 합니다. 페이스 오버레이는 머리의 캔버스와 피벗을 공유합니다.
브리핑이 파츠나 피벗 없이 단일 그림만 제공하는 경우, 맹목적으로 리그를 자를 수 없습니다. 사용자에게 알리고 미리 잘린 리그를 요청하세요.
리그 굽기(Bake)
Montagent에는 부모-자식 관계가 없으며, 요소는 이미지를 변경할 수 없습니다. 따라서 캐릭터는 '구워집니다(baked)': 번들 스크립트가 각 그려진 프레임에서 모든 파츠의 화면상 위치와 회전을 부모로부터 계산하고, 각 입 모양과 깜빡임을 자체적인 요소로 작성하여 머리의 변환과 함께 해당 기간 동안 표시합니다. 직접 작성하지 마세요.
python3 scripts/bake_rig.py <project> <rig> <spec>은 파츠당 하나의 트랙이 추가된 프로젝트를 출력합니다. --help를 실행하여 스펙(캐릭터가 서 있는 위치, 명명된 포즈, 그 사이의 움직임, 흔들기, 점프, 음성 및 비즈메 파일, 깜빡임)을 확인하세요. 스펙을 변경할 때마다 다시 실행하세요. 이 스크립트는 자신이 작성한 트랙만 교체합니다. 스펙을 프로젝트 옆에 보관하세요: 이것이 캐릭터의 진정한 소스입니다.
보고서를 읽으세요. 병합된 각 입 기간, 모든 그려진 프레임에서 자식과 부모 사이의 가장 큰 간격, 그리고 주목해야 할 순간들(각 움직임의 도착과 각 관절의 극단 각도)을 나열합니다. 위치는 정수 픽셀이므로 약 1.5px까지의 간격은 반올림으로 인한 것이며 둥근 관절에 의해 숨겨집니다. 더 큰 간격은 리그의 피벗이 잘못되었음을 의미합니다.
validate는 캐릭터가 유지하는 각 포즈에 대해 R-EASE-INERT를 보고하고, 입과 깜빡임 트랙의 간격 사이에 N-TRACK-GAP을 보고합니다. 둘 다 예상된 것입니다(발견 가이드 참조).
구운 결과는 다음과 같습니다: 각 파츠는 피벗을 중심으로 배치되고, 움직이는 곳에만 키프레임이 있으며, 각 입 또는 깜빡임 요소는 해당 기간 동안 머리의 변환을 복사합니다.
{
"frame": {"width": 640, "height": 360}, "fps": 30, "background": "#2E3440", "duration": 2000, "output": "out/baked.mp4",
"tracks": [
{"name": "set", "layer": 0, "elements": [
{"id": "set", "type": "image", "start": 0, "end": 2000, "source": "media/still.png", "x": 0, "y": 0, "origin": "top-left", "width": 640, "height": 360, "fit": "literal"}
]},
{"name": "puppet-torso", "layer": 10, "elements": [
{"id": "puppet-torso", "type": "image", "start": 0, "end": 2000, "source": "rig/parts/torso.png", "x": 320, "y": 330, "origin": "center", "fit": "literal", "width": 80, "height": 280}
]},
{"name": "puppet-head", "layer": 12, "elements": [
{"id": "puppet-head", "type": "image", "start": 0, "end": 2000, "source": "rig/parts/head.png", "x": 320, "y": 190, "origin": "center", "fit": "literal", "width": 90, "height": 160, "rotation": [{"t": 0, "v": 0}, {"t": 500, "v": 6.0, "ease": "linear"}, {"t": 1000, "v": 0.0, "ease": "linear"}]}
]},
{"name": "puppet-mouth", "layer": 13, "elements": [
{"id": "puppet-mouth-0", "type": "image", "start": 400, "end": 700, "source": "rig/parts/mouth_open.png", "x": 320, "y": 190, "origin": "center", "fit": "literal", "width": 24, "height": 60, "rotation": [{"t": 400, "v": 4.8}, {"t": 500, "v": 6.0, "ease": "linear"}, {"t": 666, "v": 4.0, "ease": "linear"}]}
]}
]
}
레시피
모든 레시피는 정답이 아닌 시작 범위를 제공합니다. 각 레시피는 확인 단계로 끝납니다: montagent-craft를 로드한 다음, 해당 단계에 명시된 대로 확인한 후 진행하세요.
각도는 그려진 기본 포즈에서의 회전이며, 각각 부모를 기준으로 하고, 화면에서 시계 방향으로 양수입니다. 따라서 시청자 기준 오른쪽 팔은 음수 각도로 올라가고, 왼쪽 팔은 양수 각도로 올라갑니다.
세트에 세우기
- 배경:
origin이top-left인 전체 프레임 세트 이미지를 (0, 0)에, 프레임 크기로, 가장 낮은 레이어에 배치합니다.origin을 명시적으로 설정하세요. - 바닥에 발: 리그의 루트(발에서 피벗하는 몸통)는 바닥이 벽의 그림자 선과 만나는 곳, 또는 그보다 약간 앞에 위치합니다. 높이 1080의 세트에서 바닥의 상단 가장자리는 보통 아래에서 80–85% 지점이므로, 발을 그보다 5–10% 아래에 두세요.
- 크기: 캐릭터는 프레임 높이의 55–75%이며, 스펙의 스케일(프레임 픽셀 / 그림 픽셀)로 설정됩니다. 패딩된 그림이 아닌 보이는 캐릭터를 측정하세요: 그림 높이에 스케일을 곱하면 실제보다 커집니다.
- 배치: 단독으로 서 있지 않다면, 소품이나 카드 반대쪽으로 중앙에서 벗어나 1/3 지점에 배치합니다.
- 확인: 안정적인 순간에
frame을 보고 발이 바닥에 닿아 있는지(떠 있거나 파묻히지 않았는지), 머리가 프레임 상단에서 최소 5% 이상 떨어져 있는지 확인하세요.
등장: 깡충 뛰어 들어오기
- 점프: 2–3회, 각 300–450ms, 점점 낮아집니다: 첫 번째 점프는 캐릭터 높이의 8–12%, 마지막 점프는 4–6%입니다. 수평 이동은 동일한 구간을
ease-out으로 덮으므로 마지막 점프는 부드럽게 착지합니다. - 포즈: 점프하는 동안 팔을 내립니다. 그려진 프레임에 착지하고, 첫 번째 제스처 전에 150–300ms 동안 유지합니다.
- 타이밍: 음성이 시작되기 전에 끝나야 하며, 최소 200ms의 여유가 있어야 합니다.
- 확인: 등장 구간에 대해
frame --from --to --keyframes를 실행합니다. 각 착지 지점에서 발이 바닥에 닿는지, 어떤 파츠도 몸통보다 뒤처지거나 앞서 튀지 않는지 확인하세요.
제스처
제스처는 명명된 포즈와, 그 포즈로 들어가고 나오는 움직임입니다. 각 움직임에 리드인 시간(스펙의 in)을 주어 포즈가 출발할 때까지 유지되도록 합니다.
- 팔 내리기: 팔을 벌린 기본 포즈에서 각 위팔을 몸쪽으로 40–55° 돌리고, 아래팔을 5–15° 더 돌립니다.
- 손 흔들기: 위팔을 기본에서 40–50° 옆으로 올리고, 아래팔을 25–35° 더 올립니다. 아래팔을 팔꿈치에서 15–20°씩 양방향으로 흔들며, 주기는 350–450ms, 최소 2회 완전한 흔들기(800ms 이상)를 수행합니다. 더 높이 올리면 손이 흔들림의 안쪽 극단에서 머리 뒤로 갑니다: 머리가 팔 위에 그려집니다.
- 무언가 가리키기: 위팔을 대상 방향으로 거의 수평(팔을 내린 상태에서 10–25° 위)으로 하고, 아래팔은 직선에서 20° 이내로 하여 손이 대상의 가까운 가장자리를 가리키도록 합니다. 그 대상을 지칭하는 단어보다 1–3프레임 먼저 도착합니다.
- 환호: 두 위팔을 40–50° 올리고, 아래팔을 20–30° 더 올립니다. 더 구부리면 오버슈트의 정점에서 손이 머리 뒤로 숨겨집니다.
- 움직임: 250–400ms 동안 들어옵니다. 오버슈트 베지어
[0.34, 1.56, 0.64, 1]로 도착하고,ease-in-out으로 기본 포즈로 돌아갑니다. 후속 동작을 위해 위팔이 도착한 후 2–4프레임 뒤에 아래팔만 지정하는 두 번째 움직임을 추가합니다. - 절대 멈추지 않음: 강세가 있는 단어에서 머리를 2–5° 기울이며, 짧은 흔들림 또는 250–400ms 동안 왔다 갔다 하는 움직임으로 표현합니다. 1.5초 이상 아무것도 움직이지 않고 포즈를 유지하는 캐릭터는 정지 이미지처럼 보입니다.
- 확인: 각 제스처에 대해 베이크 보고서에 해당 관절의 극단으로 나열된 순간에
frame --at을 실행합니다. 손이 머리와 프레임 가장자리에서 떨어져 있고, 소리 없이도 포즈가 해당 제스처로 읽히는지 확인하세요. 그런 다음 가장 높이 올린 포즈에서 어깨와 팔꿈치에 대해 실제 스케일로frame --crop을 실행하고, 간격이나 느슨한 파츠가 있는지 확인하세요.
비즈메 기반 입술 동기화
베이크는 음성의 비즈메 파일로부터 입을 작성합니다. 각 비즈메 ID는 리그의 테이블을 통해 입에 매핑되고, 침묵은 오버레이 없이 쉬고 있는 부리 또는 입술입니다. 스펙에서 음성 요소와 비즈메 파일을 지정하세요. 그러면 입은 해당 요소의 시작 및 소스 범위를 따르므로, 음성을 이동하고 다시 베이크하면 동기화가 유지됩니다.
- 가장 짧은 모양: 2프레임. 베이크는 더 짧은 모양을 이전 모양으로 병합하고 각 병합을 보고합니다. 6초 대사에서 12개의 병합은 정상입니다.
- 리드: 0ms. 렌더링을 볼 때 입이 늦게 느껴지면 1프레임(30fps에서 33ms)만 리드하고, 그 이상은 하지 마세요.
- 타이밍: 음성 파일을 프로브하세요. 길이가 비즈메 파일의 명시된 지속 시간과 일치하지 않으면 프로브를 신뢰하세요.
- 확인: 세 단어의 중간에서
query --at을 실행하고 각각 하나의 입 요소가 켜져 있는지 확인하세요. 그런 다음 가장 긴 멈춤의 중간과 대사가 끝난 후에query --at을 실행하고 어떤 입 요소도 켜져 있지 않은지 확인하세요.
깜빡임
- 길이: 3프레임(30fps에서 100ms), 최대 4프레임.
- 리듬: 2–4초마다, 불규칙적으로, 절대 박자에 맞추지 마세요. 큰 움직임이 도착한 직후에 한 번, 대사의 멈춤 중에 한 번 넣으세요. 8초마다 최소 2번.
- 피해야 할 것: 제스처 도착과 같은 프레임에 깜빡임이 있으면 도착이 가려집니다.
- 확인: 한 번의 깜빡임 중간 프레임에서
frame --at을 실행하고, 감긴 눈이 머리 위에 정확히 위치하고 머리의 기울기를 따르는지 확인하세요.