Repository navigation
Research Report R2 Md6anim
Continues decoding the skeleton and animation formats used by posed/skinned character models, aiming to pose a weapon and a soldier at a given frame. The skeleton format and its posing math for a flat weapon rig are unchanged and still corpus-verified; a prior claim that the per-joint quaternion table stores the inverse of the per-joint matrix's rotation is corrected on a large corpus — it is the same rotation. The humanoid bind-pose puzzle, previously scoped to a handful of torso/shoulder joints, turns out to be much bigger: no tested hierarchy-composition hypothesis gives plausible bone lengths for most of a soldier rig's non-root joints. The animation file's outer header is decoded one field further, and the search space for its still-undecoded per-frame compressed data is narrowed from the whole executable to a specific, small code cluster. Everything here is offline format research; posing an animation frame could not be completed, since no per-frame data is decoded yet to apply.
Header, joint name table, parent-index array, and per-joint bind matrix are decoded and corpus-verified across essentially the whole shipped skeleton corpus (one corrupt/truncated file is correctly rejected). Correction this pass: the per-joint quaternion table encodes the same rotation as the matrix table's own rotation, not its inverse — checked on over 24,000 individual joints across every parseable skeleton, not a single hand-checked example.
"Invert each joint's own matrix in model space, no hierarchy (FK) composition" fully and correctly poses a flat weapon rig (e.g. a pistol). For a humanoid soldier rig, this hypothesis is only solidly right for the hip root and the first 1–2 hierarchy levels: 45 of 71 non-root joints get an implausible bone length to their named parent under this hypothesis, and 65 of 71 have an implausible raw translation magnitude outright — which rules out both "no FK" and any ordering of hierarchical composition for most of the rig simultaneously, not a short exception list. A concrete structural clue: left/right mirror symmetry of the raw translation breaks at almost exactly the same joints where bone length also breaks (9 of 10 tested limb pairs) — a lead toward the real mechanism, not an explanation of it.
u32-len + ascii skeleton name (ends .md6skl)
u32-len + ascii OPTIONAL reference-animation name (ends .md6anim when present,
empty for a standalone animation — present on ~23% of a
400-file random sample: "bodyparts"/single-limb and
"additive" animations that supply partial joint data on
top of a named base animation)
12 x s16 two groups of 6; small/plausible on the large majority of
sampled files; the handful of exceptions are genuinely
world-scale set-piece animations (a sliding tunnel wall, a
vehicle, a collapsing walkway), not parse failures
The 12-s16 header is likely a per-channel quantization range: two different animation files of unrelated content but the same generic prop-animation template reproduce the exact same 12 values bit-for-bit. Which group quantizes which channel, and the fixed-point scale, are not resolved.
Per-frame bit-packed joint data is still not decoded. The known compressor function is located in the executable; the animation class's own RTTI gives exactly two constructor/destructor cross-references, bounding a dense ~51-function, ~20 KB cluster immediately bordering the compressor that almost certainly contains the frame decoder — a sharply narrowed search space versus the whole executable. (A previously proposed search method — looking for code references to a related matrix-type's RTTI name — is a dead end: that type has no RTTI/vtable entry at all, so it is never referenced from code; the vtable-of-a-related-class method above is what actually worked.)
Supporting decl types (spineIK, playerArmIK, playerLegIK, a per-character animation-alias table) are plain text, already readable, and corroborate joint naming but say nothing about the bind-pose matrix encoding itself.
Prior art: closed-source community extractors for this game family exist and advertise animation support, evidence the format has been solved elsewhere, but no public documentation of the per-frame bit layout was found.
- Matrix grouped as 4 sequential 3-vectors; FK composition in any order/convention; reading the quaternion one float early as a negative control; joint count read as the wrong integer width.
- Searching for code references to the matrix-type's own RTTI string (it has none).
- Guessed decoder function names (none exist as strings in the executable) — the decoder must be found structurally, by its position in the narrowed code cluster, not by name.
- What operation (not plain per-joint inverse, not any FK ordering — both corpus-ruled-out) recovers correct bone lengths for most of the soldier rig.
- Whether the left/right mirror-break is the same root cause as the bone-length puzzle, or a separate fact about how chain-root/roll-helper joints are authored.
- Which of the two
s16groups in the animation header quantizes which channel, and at what fixed-point scale. - The animation format's actual per-frame bit layout — next step: disassemble the narrowed code cluster described above, using known constants (the header's quantization-range shape, a groups-of-8 addressing idiom already seen inside the compressor) as correlation anchors.
No in-game test applies yet — this is pure offline format research; nothing changes visibly in a mod until both the per-frame compression and the full bind-pose reconstruction are decoded.
English Wiki generated from the measured research notes in docs/. Evidence grades and uncertainty are preserved intentionally.
- WolfSDK Loader · DE
- WolfSDK Studio · DE
- FAQ · DE
- Mod format · DE
- Modding Guide
- Modding Surface
- CVar Catalog
- CVar Validation (old scrape)
- Texture Database
- Developer Mode
- Dev Menu
- Custom-Map Status