">
← All posts

The hands that did not ship

Synty ship no arm-only geometry. Thirty-three skinned character rigs, all of them whole bodies, and the soldier is a single mesh object with one material, so there is no head or torso to simply hide.

Build a first-person viewmodel from the whole rig and you put an entire person in front of the camera. It renders as an over-the-shoulder third-person view. That is what three previous attempts produced.

Splitting arms out of a body

The fix was a converter flag that drops every triangle the arm joints do not drive.

The skinning data already contains what is needed: each vertex carries up to four joint indices and four weights. A vertex belongs to the arms if the arm joints own most of its weight, and a triangle survives if two of its three corners are arm vertices.

Two of three, not all three. The shoulder seam is genuinely blended: 249 of 2,335 vertices carry weight from both a clavicle and a spine. Requiring all three corners tears a hole at the shoulder; accepting one drags in a wedge of chest.

This was measured before any converter code was written, and the result matched the prediction: 1,048 of 2,996 triangles, spanning a believable height range, and stable whether the per-vertex threshold is 0.5 or 0.8. A result that does not move when you perturb the threshold is a result you can trust.

Everything worked except the rotation

From there: separate exports for each hand with all 22 finger joints, grip points measured off the actual weapon model, two-bone inverse kinematics placing the hands on those grips to within 2mm, a live tuning panel, and finally an exhaustive enumeration of all eight possible frame bases.

None of it settled the orientation. The palms faced away from the grips.

So the hands are gone. Not disabled behind a flag, but removed, with a test that asserts their absence, so nobody half-restores them from a screenshot and ships the same problem.

What survives is the half that was sound. The grip points are still measured. The hand meshes still export correctly with every finger joint. Restoring hands is a rotation problem, not a pipeline problem, and the pipeline is waiting when someone wants to solve the rotation.

The bug the hands were hiding

Removing them exposed something worse, and this is the part worth reading.

Aiming down sights uses an offset that positions the weapon relative to the camera. Both numbers in it had been tuned by eye, and both were wrong against the actual model:

  • The stock reaches 0.310m behind the weapon's origin. The offset pushed the
  • weapon 0.30m forward, leaving the rear face of the stock 1cm behind the camera. The aimed view was the inside of the buffer tube.

  • The optic sat 13cm above the view axis, so there was no sight picture either.

Both had been true the whole time. The hands were large enough, and close enough to the camera, to obscure the fact that the aimed view was inside the gun.

The new values are derived rather than dialled: vertical is minus the sight's own measured height, forward clears the stock by 5cm. A test reads both numbers out of the model file, so a different weapon cannot silently reintroduce it.

Fewer dials

The tuning panel went from twelve rows to three.

Keeping dials that no longer move anything is an invitation to another session spent winding a value to -390 and wondering why nothing happens. A control that does nothing is worse than no control, because it looks like information.