Formato de Arquivo¶
Os dois arquivos do OTS são JSON UTF-8 puro, indentado e legível. Você pode abrir um num editor de texto, comparar dois no controle de versão, ou escrever um script que leia um. Isso é deliberado — um formato de intercâmbio que você não consegue inspecionar é um formato de intercâmbio que você não consegue debugar.
O formato atual é a versão 4.
Cabeçalho compartilhado¶
Os dois formatos começam do mesmo jeito:
{
"format": "octo_anm",
"version": 4,
"source": "harmony",
"fps": 24.0,
"coordinate_system": {
"up": "y",
"hand": "right",
"unit": "meters",
"rot_order": "xyz",
"rot_repr_anim": "euler_deg",
"rot_repr_rest": "quat_wxyz"
}
}
| Chave | Significado |
|---|---|
format |
octo_pvt ou octo_anm |
version |
A versão do formato. Tem que bater exatamente — veja abaixo |
source |
Qual aplicação escreveu: harmony, blender ou maya |
fps |
A taxa de quadros da cena de origem |
coordinate_system |
O espaço em que os valores estão — veja Sistemas de Coordenadas |
Sem migração retroativa
Um leitor aceita apenas a própria versão. Um arquivo v3 carregado num build v4 reporta:
unsupported version 3 (this build writes/reads v4; no backward migration — re-export from the source DCC)
Isso é uma escolha, não um descuido. Migrar silenciosamente um arquivo antigo significa adivinhar o que seus números queriam dizer, e um chute errado produz um rig sutilmente torto em vez de obviamente quebrado. Reexportar da origem leva segundos e é sempre correto.
.pvt — pivot file¶
{
"format": "octo_pvt",
"version": 4,
"source": "harmony",
"name": "spaceship",
"scale_factor": 1.0,
"pivot_space": "local",
"fps": 24.0,
"coordinate_system": { "…": "…" },
"bones": [
{
"name": "hip",
"parent": null,
"pivot": [0.0, 0.0, 0.0],
"rotation": [1.0, 0.0, 0.0, 0.0],
"path": "Armature/hip",
"rig": "spaceship",
"is_camera": false
}
],
"cameras": []
}
| Chave | Significado |
|---|---|
name |
O nome do rig |
scale_factor |
A opção Scale voltada ao usuário. Pivots são multiplicados por ela na escrita, divididos na leitura |
pivot_space |
local (relativo ao parent) ou armature |
bones[].pivot |
Posição de repouso |
bones[].rotation |
Rotação de repouso, como quaternion [w, x, y, z] |
bones[].path |
O caminho completo do item na sua cena de origem — usado no match, e para manter distintos itens de mesmo nome em rigs diferentes |
bones[].rig |
A tag de rig |
path, rig e is_camera são omitidos quando vazios, então um arquivo simples continua pequeno.
.anm — arquivo de animação¶
{
"format": "octo_anm",
"version": 4,
"source": "maya",
"frame_range": [1, 60],
"fps": 24.0,
"coordinate_system": { "…": "…" },
"pegs": [
{
"name": "hip-P",
"path": "Top/spaceship/hip-P",
"parent": "root",
"rest_pivot": [0.0, 0.0, 0.0],
"rest_rotation": [1.0, 0.0, 0.0, 0.0],
"rig": "spaceship",
"is_camera": false,
"source_modes": {
"position": "separate",
"rotation": "euler",
"scale": "separate",
"enable_3d": true
},
"keyframes": [
{
"frame": 1,
"pos": [0.0, 0.0, 0.0],
"rot": [0.0, 0.0, 0.0],
"rot_quat": [1.0, 0.0, 0.0, 0.0],
"scl": [1.0, 1.0, 1.0],
"interp": "BEZIER",
"handles": { "pos": [], "rot": [], "scl": [] }
}
]
}
],
"cameras": []
}
Os campos de autossuficiência¶
parent, rest_pivot, rest_rotation e rig são o conteúdo do .pvt, embutido em cada peg. São a razão pela qual o Create Rig consegue construir um esqueleto funcional a partir de um .anm sozinho. Veja Arquivos de Animação (.anm).
Keyframes¶
| Chave | Significado |
|---|---|
frame |
Número do frame |
pos |
Posição, metros canônicos |
rot |
Euler XYZ, graus — a forma legível por humanos |
rot_quat |
A mesma rotação como quaternion [w, x, y, z], vinda do bake da world matrix |
scl |
Escala |
interp |
BEZIER, LINEAR ou CONSTANT |
handles |
Handles bezier absolutos, por eixo, agrupados por canal |
rot_quat ganha
Quando os dois estão presentes, rot_quat é o autoritativo e todo importador o prefere. Ele é independente de ordem, então contorna a ambiguidade de ordem Euler por completo. rot é mantido como fallback legível.
Handles não são emitidos junto com rot_quat pelos bakes do Maya e do Blender, porque handles em frame local não mapeiam para uma curva bakeada em world. O tipo de interpolação ainda viaja.
Handles são pares absolutos [[left_x, left_y], [right_x, right_y]] no espaço (frame, valor) — um por eixo, agrupados em pos, rot e scl. Absolutos em vez de relativos, para que não precisem ser re-derivados contra uma taxa de quadros na entrada.
source_modes¶
Um registro de como o peg foi autorado na sua aplicação de origem — position separada ou baseada em path, rotação Euler ou quaternion-path, e se 3D estava habilitado.
É uma dica, e só uma dica
source_modes nunca afeta nenhum valor. É informação diagnóstica para um humano lendo o arquivo. Um importador não vai mudar como escreve uma curva por causa disso.
Câmeras¶
Os dois formatos carregam o mesmo bloco de câmera, ligado por nome ao seu item animado:
| Chave | Significado |
|---|---|
name, peg, path |
Identidade, e qual item a anima |
is_default |
Se esta é a câmera padrão da cena |
fov, fov_axis |
Field of view — vertical, casando com a convenção do Harmony |
override_fov |
A flag de override de FOV por câmera do Harmony |
near_plane, far_plane |
Clip planes, como distâncias canônicas |
near_field, far_field |
Os valores de clip originais do Harmony em fields, preservados para que um round trip do Harmony seja lossless |
angle |
Roll, em graus em torno de Z |
offset_x/y/z, pivot_x/y |
Posicionamento relativo ao peg |
rig |
A tag de rig |
Veja Câmeras.
Notas práticas¶
Os arquivos são pequenos. Um rig completo de personagem com um shot de 60 frames tem algumas centenas de kilobytes. Dá para mandar por e-mail, pôr no controle de versão, ou guardar junto a um shot como registro.
Eles são diffáveis. Dois exports do mesmo rig produzem JSON comparável, o que faz de "o que mudou entre estas duas versões" um diff de texto em vez de um chute.
A nomenclatura é sua. O OTS não se importa com como o arquivo se chama; a chave format dentro dele é o que o identifica. Manter as extensões .pvt / .anm só faz os seletores de arquivo se comportarem.