Birdoggydog's Builds

Dressing an orc piece by piece on sockets in Godot

A bare body with eight armour pieces sized by socket measure, a node that swaps one piece while the monster walks, and draw calls for hung against merged gear.

An orc in Blobber can now have one piece of armour put on, taken off or replaced while the game runs, and its walk doesn’t break. To get there the new orc got a theme, three states and eight armour pieces built as a model apart from its body. Both are trials from 10 October: no monster in the played game uses them yet. The work is done by AI coding agents that I direct.

Building the armour apart from the body

The plain new orc beside the high fantasy one; the helm, chest and back close; both walking and striking with a longsword, then close on the fist; peak, declining and decayed side by side; the old themed orc beside the new one at the same distance.

The new orc exists in high fantasy in three living states: peak, declining and decayed. Each is a bare body plus a separate model of eight rigid armour pieces: a helm, two pauldrons, a breastplate, two vambraces, a tasset at the hip and a shield on the back.

On 9 October I decided to scrap the old creature models and redo them on the new head and body kits. The plain new orc had no theme, state or armour, and the old theming code was written round the old orc’s shape.

Nothing worn is ever in the body’s mesh. So the theme’s finish hands over to the body kit’s own finish unchanged, and a themed body keeps what the plain one has: skin weights by rule, removal of faces no eye can reach, the head’s paint, 20 bones, nine sockets and five clips. The theme reaches the skin only as data. The hide’s colours are leaned toward the theme’s body material. A state is laid over that as wear patches, grime low down and in runs, and dust on what faces up. A state changes paint and posture, not geometry.

The eight pieces are exported as one model beside the body, each piece rigid on one bone. What a state has lost is data too: declining has one piece hanging loose, decayed has both pauldrons gone and one piece loose. Gear gets its own gap check and its own removal of unseen faces, a socket at a time, each piece looked at alone. The body is not used to hide gear faces.

A body is 3,576 triangles at peak against a target of 6,000. The eight pieces are 1,429 against a target of 2,400, after 347 unseen faces were removed. A full build of one state takes about 9 minutes and a preview about 1.

Building three states at once showed a fault in the build. Every model is built twice to prove the two builds are the same bytes, and each of those runs deleted the other states’ second builds. A run now clears only its own folder.

How does armour drawn for a big orc fit a smaller one?

The old dressing code draws helms and breastplates in metres for the old orc, whose skull radius was 0.25 m. The new orc’s is 0.137 m. No dressing function was edited. Each piece is made at the size it was drawn for and then scaled about its socket’s point:

unit = this socket's measure / the measure the piece was drawn for

That gives 0.55 at the skull, 0.51 at the shoulders, 0.55 at the forearms, 0.70 at the breast, 0.88 at the back and 1.10 at the hip. A small table for the orc family adds nudges by kind of socket (out, up, grow, squash), tuned by eye on sheets. Each socket’s measure and unit are written into the body’s manifest, so the game can refit the same gear to a smaller or larger member of the family.

Weapons already had a rule like this. The new fist is 13 cm wide where the old orc’s was 36, and the existing fit rule scales a held weapon by 0.67.

Why did the decayed orc’s blow land a frame early?

The old orc’s posture code became a kit module. Giving the stooped, decayed orc its posture moved the frame on which its blow lands from 17 to 16, and the family’s check refuses that.

A stooped state now stoops in every clip except through the frames of the strike, where it rears upright. The weapon arm takes no extra motion. The blow lands on the same frame as the plain orc’s.

I liked all of it except the hip, where the armour is weird: the tasset hangs from no belt. He probably needs pants and shoes too, now that he looks less monstrous. The decayed orc’s back shield also stands off its stooped back at the top. Previews of the other four themes dress and are recognisable, but each fails the clip check in one to four clips.

Swapping one piece while the orc walks

A bare orc dressed piece by piece as it walks, its helm off and on, pieces swapped, two orcs in different sets, and a corpse lying in what it wore.

