Formato de archivo¶
Ambos archivos de OTS son JSON UTF-8 plano, indentado y legible. Puedes abrir uno en un editor de texto, hacer diff entre dos en control de versiones, o escribir un script que lea uno. Eso es deliberado — un formato de intercambio que no puedes inspeccionar es un formato de intercambio que no puedes debuggear.
El formato actual es la versión 4.
Header compartido¶
Ambos formatos empiezan igual:
{
"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"
}
}
| Clave | Significado |
|---|---|
format |
octo_pvt u octo_anm |
version |
La versión del formato. Debe coincidir exactamente — ver abajo |
source |
Qué aplicación lo escribió: harmony, blender o maya |
fps |
El frame rate de la escena de origen |
coordinate_system |
El espacio en el que están los valores — ver Sistemas de coordenadas |
Sin migración hacia atrás
Un lector acepta solo su propia versión. Un archivo v3 cargado en un build v4 reporta:
unsupported version 3 (this build writes/reads v4; no backward migration — re-export from the source DCC)
Esto es una decisión, no un descuido. Migrar en silencio un archivo viejo significa adivinar qué significaban sus números, y una suposición equivocada produce un rig sutilmente desviado en vez de obviamente roto. Re-exportar desde el origen toma segundos y siempre es correcto.
.pvt — archivo de pivots¶
{
"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": []
}
| Clave | Significado |
|---|---|
name |
El nombre del rig |
scale_factor |
La opción Scale de cara al usuario. Los pivots se multiplican por ella al escribir, y se dividen al leer |
pivot_space |
local (relativo al parent) o armature |
bones[].pivot |
Posición de rest |
bones[].rotation |
Rotación de rest, como quaternion [w, x, y, z] |
bones[].path |
La ruta completa del ítem en su escena de origen — se usa para el matching, y para mantener distintos los ítems con el mismo nombre en rigs diferentes |
bones[].rig |
El tag de rig |
path, rig e is_camera se omiten cuando están vacíos, así un archivo simple se mantiene pequeño.
.anm — archivo de animación¶
{
"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": []
}
Los campos de autosuficiencia¶
parent, rest_pivot, rest_rotation y rig son el contenido del .pvt, plegado dentro de cada peg. Son la razón por la que Create Rig puede construir un skeleton funcional a partir de un .anm solo. Ver Animation Files (.anm).
Keyframes¶
| Clave | Significado |
|---|---|
frame |
Número de frame |
pos |
Posición, en metros canónicos |
rot |
Euler XYZ, grados — la forma legible para humanos |
rot_quat |
La misma rotación como quaternion [w, x, y, z], del bake de la world matrix |
scl |
Escala |
interp |
BEZIER, LINEAR o CONSTANT |
handles |
Handles bezier absolutos, por eje, agrupados por canal |
rot_quat gana
Cuando ambos están presentes, rot_quat es el autoritativo y todo importador lo prefiere. Es independiente del orden, así que esquiva por completo la ambigüedad del orden de Euler. rot se conserva como fallback legible.
Los handles no se emiten junto a rot_quat en los bakes de Maya y Blender, porque los handles en frame local no mapean sobre una curva de mundo bakeada. El tipo de interpolación sí viaja.
Los handles son pares absolutos [[left_x, left_y], [right_x, right_y]] en espacio (frame, valor) — uno por eje, agrupados en pos, rot y scl. Absolutos en vez de relativos, para que no haya que re-derivarlos contra un frame rate al entrar.
source_modes¶
Un registro de cómo fue creado el peg en su aplicación de origen — posición separada o basada en path, rotación Euler o quaternion-path, y si 3D estaba habilitado.
Es una pista, y solo una pista
source_modes nunca afecta ningún valor. Es información diagnóstica para un humano que lea el archivo. Un importador no cambiará cómo escribe una curva por su causa.
Cámaras¶
Ambos formatos llevan el mismo bloque de cámara, enlazado por nombre al ítem que lo anima:
| Clave | Significado |
|---|---|
name, peg, path |
Identidad, y qué ítem lo anima |
is_default |
Si esta es la cámara por defecto de la escena |
fov, fov_axis |
Field of view — vertical, siguiendo la convención de Harmony |
override_fov |
El flag de override de FOV por cámara de Harmony |
near_plane, far_plane |
Clip planes, como distancias canónicas |
near_field, far_field |
Los valores de clip originales de Harmony en fields, preservados para que un round trip en Harmony sea sin pérdidas |
angle |
Roll, en grados sobre Z |
offset_x/y/z, pivot_x/y |
Colocación relativa al peg |
rig |
El tag de rig |
Ver Cámaras.
Notas prácticas¶
Los archivos son pequeños. Un rig de personaje completo con un plano de 60 frames son unos pocos cientos de kilobytes. Están bien para mandar por email, poner en control de versiones o guardar junto a un plano como registro.
Son diffeables. Dos exportaciones del mismo rig producen JSON comparable, lo que convierte "qué cambió entre estas dos versiones" en un diff de texto y no en una suposición.
El nombre lo decides tú. A OTS no le importa cómo se llame el archivo; la clave format de adentro es lo que lo identifica. Mantener las extensiones .pvt / .anm solo sirve para que los file pickers se comporten.