Skip to content

MiVic v0.2.0 — the briefing has a man in it

Choose a tag to compare

@tkleisas tkleisas released this 17 Sep 13:14
· 8 commits to main since this release
The cast of a scripted scene is no longer built from boxes. A cutscene figure can
now be a **rigged, skinned, textured model**, and the briefing figures are built by
MakeHuman through MPFB2: a real skull, a real skin, a skeleton with an `Idle` clip,
and a moustache painted into the skin map.

Ported, not written: NoPasaranFC's `Graphics3D/Skinning/` stack, MIT and the same
author. A glb is parsed at runtime with SharpGLTF, so it loads identically on
DesktopGL and on Android, and a scene file can name the clip a figure plays. The
figure is posed from the director's own clock rather than from frame deltas, so two
runs of a probe photograph the same moment.

Three bugs in this span were all the same kind — a thing that is present and does
not appear — and all three were settled by reading a file rather than by reasoning:

  * Assets added before the rig are exported *unskinned*. `add_mhclo_asset` looks
    for a skeleton and, finding none, does `clothes.parent = basemesh` and stops,
    with no warning. The body proxy was in the glb the whole time, at 13,652
    vertices, with no JOINTS_0 and no WEIGHTS_0, which renders as absent. That is
    why the frame was byte-identical with and without it.
  * The visible body is a *proxy* and `base.obj` is a stand-in that is never meant
    to be seen. Blender hides it behind a MASK modifier, and `export_apply=False` —
    which skinning requires — is exactly what discards that mask.
  * A generated model is coloured by a map found beside it by name; an imported one
    carries its own. `SkinnedModel` had been reading the embedded textures all along
    and `CutsceneAssets` was overwriting them. The model's own material wins now,
    which needs the loader to say "no material" and "would not decode" with two
    different values, because one value cannot mean both.

The generator aims bones at directions instead of rotating them by guessed angles —
one `rotation_difference`, carried through the chain by assigning `pose_bone.matrix`
— because the rest pose is a 48-degree A-pose and MakeHuman's pose pack ships a
`t-pose.json` and nothing else. The moustache is painted into the skin map, placed
by measuring the mesh: the head is found from the head bone, because in the rest pose
the fingers reach further forward than the nose does.

`docs/MAKEHUMAN.md` is the guide, and it is the deliverable that was asked for: two
installation roots when only one has `clothes/` in it, the API calls that are silent
no-ops in the wrong order, and how to check the result. `docs/ART_PIPELINE.md` §2.6
records the three causes above.

Full Changelog: v0.1.1...v0.2.0