What a monster wears is now a list of pieces, a slot each. One piece can be worn, taken off or replaced during play, and the other pieces and the weapon are left as they were. A corpse lies in whatever the monster wore when it died.

I wanted themes to be pieces of equipment a character wears, swapped out one at a time, so that a monster that puts on a new piece during play is seen wearing it. The goal behind it is to get assets into the game faster and to ship fewer printed models, because they’re so large. Until now each look of a creature was one joined model a theme and a state.

MonsterDress is a node named “Dress” on a model made by MonsterSockets.make(). MonsterDress.of(model) finds it, and gives null for a joined body. These are its calls:

wear(piece, slot := "") -> String   # "" or what is wrong; the piece is hung all the same
take_off(slot)
dress(list)
worn()
wearing(slot)
slots()
signal changed(slot)
static corpse_of(model)             # lies in what the model wore at that moment

A piece’s address is one string: the model’s path under assets/models/ without .glb, plus #<mesh> for a model of several. The fantasy helm is gear/orcoid/SM_gear_orcoid_fantasy_peak#SM_gear_skull. Slot, socket kind and drawn measure are read from the manifest. Slots are the body manifest’s socket names: skull, pauldron.L, pauldron.R, bracer.L, bracer.R, breast, pack and hip. A slot holds at most one piece, and wearing onto a filled slot replaces what was there.

Size is worked out a socket at a time, the wearer’s socket measure over the measure the piece was drawn at. Where either is not written, as on the old orc and the runt, it falls back to the body’s single number.

problem() says what is wrong with a pairing, in this order: not built, no such socket, a hand, a piece for another kind of socket, nothing to size it by, never clip-checked on this body, found clipping. A state’s loose pieces apply to the slot whatever is on it. Its missing pieces are taken out of the default set but are not refused to wear().

A new piece needs no code and no table. Its .glb, textures and manifest go in a folder under assets/models/, and its address goes in whatever list wears it.

Is one merged mesh cheaper than eight hung pieces?

Two ways of wearing are kept. HUNG gives each piece a BoneAttachment3D on its socket’s bone. MERGED makes one skinned mesh from the list, each point riding its socket’s one bone. A change makes that mesh again. It is kept one per body file and list, and shared between monsters wearing the same.

Merged was expected to be cheaper in a crowd. It wasn’t. Draw calls with shadows, measured by the agent that built it:

HungMerged
One orc3918
Twenty orcs in one suit138203
Twenty orcs, pieces mixed from three states196289

CPU frame time was 1.4 to 1.5 ms in every case. Mixing pieces from the three states’ files raised both columns, because each state has a texture and a material of its own.

A swap on a hung orc is 0.03 ms to take a piece off and 0.04 ms to wear one, or 0.35 ms with a gem. Merged, it takes 4 to 14 ms to make the mesh again. First use of a gear file is 3.3 ms hung and 14 ms merged. Textures in memory are 1.40 MB for one orc and for twenty, and 1.93 MB with all three states’ gear.

On disk, one bare fantasy orc is 0.59 MB in 4 files, and the three gear models are 0.44 MB in 12 files. That 1.03 MB gives 6,561 full mixes of eight slots. A joined old-orc variant averages 0.74 MB, and twenty of them are 14.8 MB.

Those draw calls led to a decision the same day. A state becomes a setting of one material on one set of files, and a worn piece shows its own condition, not its wearer’s.

Also done

  • The dresser’s test passes 244 checks, by the building agent’s own run. One of the ten named tests failed on its branch, over the party’s step height (0.5 in the game, 0.0 in the editor), and the agent reports it fails the same without the change.
  • I typed 32 answers on the shared work-list page. They were recorded, with sixteen new work items that follow from them.

Next

Left on the orc are the dead state, the other four themes, and legs and feet. I want those from an armour generator that builds whole suits.